feat: upgrade to influxdb 2
This commit is contained in:
parent
46e58a0aff
commit
d183af929b
16 changed files with 933 additions and 261 deletions
|
@ -5,6 +5,10 @@ Which is based on [Keep A Changelog](http://keepachangelog.com/)
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Break
|
||||
|
||||
- upgrade to influxdb 2
|
||||
|
||||
## [2.0.0] 2021-08-18
|
||||
|
||||
### Break
|
||||
|
|
90
README.md
90
README.md
|
@ -3,50 +3,63 @@
|
|||
[![Version](https://img.shields.io/badge/latest_version-2.0.0-green.svg)](https://git.yaegashi.fr/nishiki/ansible-role-influxdb/releases)
|
||||
[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](https://git.yaegashi.fr/nishiki/ansible-role-influxdb/src/branch/master/LICENSE)
|
||||
|
||||
Install and configure InfluxDB
|
||||
Install and configure InfluxDB 2
|
||||
|
||||
## Requirements
|
||||
|
||||
* Ansible >= 2.9
|
||||
* Ansible >= 2.10
|
||||
* Debian
|
||||
* Buster
|
||||
* Bullseye
|
||||
* Bookworm
|
||||
|
||||
## Role variables
|
||||
|
||||
* `influxdb_databases` - array with the databases name
|
||||
* `influxdb_users` - array with the users informations
|
||||
- `influxdb_init_username` - user created during the influxdb setup
|
||||
- `influxdb_init_org` - organization created during the influxdb setup
|
||||
- `influxdb_init_bucket` - bucket created during the influxdb setup
|
||||
- `influxdb_api_token` - token to manage influxdb
|
||||
- `influxdb_orgs` - hash with organizations
|
||||
|
||||
```
|
||||
- name: test
|
||||
password: secret
|
||||
admin: true
|
||||
grants:
|
||||
- database: collectd
|
||||
privilege: WRITE
|
||||
```yaml
|
||||
myorg:
|
||||
description: it's a test
|
||||
state: present
|
||||
```
|
||||
|
||||
- `influxdb_retention_policies` - array with the retention policies
|
||||
- `influxdb_buckets` - hash with the buckets
|
||||
|
||||
```
|
||||
- name: default
|
||||
database: test_db
|
||||
duration: 1d
|
||||
default: true
|
||||
```yaml
|
||||
mybucket:
|
||||
description: KFC
|
||||
retention: 3600
|
||||
org: neworg
|
||||
state: present
|
||||
```
|
||||
|
||||
* `influxdb_api_user` - set the api user if you have enabled http authentification (default: `admin`)
|
||||
* `influxdb_api_password` - set the api password if you have enabled http authentification
|
||||
* `influxdb_api_port` - set the api port (default: `8086`)
|
||||
* `influxdb_config` - hash with the influxdb configuration (see [influxdb documentation](https://docs.influxdata.com/influxdb/v1.7/administration/config/))
|
||||
- `influxdb_users` - hash with the users
|
||||
|
||||
```yaml
|
||||
myuser:
|
||||
status: active
|
||||
state: present
|
||||
```
|
||||
meta:
|
||||
dir: /var/lib/influxdb/meta
|
||||
data:
|
||||
dir: /var/lib/influxdb/data
|
||||
wal-dir: /var/lib/influxdb/wal
|
||||
|
||||
- `influxdb_authorizations` - array with the authorizations
|
||||
|
||||
```yaml
|
||||
- user: myuser
|
||||
description: write bucket
|
||||
org: neworg
|
||||
status: active
|
||||
state: present
|
||||
permissions:
|
||||
- action: write
|
||||
resource:
|
||||
type: buckets
|
||||
org: myorg
|
||||
name: mybucket
|
||||
- action: read
|
||||
resource:
|
||||
type: buckets
|
||||
```
|
||||
|
||||
## How to use
|
||||
|
@ -59,25 +72,12 @@ Install and configure InfluxDB
|
|||
|
||||
## Development
|
||||
|
||||
### Test syntax with yamllint
|
||||
|
||||
* install `python` and `python-pip`
|
||||
* install yamllint `pip install yamllint`
|
||||
* run `yamllint .`
|
||||
|
||||
### Test syntax with ansible-lint
|
||||
|
||||
* install `python` and `python-pip`
|
||||
* install yamllint `pip install ansible-lint`
|
||||
* run `ansible-lint .`
|
||||
|
||||
### Tests with docker
|
||||
### Test with molecule and docker
|
||||
|
||||
* install [docker](https://docs.docker.com/engine/installation/)
|
||||
* install ruby
|
||||
* install bundler `gem install bundler`
|
||||
* install dependencies `bundle install`
|
||||
* run the tests `kitchen test`
|
||||
* install `python3` and `python3-pip`
|
||||
* install molecule and dependencies `pip3 install molecule molecule-plugins[docker] ansible-lint pytest-testinfra yamllint`
|
||||
* run `molecule test`
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
@ -1,14 +1,5 @@
|
|||
---
|
||||
influxdb_api_user: admin
|
||||
influxdb_api_port: 8086
|
||||
influxdb_default_config:
|
||||
meta:
|
||||
dir: /var/lib/influxdb/meta
|
||||
data:
|
||||
dir: /var/lib/influxdb/data
|
||||
wal-dir: /var/lib/influxdb/wal
|
||||
influxdb_config: {}
|
||||
influxdb_full_config: '{{ influxdb_default_config|combine(influxdb_config) }}'
|
||||
influxdb_databases: []
|
||||
influxdb_policies: []
|
||||
influxdb_users: []
|
||||
influxdb_orgs: {}
|
||||
influxdb_buckets: {}
|
||||
influxdb_users: {}
|
||||
influxdb_authorizations: []
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
- name: restart influxdb
|
||||
ansible.builtin.service:
|
||||
name: influxdb
|
||||
state: restarted
|
235
library/influxdb_auth.py
Normal file
235
library/influxdb_auth.py
Normal file
|
@ -0,0 +1,235 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
import requests
|
||||
import json
|
||||
|
||||
|
||||
class InfluxdbAuth:
|
||||
def __init__(self, api_url, api_token, org, user, permissions):
|
||||
self.api_url = api_url
|
||||
self.headers = {'Authorization': 'Token {}'.format(api_token)}
|
||||
self.org = org
|
||||
self.user = user
|
||||
self.permissions = permissions
|
||||
|
||||
def exists(self):
|
||||
url = '{}/api/v2/authorizations'.format(self.api_url)
|
||||
r = requests.get(
|
||||
url,
|
||||
headers=self.headers,
|
||||
params={'org': self.org, 'user': self.user}
|
||||
)
|
||||
|
||||
if r.status_code == 404:
|
||||
return False
|
||||
elif r.status_code == 200:
|
||||
data = json.loads(r.text)
|
||||
for auth in data['authorizations']:
|
||||
if self.check_permissions(auth['permissions']):
|
||||
self.id = auth['id']
|
||||
self.status = auth['status']
|
||||
self.description = auth['description']
|
||||
return True
|
||||
return False
|
||||
|
||||
raise Exception(
|
||||
'Influxdb',
|
||||
'Bad status code {}: {}'.format(r.status_code, r.text)
|
||||
)
|
||||
|
||||
def check_permissions(self, permissions):
|
||||
for pa in self.permissions:
|
||||
find = False
|
||||
for pb in permissions:
|
||||
if pa['action'] != pb['action']:
|
||||
continue
|
||||
if pa['resource']['type'] != pb['resource']['type']:
|
||||
continue
|
||||
if 'org' in pa['resource'] and 'org' in pb['resource']:
|
||||
if pa['resource']['org'] != pb['resource']['org']:
|
||||
continue
|
||||
if 'name' in pa['resource'] and 'name' in pb['resource']:
|
||||
if pa['resource']['name'] != pb['resource']['name']:
|
||||
continue
|
||||
find = True
|
||||
break
|
||||
|
||||
if not find:
|
||||
return False
|
||||
return True
|
||||
|
||||
def transform_permissions(self):
|
||||
permissions = list()
|
||||
for perm in self.permissions:
|
||||
org = None
|
||||
if 'org' in perm['resource'] and 'orgID' not in perm['resource']:
|
||||
org = perm['resource']['org']
|
||||
perm['resource']['orgID'] = self.get_orgid(org)
|
||||
if 'name' in perm['resource'] and 'id' not in perm['resource']:
|
||||
if perm['resource']['type'] == 'buckets':
|
||||
if org is None:
|
||||
org = self.org
|
||||
perm['resource']['id'] = self.get_bucketid(
|
||||
perm['resource']['name'], org)
|
||||
permissions.append(perm)
|
||||
|
||||
return permissions
|
||||
|
||||
def has_changed(self, status, description):
|
||||
if self.status != status:
|
||||
return True
|
||||
if self.description != description:
|
||||
return True
|
||||
return False
|
||||
|
||||
def create(self, status, description):
|
||||
url = '{}/api/v2/authorizations'.format(self.api_url)
|
||||
r = requests.post(
|
||||
url,
|
||||
headers=self.headers,
|
||||
json={
|
||||
'userID': self.get_userid(self.user, self.org),
|
||||
'orgID': self.get_orgid(self.org),
|
||||
'status': status,
|
||||
'description': description,
|
||||
'permissions': self.transform_permissions()
|
||||
}
|
||||
)
|
||||
|
||||
if r.status_code != 201:
|
||||
raise Exception(
|
||||
'Influxdb',
|
||||
'Bad status code {}: {}'.format(r.status_code, r.text)
|
||||
)
|
||||
|
||||
def delete(self):
|
||||
url = '{}/api/v2/authorizations/{}'.format(self.api_url, self.id)
|
||||
r = requests.delete(url, headers=self.headers)
|
||||
|
||||
if r.status_code != 204:
|
||||
raise Exception(
|
||||
'Influxdb',
|
||||
'Bad status code {}: {}'.format(r.status_code, r.text)
|
||||
)
|
||||
|
||||
def update(self, status, description):
|
||||
url = '{}/api/v2/authorizations/{}'.format(self.api_url, self.id)
|
||||
r = requests.patch(
|
||||
url,
|
||||
headers=self.headers,
|
||||
json={
|
||||
'description': description,
|
||||
'status': status
|
||||
}
|
||||
)
|
||||
|
||||
if r.status_code != 200:
|
||||
raise Exception(
|
||||
'Influxdb',
|
||||
'Bad status code {}: {}'.format(r.status_code, r.text)
|
||||
)
|
||||
|
||||
def get_bucketid(self, bucket_name, org):
|
||||
url = '{}/api/v2/buckets'.format(self.api_url)
|
||||
r = requests.get(
|
||||
url,
|
||||
headers=self.headers,
|
||||
params={'name': bucket_name, 'org': org}
|
||||
)
|
||||
|
||||
if r.status_code != 200:
|
||||
raise Exception(
|
||||
'Influxdb',
|
||||
'Bad status code {}: {}'.format(r.status_code, r.text)
|
||||
)
|
||||
|
||||
data = json.loads(r.text)
|
||||
for bucket in data['buckets']:
|
||||
if bucket['name'] == bucket_name:
|
||||
return bucket['id']
|
||||
|
||||
raise Exception('Influxdb', 'Don\'t get the bucketID')
|
||||
|
||||
def get_orgid(self, org_name):
|
||||
url = '{}/api/v2/orgs'.format(self.api_url)
|
||||
r = requests.get(url, headers=self.headers, params={'org': org_name})
|
||||
|
||||
if r.status_code != 200:
|
||||
raise Exception(
|
||||
'Influxdb',
|
||||
'Bad status code {}: {}'.format(r.status_code, r.text)
|
||||
)
|
||||
|
||||
data = json.loads(r.text)
|
||||
for org in data['orgs']:
|
||||
if org['name'] == org_name:
|
||||
return org['id']
|
||||
|
||||
raise Exception('Influxdb', 'Don\'t get the orgID')
|
||||
|
||||
def get_userid(self, user_name, org):
|
||||
url = '{}/api/v2/users'.format(self.api_url)
|
||||
r = requests.get(
|
||||
url,
|
||||
headers=self.headers,
|
||||
params={'name': user_name, 'org': org}
|
||||
)
|
||||
|
||||
if r.status_code != 200:
|
||||
raise Exception(
|
||||
'Influxdb',
|
||||
'Bad status code {}: {}'.format(r.status_code, r.text)
|
||||
)
|
||||
|
||||
data = json.loads(r.text)
|
||||
for user in data['users']:
|
||||
if user['name'] == user_name:
|
||||
return user['id']
|
||||
|
||||
raise Exception('Influxdb', 'Don\'t get the userID')
|
||||
|
||||
|
||||
def main():
|
||||
fields = {
|
||||
'user': {'type': 'str', 'required': True},
|
||||
'org': {'type': 'str', 'required': True},
|
||||
'permissions': {'type': 'list', 'required': True},
|
||||
'status': {'type': 'str',
|
||||
'default': 'active',
|
||||
'choice': ['active', 'inactive']},
|
||||
'description': {'type': 'str', 'default': ''},
|
||||
'api_url': {'type': 'str', 'default': 'http://127.0.0.1:8086'},
|
||||
'api_token': {'type': 'str', 'required': True},
|
||||
'state': {'type': 'str',
|
||||
'default': 'present',
|
||||
'choice': ['present', 'absent']},
|
||||
}
|
||||
module = AnsibleModule(argument_spec=fields)
|
||||
|
||||
auth = InfluxdbAuth(
|
||||
module.params['api_url'],
|
||||
module.params['api_token'],
|
||||
module.params['org'],
|
||||
module.params['user'],
|
||||
module.params['permissions'],
|
||||
)
|
||||
changed = False
|
||||
|
||||
if auth.exists():
|
||||
if module.params['state'] == 'absent':
|
||||
auth.delete()
|
||||
changed = True
|
||||
elif auth.has_changed(module.params['status'],
|
||||
module.params['description']):
|
||||
auth.update(module.params['status'], module.params['description'])
|
||||
changed = True
|
||||
elif module.params['state'] == 'present':
|
||||
auth.create(module.params['status'], module.params['description'])
|
||||
changed = True
|
||||
|
||||
module.exit_json(changed=changed)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
162
library/influxdb_bucket.py
Normal file
162
library/influxdb_bucket.py
Normal file
|
@ -0,0 +1,162 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
import requests
|
||||
import json
|
||||
|
||||
|
||||
class InfluxdbBucket:
|
||||
def __init__(self, api_url, api_token, name, org):
|
||||
self.api_url = api_url
|
||||
self.headers = {'Authorization': 'Token {}'.format(api_token)}
|
||||
self.name = name
|
||||
self.org = org
|
||||
|
||||
def exists(self):
|
||||
url = '{}/api/v2/buckets'.format(self.api_url)
|
||||
r = requests.get(
|
||||
url,
|
||||
headers=self.headers,
|
||||
params={'name': self.name, 'org': self.org}
|
||||
)
|
||||
|
||||
if r.status_code == 404:
|
||||
return False
|
||||
elif r.status_code == 200:
|
||||
data = json.loads(r.text)
|
||||
for bucket in data['buckets']:
|
||||
if bucket['name'] == self.name:
|
||||
self.id = bucket['id']
|
||||
self.retention = bucket['retentionRules'][0]['everySeconds']
|
||||
if 'description' in bucket:
|
||||
self.description = bucket['description']
|
||||
return True
|
||||
return False
|
||||
|
||||
raise Exception(
|
||||
'Influxdb',
|
||||
'Bad status code {}: {}'.format(r.status_code, r.text)
|
||||
)
|
||||
|
||||
def has_changed(self, description, retention):
|
||||
if self.description != description:
|
||||
return True
|
||||
if self.retention != retention:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_orgid(self):
|
||||
url = '{}/api/v2/orgs'.format(self.api_url)
|
||||
r = requests.get(url, headers=self.headers, params={'org': self.org})
|
||||
|
||||
if r.status_code != 200:
|
||||
raise Exception(
|
||||
'Influxdb',
|
||||
'Bad status code {}: {}'.format(r.status_code, r.text)
|
||||
)
|
||||
|
||||
data = json.loads(r.text)
|
||||
for org in data['orgs']:
|
||||
if org['name'] == self.org:
|
||||
return org['id']
|
||||
|
||||
raise Exception('Influxdb', 'Don\'t get the orgID')
|
||||
|
||||
def create(self, description, retention):
|
||||
url = '{}/api/v2/buckets'.format(self.api_url)
|
||||
r = requests.post(
|
||||
url,
|
||||
headers=self.headers,
|
||||
json={
|
||||
'name': self.name,
|
||||
'description': description,
|
||||
'orgID': self.get_orgid(),
|
||||
'retentionRules': [{
|
||||
'everySeconds': retention,
|
||||
'shardGroupDurationSeconds': 0,
|
||||
'type': 'expire'
|
||||
}]
|
||||
}
|
||||
)
|
||||
|
||||
if r.status_code != 201:
|
||||
raise Exception(
|
||||
'Influxdb',
|
||||
'Bad status code {}: {}'.format(r.status_code, r.text)
|
||||
)
|
||||
|
||||
def delete(self):
|
||||
url = '{}/api/v2/buckets/{}'.format(self.api_url, self.id)
|
||||
r = requests.delete(url, headers=self.headers)
|
||||
|
||||
if r.status_code != 204:
|
||||
raise Exception(
|
||||
'Influxdb',
|
||||
'Bad status code {}: {}'.format(r.status_code, r.text)
|
||||
)
|
||||
|
||||
def update(self, description, retention):
|
||||
url = '{}/api/v2/buckets/{}'.format(self.api_url, self.id)
|
||||
r = requests.patch(
|
||||
url,
|
||||
headers=self.headers,
|
||||
json={
|
||||
'name': self.name,
|
||||
'description': description,
|
||||
'retentionRules': [{
|
||||
'everySeconds': retention,
|
||||
'shardGroupDurationSeconds': 0,
|
||||
'type': 'expire'
|
||||
}]
|
||||
}
|
||||
)
|
||||
|
||||
if r.status_code != 200:
|
||||
raise Exception(
|
||||
'Influxdb',
|
||||
'Bad status code {}: {}'.format(r.status_code, r.text)
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
fields = {
|
||||
'name': {'type': 'str', 'required': True},
|
||||
'org': {'type': 'str', 'required': True},
|
||||
'description': {'type': 'str', 'default': ''},
|
||||
'retention': {'type': 'int', 'default': 0},
|
||||
'api_url': {'type': 'str', 'default': 'http://127.0.0.1:8086'},
|
||||
'api_token': {'type': 'str', 'required': True},
|
||||
'state': {'type': 'str',
|
||||
'default': 'present',
|
||||
'choice': ['present', 'absent']},
|
||||
}
|
||||
module = AnsibleModule(argument_spec=fields)
|
||||
|
||||
bucket = InfluxdbBucket(
|
||||
module.params['api_url'],
|
||||
module.params['api_token'],
|
||||
module.params['name'],
|
||||
module.params['org'],
|
||||
)
|
||||
changed = False
|
||||
|
||||
if bucket.exists():
|
||||
if module.params['state'] == 'absent':
|
||||
bucket.delete()
|
||||
changed = True
|
||||
elif bucket.has_changed(module.params['description'],
|
||||
module.params['retention']):
|
||||
bucket.update(
|
||||
module.params['description'],
|
||||
module.params['retention']
|
||||
)
|
||||
changed = True
|
||||
elif module.params['state'] == 'present':
|
||||
bucket.create(module.params['description'], module.params['retention'])
|
||||
changed = True
|
||||
|
||||
module.exit_json(changed=changed)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
112
library/influxdb_org.py
Normal file
112
library/influxdb_org.py
Normal file
|
@ -0,0 +1,112 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
import requests
|
||||
import json
|
||||
|
||||
|
||||
class InfluxdbOrg:
|
||||
def __init__(self, api_url, api_token, name):
|
||||
self.api_url = api_url
|
||||
self.headers = {'Authorization': 'Token {}'.format(api_token)}
|
||||
self.name = name
|
||||
|
||||
def exists(self):
|
||||
url = '{}/api/v2/orgs'.format(self.api_url)
|
||||
r = requests.get(url, headers=self.headers, params={'org': self.name})
|
||||
|
||||
if r.status_code == 404:
|
||||
return False
|
||||
elif r.status_code == 200:
|
||||
data = json.loads(r.text)
|
||||
for org in data['orgs']:
|
||||
if org['name'] == self.name:
|
||||
self.id = org['id']
|
||||
self.description = org['description']
|
||||
return True
|
||||
return False
|
||||
|
||||
raise Exception(
|
||||
'Influxdb',
|
||||
'Bad status code {}: {}'.format(r.status_code, r.text)
|
||||
)
|
||||
|
||||
def has_changed(self, description):
|
||||
if self.description == description:
|
||||
return False
|
||||
return True
|
||||
|
||||
def create(self, description):
|
||||
url = '{}/api/v2/orgs'.format(self.api_url)
|
||||
r = requests.post(
|
||||
url,
|
||||
headers=self.headers,
|
||||
json={'name': self.name, 'description': description}
|
||||
)
|
||||
|
||||
if r.status_code != 201:
|
||||
raise Exception(
|
||||
'Influxdb',
|
||||
'Bad status code {}: {}'.format(r.status_code, r.text)
|
||||
)
|
||||
|
||||
def delete(self):
|
||||
url = '{}/api/v2/orgs/{}'.format(self.api_url, self.id)
|
||||
r = requests.delete(url, headers=self.headers)
|
||||
|
||||
if r.status_code != 204:
|
||||
raise Exception(
|
||||
'Influxdb',
|
||||
'Bad status code {}: {}'.format(r.status_code, r.text)
|
||||
)
|
||||
|
||||
def update(self, description):
|
||||
url = '{}/api/v2/orgs/{}'.format(self.api_url, self.id)
|
||||
r = requests.patch(
|
||||
url,
|
||||
headers=self.headers,
|
||||
json={'name': self.name, 'description': description}
|
||||
)
|
||||
|
||||
if r.status_code != 200:
|
||||
raise Exception(
|
||||
'Influxdb',
|
||||
'Bad status code {}: {}'.format(r.status_code, r.text)
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
fields = {
|
||||
'name': {'type': 'str', 'required': True},
|
||||
'description': {'type': 'str', 'default': ''},
|
||||
'api_url': {'type': 'str', 'default': 'http://127.0.0.1:8086'},
|
||||
'api_token': {'type': 'str', 'required': True},
|
||||
'state': {'type': 'str',
|
||||
'default': 'present',
|
||||
'choice': ['present', 'absent']},
|
||||
}
|
||||
module = AnsibleModule(argument_spec=fields)
|
||||
|
||||
org = InfluxdbOrg(
|
||||
module.params['api_url'],
|
||||
module.params['api_token'],
|
||||
module.params['name'],
|
||||
)
|
||||
changed = False
|
||||
|
||||
if org.exists():
|
||||
if module.params['state'] == 'absent':
|
||||
org.delete()
|
||||
changed = True
|
||||
elif org.has_changed(module.params['description']):
|
||||
org.update(module.params['description'])
|
||||
changed = True
|
||||
elif module.params['state'] == 'present':
|
||||
org.create(module.params['description'])
|
||||
changed = True
|
||||
|
||||
module.exit_json(changed=changed)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
69
library/influxdb_setup.py
Normal file
69
library/influxdb_setup.py
Normal file
|
@ -0,0 +1,69 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
import requests
|
||||
import json
|
||||
|
||||
|
||||
class InfluxdbSetup:
|
||||
def __init__(self, api_url):
|
||||
self.api_url = api_url
|
||||
|
||||
def already(self):
|
||||
url = '{}/api/v2/setup'.format(self.api_url)
|
||||
r = requests.get(url)
|
||||
|
||||
if r.status_code != 200:
|
||||
raise Exception(
|
||||
'Influxdb',
|
||||
'Bad status code {}: {}'.format(r.status_code, r.text)
|
||||
)
|
||||
|
||||
data = json.loads(r.text)
|
||||
if 'allowed' not in data or data['allowed'] is True:
|
||||
return False
|
||||
return True
|
||||
|
||||
def run(self, username, org, bucket, token):
|
||||
url = '{}/api/v2/setup'.format(self.api_url)
|
||||
r = requests.post(url, json={
|
||||
'username': username,
|
||||
'org': org,
|
||||
'bucket': bucket,
|
||||
'token': token,
|
||||
})
|
||||
|
||||
if r.status_code != 201:
|
||||
raise Exception(
|
||||
'Influxdb',
|
||||
'Bad status code {}: {}'.format(r.status_code, r.text)
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
fields = {
|
||||
'username': {'type': 'str', 'required': True},
|
||||
'org': {'type': 'str', 'required': True},
|
||||
'bucket': {'type': 'str', 'required': True},
|
||||
'token': {'type': 'str', 'required': True},
|
||||
'api_url': {'type': 'str', 'default': 'http://127.0.0.1:8086'},
|
||||
}
|
||||
module = AnsibleModule(argument_spec=fields)
|
||||
|
||||
setup = InfluxdbSetup(
|
||||
module.params['api_url'],
|
||||
)
|
||||
|
||||
if setup.already() is True:
|
||||
module.exit_json(changed=False)
|
||||
setup.run(
|
||||
module.params['username'],
|
||||
module.params['org'],
|
||||
module.params['bucket'],
|
||||
module.params['token'],
|
||||
)
|
||||
module.exit_json(changed=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
124
library/influxdb_user.py
Normal file
124
library/influxdb_user.py
Normal file
|
@ -0,0 +1,124 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
import requests
|
||||
import json
|
||||
|
||||
|
||||
class InfluxdbUser:
|
||||
def __init__(self, api_url, api_token, name):
|
||||
self.api_url = api_url
|
||||
self.headers = {'Authorization': 'Token {}'.format(api_token)}
|
||||
self.name = name
|
||||
|
||||
def exists(self):
|
||||
url = '{}/api/v2/users'.format(self.api_url)
|
||||
r = requests.get(
|
||||
url,
|
||||
headers=self.headers,
|
||||
params={'name': self.name}
|
||||
)
|
||||
|
||||
if r.status_code == 404:
|
||||
return False
|
||||
elif r.status_code == 200:
|
||||
data = json.loads(r.text)
|
||||
for user in data['users']:
|
||||
if user['name'] == self.name:
|
||||
self.id = user['id']
|
||||
self.status = user['status']
|
||||
return True
|
||||
return False
|
||||
|
||||
raise Exception(
|
||||
'Influxdb',
|
||||
'Bad status code {}: {}'.format(r.status_code, r.text)
|
||||
)
|
||||
|
||||
def has_changed(self, status):
|
||||
if self.status != status:
|
||||
return True
|
||||
return False
|
||||
|
||||
def create(self, status):
|
||||
url = '{}/api/v2/users'.format(self.api_url)
|
||||
r = requests.post(
|
||||
url,
|
||||
headers=self.headers,
|
||||
json={
|
||||
'name': self.name,
|
||||
'status': status
|
||||
}
|
||||
)
|
||||
|
||||
if r.status_code != 201:
|
||||
raise Exception(
|
||||
'Influxdb',
|
||||
'Bad status code {}: {}'.format(r.status_code, r.text)
|
||||
)
|
||||
|
||||
def delete(self):
|
||||
url = '{}/api/v2/users/{}'.format(self.api_url, self.id)
|
||||
r = requests.delete(url, headers=self.headers)
|
||||
|
||||
if r.status_code != 204:
|
||||
raise Exception(
|
||||
'Influxdb',
|
||||
'Bad status code {}: {}'.format(r.status_code, r.text)
|
||||
)
|
||||
|
||||
def update(self, status):
|
||||
url = '{}/api/v2/users/{}'.format(self.api_url, self.id)
|
||||
r = requests.patch(
|
||||
url,
|
||||
headers=self.headers,
|
||||
json={
|
||||
'name': self.name,
|
||||
'status': status
|
||||
}
|
||||
)
|
||||
|
||||
if r.status_code != 200:
|
||||
raise Exception(
|
||||
'Influxdb',
|
||||
'Bad status code {}: {}'.format(r.status_code, r.text)
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
fields = {
|
||||
'name': {'type': 'str', 'required': True},
|
||||
'status': {'type': 'str',
|
||||
'default': 'active',
|
||||
'choice': ['active', 'inactive']},
|
||||
'api_url': {'type': 'str', 'default': 'http://127.0.0.1:8086'},
|
||||
'api_token': {'type': 'str', 'required': True},
|
||||
'state': {'type': 'str',
|
||||
'default': 'present',
|
||||
'choice': ['present', 'absent']},
|
||||
}
|
||||
module = AnsibleModule(argument_spec=fields)
|
||||
|
||||
user = InfluxdbUser(
|
||||
module.params['api_url'],
|
||||
module.params['api_token'],
|
||||
module.params['name'],
|
||||
)
|
||||
changed = False
|
||||
|
||||
if user.exists():
|
||||
if module.params['state'] == 'absent':
|
||||
user.delete()
|
||||
changed = True
|
||||
elif user.has_changed(module.params['status']):
|
||||
user.update(module.params['status'])
|
||||
changed = True
|
||||
elif module.params['state'] == 'present':
|
||||
user.create(module.params['status'])
|
||||
changed = True
|
||||
|
||||
module.exit_json(changed=changed)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -4,15 +4,14 @@ galaxy_info:
|
|||
namespace: nishiki
|
||||
author: Adrien Waksberg
|
||||
company: Adrien Waksberg
|
||||
description: Install and configure InfluxDB
|
||||
description: Install and configure InfluxDB 2
|
||||
license: Apache2
|
||||
min_ansible_version: 2.9
|
||||
min_ansible_version: "2.10"
|
||||
|
||||
platforms:
|
||||
- name: Debian
|
||||
versions:
|
||||
- buster
|
||||
- bullseye
|
||||
- bookworm
|
||||
|
||||
galaxy_tags:
|
||||
- database
|
||||
|
|
|
@ -4,38 +4,37 @@
|
|||
roles:
|
||||
- ansible-role-influxdb
|
||||
vars:
|
||||
influxdb_api_password: password
|
||||
influxdb_users:
|
||||
- name: '{{ influxdb_api_user }}'
|
||||
password: '{{ influxdb_api_password }}'
|
||||
admin: yes
|
||||
- name: test
|
||||
password: test2
|
||||
grants:
|
||||
- database: test_db
|
||||
privilege: WRITE
|
||||
- name: user_absent
|
||||
influxdb_init_username: admin
|
||||
influxdb_init_org: init_org
|
||||
influxdb_init_bucket: test
|
||||
influxdb_api_token: SuP3rS3cr3t
|
||||
influxdb_orgs:
|
||||
neworg:
|
||||
description: it's a test
|
||||
init_org:
|
||||
state: absent
|
||||
influxdb_databases:
|
||||
- test_db
|
||||
influxdb_retention_policies:
|
||||
- name: default
|
||||
database: test_db
|
||||
duration: 1d
|
||||
default: true
|
||||
influxdb_config:
|
||||
'[collectd]':
|
||||
enabled: true
|
||||
port: 25826
|
||||
database: collectd
|
||||
typesdb: /usr/share/collectd/types.db
|
||||
influxdb_buckets:
|
||||
mybucket:
|
||||
description: KFC
|
||||
retention: 3600
|
||||
org: neworg
|
||||
influxdb_users:
|
||||
telegraf:
|
||||
user_inactive:
|
||||
status: inactive
|
||||
influxdb_authorizations:
|
||||
- user: telegraf
|
||||
description: write telegraf
|
||||
org: neworg
|
||||
status: active
|
||||
permissions:
|
||||
- action: write
|
||||
resource:
|
||||
type: buckets
|
||||
org: neworg
|
||||
name: mybucket
|
||||
|
||||
pre_tasks:
|
||||
- name: update apt cache
|
||||
- name: Update apt cache
|
||||
ansible.builtin.apt:
|
||||
update_cache: true
|
||||
|
||||
- name: install collectd package
|
||||
ansible.builtin.package:
|
||||
name:
|
||||
- collectd-core
|
||||
|
|
|
@ -2,19 +2,12 @@
|
|||
driver:
|
||||
name: docker
|
||||
platforms:
|
||||
- name: debian10
|
||||
image: nishiki/debian10:molecule
|
||||
- name: debian12
|
||||
image: nishiki/debian12:molecule
|
||||
privileged: true
|
||||
volumes:
|
||||
- /sys/fs/cgroup:/sys/fs/cgroup:ro
|
||||
command: /bin/systemd
|
||||
capabilities:
|
||||
- SYS_ADMIN
|
||||
- name: debian11
|
||||
image: nishiki/debian11:molecule
|
||||
privileged: true
|
||||
volumes:
|
||||
- /sys/fs/cgroup:/sys/fs/cgroup:ro
|
||||
- /sys/fs/cgroup:/sys/fs/cgroup:rw
|
||||
cgroupns_mode: host
|
||||
command: /bin/systemd
|
||||
capabilities:
|
||||
- SYS_ADMIN
|
||||
|
|
|
@ -1,48 +1,48 @@
|
|||
import testinfra.utils.ansible_runner
|
||||
import re
|
||||
|
||||
CURL = ('curl --header "Authorization: Token SuP3rS3cr3t"'
|
||||
' http://localhost:8086/api/v2')
|
||||
|
||||
|
||||
def test_packages(host):
|
||||
package = host.package('influxdb')
|
||||
package = host.package('influxdb2')
|
||||
assert package.is_installed
|
||||
|
||||
def test_config_file(host):
|
||||
path = host.file('/etc/influxdb/influxdb.conf')
|
||||
assert path.exists
|
||||
assert path.is_file
|
||||
assert path.user == 'root'
|
||||
assert path.group == 'root'
|
||||
assert path.mode == 0o644
|
||||
assert path.contains('enabled = true')
|
||||
|
||||
def test_service(host):
|
||||
service = host.service('influxdb')
|
||||
assert service.is_running
|
||||
assert service.is_enabled
|
||||
|
||||
|
||||
def test_sockets(host):
|
||||
socket = host.socket('tcp://0.0.0.0:8086')
|
||||
assert socket.is_listening
|
||||
socket = host.socket('udp://0.0.0.0:25826')
|
||||
assert socket.is_listening
|
||||
|
||||
|
||||
def test_users(host):
|
||||
cmd = host.run('influx -execute "SHOW USERS"')
|
||||
cmd = host.run('{}/users -X GET'.format(CURL))
|
||||
assert cmd.succeeded
|
||||
assert re.search(r'admin\s+true', cmd.stdout)
|
||||
assert re.search(r'test\s+false', cmd.stdout)
|
||||
assert not re.search('user_absent', cmd.stdout)
|
||||
assert '"name": "admin"' in cmd.stdout
|
||||
assert '"name": "telegraf"' in cmd.stdout
|
||||
|
||||
def test_databases(host):
|
||||
cmd = host.run('influx -execute "SHOW DATABASES"')
|
||||
assert cmd.succeeded
|
||||
assert 'test_db' in cmd.stdout
|
||||
|
||||
def test_databases(host):
|
||||
cmd = host.run('influx -execute "SHOW RETENTION POLICIES ON test_db"')
|
||||
def test_org(host):
|
||||
cmd = host.run('{}/orgs -X GET'.format(CURL))
|
||||
assert cmd.succeeded
|
||||
assert re.search(r'default\s+24h0m0s\s+1h0m0s\s+1\s+true', cmd.stdout)
|
||||
assert '"name": "neworg"' in cmd.stdout
|
||||
assert '"name": "init_org"' not in cmd.stdout
|
||||
|
||||
def test_grants(host):
|
||||
cmd = host.run('influx -execute "SHOW GRANTS FOR test"')
|
||||
|
||||
def test_bucket(host):
|
||||
cmd = host.run('{}/buckets -X GET'.format(CURL))
|
||||
assert cmd.succeeded
|
||||
assert re.search(r'test_db\s+WRITE', cmd.stdout)
|
||||
assert '"name": "mybucket"' in cmd.stdout
|
||||
assert '"everySeconds": 3600' in cmd.stdout
|
||||
assert '"name": "test"' not in cmd.stdout
|
||||
|
||||
|
||||
def test_auth(host):
|
||||
cmd = host.run('{}/authorizations -X GET'.format(CURL))
|
||||
assert cmd.succeeded
|
||||
assert '"description": "write telegraf"' in cmd.stdout
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
---
|
||||
- name: copy config file
|
||||
ansible.builtin.template:
|
||||
src: influxdb.conf.j2
|
||||
dest: /etc/influxdb/influxdb.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0644
|
||||
notify: restart influxdb
|
||||
tags: influxdb
|
||||
|
||||
- name: start and enable service
|
||||
ansible.builtin.service:
|
||||
name: influxdb
|
||||
state: started
|
||||
enabled: yes
|
||||
tags: influxdb
|
||||
|
||||
- name: wait http api is up
|
||||
ansible.builtin.wait_for:
|
||||
port: 8086
|
||||
timeout: 10
|
||||
tags: influxdb
|
||||
|
||||
- name: create databases
|
||||
community.general.influxdb_database:
|
||||
database_name: '{{ item }}'
|
||||
username: '{{ influxdb_api_user }}'
|
||||
password: '{{ influxdb_api_password }}'
|
||||
loop: '{{ influxdb_databases }}'
|
||||
tags: influxdb
|
||||
|
||||
- name: create retention policies
|
||||
community.general.influxdb_retention_policy:
|
||||
policy_name: '{{ item.name }}'
|
||||
database_name: '{{ item.database }}'
|
||||
duration: '{{ item.duration }}'
|
||||
replication: '{{ item.replication|default(1) }}'
|
||||
default: '{{ item.default|default(False) }}'
|
||||
username: '{{ influxdb_api_user }}'
|
||||
password: '{{ influxdb_api_password }}'
|
||||
loop: '{{ influxdb_retention_policies }}'
|
||||
tags: influxdb
|
||||
|
||||
- name: create users
|
||||
community.general.influxdb_user:
|
||||
user_name: '{{ item.name }}'
|
||||
user_password: '{{ item.password }}'
|
||||
admin: '{{ item.admin|default(false) }}'
|
||||
grants: '{{ item.grants|default([]) }}'
|
||||
username: '{{ influxdb_api_user }}'
|
||||
password: '{{ influxdb_api_password }}'
|
||||
loop: '{{ influxdb_users }}'
|
||||
loop_control:
|
||||
label: '{{ item.name }}'
|
||||
when: item.state is not defined or item.state != 'absent'
|
||||
tags: influxdb
|
||||
|
||||
- name: delete users
|
||||
community.general.influxdb_user:
|
||||
user_name: '{{ item.name }}'
|
||||
username: '{{ influxdb_api_user }}'
|
||||
password: '{{ influxdb_api_password }}'
|
||||
state: absent
|
||||
loop: '{{ influxdb_users }}'
|
||||
loop_control:
|
||||
label: '{{ item.name }}'
|
||||
when: item.state is defined and item.state == 'absent'
|
||||
tags: influxdb
|
|
@ -1,42 +0,0 @@
|
|||
---
|
||||
- name: install depencies packages
|
||||
ansible.builtin.package:
|
||||
name:
|
||||
- apt-transport-https
|
||||
- collectd-core
|
||||
- python3-pip
|
||||
register: result
|
||||
until: result is succeeded
|
||||
retries: 2
|
||||
tags: influxdb
|
||||
|
||||
- name: add key for influxdb repository
|
||||
ansible.builtin.apt_key:
|
||||
url: https://repos.influxdata.com/influxdb.key
|
||||
register: result
|
||||
until: result is succeeded
|
||||
retries: 2
|
||||
tags: influxdb
|
||||
|
||||
- name: add influxdb repository
|
||||
ansible.builtin.apt_repository:
|
||||
repo: 'deb https://repos.influxdata.com/debian {{ ansible_distribution_release }} stable'
|
||||
tags: influxdb
|
||||
|
||||
- name: install influxdb package
|
||||
ansible.builtin.package:
|
||||
name:
|
||||
- influxdb
|
||||
register: result
|
||||
until: result is succeeded
|
||||
retries: 2
|
||||
tags: influxdb
|
||||
|
||||
- name: install python-influxdb
|
||||
ansible.builtin.pip:
|
||||
name: influxdb
|
||||
executable: /usr/bin/pip3
|
||||
register: result
|
||||
until: result is succeeded
|
||||
retries: 2
|
||||
tags: influxdb
|
104
tasks/main.yml
104
tasks/main.yml
|
@ -1,3 +1,103 @@
|
|||
---
|
||||
- import_tasks: install.yml
|
||||
- import_tasks: config.yml
|
||||
- name: Install depencies packages
|
||||
ansible.builtin.package:
|
||||
name:
|
||||
- apt-transport-https
|
||||
- python3-requests
|
||||
tags: influxdb
|
||||
|
||||
- name: Add key for influxdb repository
|
||||
ansible.builtin.get_url:
|
||||
url: https://repos.influxdata.com/influxdata-archive_compat.key
|
||||
dest: /etc/apt/keyrings/influx.asc
|
||||
checksum: sha256:393e8779c89ac8d958f81f942f9ad7fb82a25e133faddaf92e15b16e6ac9ce4c
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
tags: influxdb
|
||||
|
||||
- name: Add influxdb repository
|
||||
ansible.builtin.apt_repository:
|
||||
repo: "deb [signed-by=/etc/apt/keyrings/influx.asc] https://repos.influxdata.com/debian stable main"
|
||||
tags: influxdb
|
||||
|
||||
- name: Install package
|
||||
ansible.builtin.package:
|
||||
name:
|
||||
- influxdb2
|
||||
tags: influxdb
|
||||
|
||||
- name: Start and enable service
|
||||
ansible.builtin.service:
|
||||
name: influxdb
|
||||
state: started
|
||||
enabled: true
|
||||
tags: influxdb
|
||||
|
||||
- name: Wait http api is up
|
||||
ansible.builtin.wait_for:
|
||||
port: 8086
|
||||
timeout: 10
|
||||
tags: influxdb
|
||||
|
||||
- name: Setup server
|
||||
influxdb_setup:
|
||||
api_url: http://127.0.0.1:8086
|
||||
username: "{{ influxdb_init_username }}"
|
||||
org: "{{ influxdb_init_org }}"
|
||||
bucket: "{{ influxdb_init_bucket }}"
|
||||
token: "{{ influxdb_api_token }}"
|
||||
tags: influxdb
|
||||
|
||||
- name: Manage organisations
|
||||
influxdb_org:
|
||||
name: "{{ item.key }}"
|
||||
description: "{{ item.value.description | default(omit) }}"
|
||||
api_url: http://127.0.0.1:8086
|
||||
api_token: "{{ influxdb_api_token }}"
|
||||
state: "{{ item.value.state | default('present') }}"
|
||||
loop: "{{ influxdb_orgs | dict2items }}"
|
||||
loop_control:
|
||||
label: "{{ item.key }}"
|
||||
tags: influxdb
|
||||
|
||||
- name: Manage buckets
|
||||
influxdb_bucket:
|
||||
name: "{{ item.key }}"
|
||||
org: "{{ item.value.org }}"
|
||||
description: "{{ item.value.description | default(omit) }}"
|
||||
retention: "{{ item.value.retention | default(omit) }}"
|
||||
api_url: http://127.0.0.1:8086
|
||||
api_token: "{{ influxdb_api_token }}"
|
||||
state: "{{ item.value.state | default('present') }}"
|
||||
loop: "{{ influxdb_buckets | dict2items }}"
|
||||
loop_control:
|
||||
label: "{{ item.key }}"
|
||||
tags: influxdb
|
||||
|
||||
- name: Manage users
|
||||
influxdb_user:
|
||||
name: "{{ item.key }}"
|
||||
status: "{{ item.value.status | default('active') }}"
|
||||
api_url: http://127.0.0.1:8086
|
||||
api_token: "{{ influxdb_api_token }}"
|
||||
state: "{{ item.value.state | default('present') }}"
|
||||
loop: "{{ influxdb_users | dict2items }}"
|
||||
loop_control:
|
||||
label: "{{ item.key }}"
|
||||
tags: influxdb
|
||||
|
||||
- name: Manage authorizations
|
||||
influxdb_auth:
|
||||
org: "{{ item.org }}"
|
||||
user: "{{ item.user }}"
|
||||
description: "{{ item.description | default(omit) }}"
|
||||
permissions: "{{ item.permissions }}"
|
||||
status: "{{ item.status | default('active') }}"
|
||||
api_url: http://127.0.0.1:8086
|
||||
api_token: "{{ influxdb_api_token }}"
|
||||
state: "{{ item.state | default('present') }}"
|
||||
loop: "{{ influxdb_authorizations }}"
|
||||
loop_control:
|
||||
label: "{{ item.org }}/{{ item.user }}"
|
||||
tags: influxdb
|
||||
|
|
Loading…
Reference in a new issue