first version

This commit is contained in:
Adrien Waksberg 2019-04-12 19:14:25 +02:00
parent 01ff51ed93
commit b12f5def6b
19 changed files with 613 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
.kitchen/*

27
.kitchen.yml Normal file
View file

@ -0,0 +1,27 @@
---
driver:
name: docker_cli
transport:
name: docker_cli
provisioner:
name: ansible_playbook
hosts: localhost
require_ansible_repo: false
require_ansible_omnibus: false
require_chef_for_busser: true
ansible_verbose: false
ansible_inventory: ./test/integration/inventory
platforms:
- name: debian-9
driver_config:
image: "nishiki/debian9:ansible-<%= ENV['ANSIBLE_VERSION'] ? ENV['ANSIBLE_VERSION'] : '2.7' %>"
command: /bin/systemd
volume:
- /sys/fs/cgroup:/sys/fs/cgroup:ro
security_opt: seccomp=unconfined
suites:
- name: default

12
.yamllint Normal file
View file

@ -0,0 +1,12 @@
---
extends: default
ignore: |
.kitchen/*
vendor/
rules:
line-length:
max: 120
level: warning
truthy: false

8
CHANGELOG.md Normal file
View file

@ -0,0 +1,8 @@
# CHANGELOG
This project adheres to [Semantic Versioning](http://semver.org/).
Which is based on [Keep A Changelog](http://keepachangelog.com/)
## [Unreleased]
- first version

8
Gemfile Normal file
View file

@ -0,0 +1,8 @@
source 'https://rubygems.org'
group :development do
gem 'kitchen-ansible'
gem 'kitchen-docker_cli'
gem 'rubocop', '0.50.0'
gem 'test-kitchen'
end

93
Gemfile.lock Normal file
View file

@ -0,0 +1,93 @@
GEM
remote: https://rubygems.org/
specs:
ast (2.4.0)
builder (3.2.3)
erubis (2.7.0)
ffi (1.10.0)
gssapi (1.2.0)
ffi (>= 1.0.1)
gyoku (1.3.1)
builder (>= 2.1.2)
httpclient (2.8.3)
kitchen-ansible (0.47.4)
mixlib-shellout (>= 2.3.2)
net-ssh (>= 3)
test-kitchen (>= 1.17.0)
kitchen-docker_cli (0.19.0)
test-kitchen (>= 1.3)
little-plugger (1.1.4)
logging (2.2.2)
little-plugger (~> 1.1)
multi_json (~> 1.10)
mixlib-install (3.11.11)
mixlib-shellout
mixlib-versioning
thor
mixlib-shellout (2.4.4)
mixlib-versioning (1.2.7)
multi_json (1.13.1)
net-scp (2.0.0)
net-ssh (>= 2.6.5, < 6.0.0)
net-ssh (5.2.0)
net-ssh-gateway (2.0.0)
net-ssh (>= 4.0.0)
nori (2.6.0)
parallel (1.17.0)
parser (2.6.2.1)
ast (~> 2.4.0)
powerpack (0.1.2)
rainbow (2.2.2)
rake
rake (12.3.2)
rubocop (0.50.0)
parallel (~> 1.10)
parser (>= 2.3.3.1, < 3.0)
powerpack (~> 0.1)
rainbow (>= 2.2.2, < 3.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
ruby-progressbar (1.10.0)
rubyntlm (0.6.2)
rubyzip (1.2.2)
test-kitchen (2.0.1)
mixlib-install (~> 3.6)
mixlib-shellout (>= 1.2, < 3.0)
net-scp (>= 1.1, < 3.0)
net-ssh (>= 2.9, < 6.0)
net-ssh-gateway (>= 1.2, < 3.0)
thor (~> 0.19)
winrm (~> 2.0)
winrm-elevated (~> 1.0)
winrm-fs (~> 1.1)
thor (0.20.3)
unicode-display_width (1.5.0)
winrm (2.3.1)
builder (>= 2.1.2)
erubis (~> 2.7)
gssapi (~> 1.2)
gyoku (~> 1.0)
httpclient (~> 2.2, >= 2.2.0.2)
logging (>= 1.6.1, < 3.0)
nori (~> 2.0)
rubyntlm (~> 0.6.0, >= 0.6.1)
winrm-elevated (1.1.1)
winrm (~> 2.0)
winrm-fs (~> 1.0)
winrm-fs (1.3.2)
erubis (~> 2.7)
logging (>= 1.6.1, < 3.0)
rubyzip (~> 1.1)
winrm (~> 2.0)
PLATFORMS
ruby
DEPENDENCIES
kitchen-ansible
kitchen-docker_cli
rubocop (= 0.50.0)
test-kitchen
BUNDLED WITH
1.16.0

93
README.md Normal file
View file

@ -0,0 +1,93 @@
# Ansible role: Influxdb
[![Version](https://img.shields.io/badge/latest_version-1.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
## Requirements
* Ansible >= 2.7
* Debian Stretch
## Role variables
* `influxdb_databases` - array with the databases name
* `influxdb_users` - array with the users informations
```
- name: test
password: secret
admin: true
state: present
```
* `influxdb_privileges` - array with the privileges
```
- user: test
database: metric
privilege: WRITE
state: present
```
* `influxdb_api_user` - set the api user if you have enabled http authentification
* `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/))
```
meta:
dir: /var/lib/influxdb/meta
data:
dir: /var/lib/influxdb/data
wal-dir: /var/lib/influxdb/wal
```
## How to use
```
- hosts: server
roles:
- 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
* install [docker](https://docs.docker.com/engine/installation/)
* install ruby
* install bundler `gem install bundler`
* install dependencies `bundle install`
* run the tests `kitchen test`
## License
```
Copyright (c) 2019 Adrien Waksberg
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```

15
defaults/main.yml Normal file
View file

@ -0,0 +1,15 @@
---
influxdb_databases: []
influxdb_users: []
influxdb_privileges: []
influxdb_api_user: user
influxdb_api_password: password
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) }}'

5
handlers/main.yml Normal file
View file

@ -0,0 +1,5 @@
---
- name: restart influxdb
systemd:
name: influxdb
state: restarted

View file

@ -0,0 +1,94 @@
#!/usr/bin/python
from ansible.module_utils.basic import *
import requests
import json
class InfluxdbPrivilege:
def __init__(self, user, database, privilege, api_host, api_port, api_user, api_password):
self.user = user
self.database = database
self.privilege = privilege
self.api_host = api_host
self.api_port = api_port
self.api_user = api_user
self.api_password = api_password
self.change = False
self.get_info()
def request(self, query):
url = 'http://{}:{}/query?q={}'.format(self.api_host, self.api_port, requests.utils.quote(query))
if self.api_user is not None:
r = requests.get(url, auth=(self.api_user, self.api_password))
else:
r = requests.get(url)
if r.status_code != 200:
raise Exception('Influxdb', 'Bad status code {}: {}'.format(r.status_code, r.text))
return json.loads(r.text)
def get_info(self):
privileges = self.request(
'SHOW GRANTS FOR {}'.format(self.user),
)['results'][0]['series'][0]
if 'values' in privileges:
for privilege in privileges['values']:
if self.database == privilege[0]:
self.exist = True
if self.privilege != privilege[1]:
self.change = True
return
self.exist = False
def grant(self):
self.request(
'GRANT {} ON {} TO {}'.format(self.privilege, self.database, self.user)
)
def revoke(self):
self.request(
'REVOKE {} ON {} FROM {}'.format(self.privilege, self.database, self.user)
)
def main():
fields = {
'user': { 'type': 'str', 'required': True },
'database': { 'type': 'str', 'required': True },
'privilege': { 'type': 'str', 'required': True, 'choices': ['ALL', 'WRITE', 'READ'] },
'api_user': { 'type': 'str' },
'api_password': { 'type': 'str' },
'api_host': { 'type': 'str', 'default': '127.0.0.1' },
'api_port': { 'type': 'int', 'default': 8086 },
'state': { 'type': 'str', 'default': 'present', 'choices': ['present', 'absent'] }
}
module = AnsibleModule(argument_spec=fields)
changed = False
influxdb_privilege = InfluxdbPrivilege(
module.params['user'],
module.params['database'],
module.params['privilege'],
module.params['api_host'],
module.params['api_port'],
module.params['api_user'],
module.params['api_password']
)
if module.params['state'] == 'present':
if not influxdb_privilege.exist or influxdb_privilege.change:
influxdb_privilege.grant()
changed = True
else:
if influxdb_privilege.exist:
influxdb_privilege.revoke()
changed = True
module.exit_json(changed=changed)
if __name__ == '__main__':
main()

20
meta/main.yml Normal file
View file

@ -0,0 +1,20 @@
---
galaxy_info:
role_name: Influxdb
author: Adrien Waksberg
company: Adrien Waksberg
description: Install and configure InfluxDB
license: Apache2
min_ansible_version: 2.7
platforms:
- name: Debian
versions:
- stretch
galaxy_tags:
- database
- influxdb
- timeseries
dependencies: []

68
tasks/config.yml Normal file
View file

@ -0,0 +1,68 @@
---
- name: copy config file
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
systemd:
name: influxdb
state: started
enabled: yes
tags: influxdb
- name: wait http api is up
wait_for:
port: 8086
timeout: 10
tags: influxdb
- name: create users
influxdb_user:
user_name: '{{ item.name }}'
user_password: '{{ item.password }}'
admin: '{{ item.admin|default(false) }}'
username: '{{ influxdb_api_user }}'
password: '{{ influxdb_api_password }}'
loop: '{{ influxdb_users }}'
when: item.state is not defined or item.state != 'absent'
no_log: true
tags: influxdb
- name: delete users
influxdb_user:
user_name: '{{ item.name }}'
username: '{{ influxdb_api_user }}'
password: '{{ influxdb_api_password }}'
state: absent
loop: '{{ influxdb_users }}'
when: item.state is defined and item.state == 'absent'
no_log: true
tags: influxdb
- name: create databases
influxdb_database:
database_name: '{{ item }}'
username: '{{ influxdb_api_user }}'
password: '{{ influxdb_api_password }}'
loop: '{{ influxdb_databases }}'
no_log: true
tags: influxdb
- name: create privileges
influxdb_privilege:
user: '{{ item.user }}'
database: '{{ item.database }}'
privilege: '{{ item.privilege }}'
api_user: '{{ influxdb_api_user }}'
api_password: '{{ influxdb_api_password }}'
api_port: '{{ influxdb_api_port }}'
state: '{{ item.state|default("present") }}'
loop: '{{ influxdb_privileges }}'
no_log: true
tags: influxdb

42
tasks/install.yml Normal file
View file

@ -0,0 +1,42 @@
---
- name: install depencies packages
apt:
name: '{{ packages }}'
vars:
packages:
- apt-transport-https
- collectd-core
- python-pip
register: result
until: result is succeeded
retries: 2
tags: influxdb
- name: add key for influxdb repository
apt_key:
url: https://repos.influxdata.com/influxdb.key
register: result
until: result is succeeded
retries: 2
tags: influxdb
- name: add influxdb repository
apt_repository:
repo: 'deb https://repos.influxdata.com/debian {{ ansible_distribution_release }} stable'
tags: influxdb
- name: install influxdb package
apt:
name: influxdb
register: result
until: result is succeeded
retries: 2
tags: influxdb
- name: install python-influxdb
pip:
name: influxdb
register: result
until: result is succeeded
retries: 2
tags: influxdb

3
tasks/main.yml Normal file
View file

@ -0,0 +1,3 @@
---
- import_tasks: install.yml
- import_tasks: config.yml

View file

@ -0,0 +1,13 @@
# {{ ansible_managed }}
{% for section, options in influxdb_full_config.iteritems() %}
[{{ section }}]
{% for option, value in options.iteritems() %}
{{ option }} = {% if value is sameas true %}true
{% elif value is sameas false %}false
{% elif value is string %}"{{ value }}"
{% elif value is number %}{{ value }}
{% else %}["{{ value|join('", "') }}"]
{% endif %}
{% endfor %}
{% endfor %}

View file

@ -0,0 +1,28 @@
E, [2019-01-17T09:43:25.055727 #24689] ERROR -- Kitchen: ------Exception-------
E, [2019-01-17T09:43:25.055802 #24689] ERROR -- Kitchen: Class: Kitchen::UserError
E, [2019-01-17T09:43:25.055823 #24689] ERROR -- Kitchen: Message: Kitchen YAML file /home/awaksberg/git/ansible-role-influxdb/test/integration/default/.kitchen.yml does not exist.
E, [2019-01-17T09:43:25.055835 #24689] ERROR -- Kitchen: ----------------------
E, [2019-01-17T09:43:25.055845 #24689] ERROR -- Kitchen: ------Backtrace-------
E, [2019-01-17T09:43:25.055854 #24689] ERROR -- Kitchen: /home/awaksberg/.rvm/gems/ruby-2.5.1/gems/test-kitchen-1.23.5/lib/kitchen/loader/yaml.rb:65:in `read'
E, [2019-01-17T09:43:25.055863 #24689] ERROR -- Kitchen: /home/awaksberg/.rvm/gems/ruby-2.5.1/gems/test-kitchen-1.23.5/lib/kitchen/config.rb:152:in `data'
E, [2019-01-17T09:43:25.055872 #24689] ERROR -- Kitchen: /home/awaksberg/.rvm/gems/ruby-2.5.1/gems/test-kitchen-1.23.5/lib/kitchen/config.rb:131:in `suites'
E, [2019-01-17T09:43:25.055881 #24689] ERROR -- Kitchen: /home/awaksberg/.rvm/gems/ruby-2.5.1/gems/test-kitchen-1.23.5/lib/kitchen/config.rb:182:in `filter_instances'
E, [2019-01-17T09:43:25.055891 #24689] ERROR -- Kitchen: /home/awaksberg/.rvm/gems/ruby-2.5.1/gems/test-kitchen-1.23.5/lib/kitchen/config.rb:141:in `build_instances'
E, [2019-01-17T09:43:25.055900 #24689] ERROR -- Kitchen: /home/awaksberg/.rvm/gems/ruby-2.5.1/gems/test-kitchen-1.23.5/lib/kitchen/config.rb:117:in `instances'
E, [2019-01-17T09:43:25.055909 #24689] ERROR -- Kitchen: /home/awaksberg/.rvm/gems/ruby-2.5.1/gems/test-kitchen-1.23.5/lib/kitchen/command.rb:112:in `filtered_instances'
E, [2019-01-17T09:43:25.055918 #24689] ERROR -- Kitchen: /home/awaksberg/.rvm/gems/ruby-2.5.1/gems/test-kitchen-1.23.5/lib/kitchen/command.rb:142:in `parse_subcommand'
E, [2019-01-17T09:43:25.055927 #24689] ERROR -- Kitchen: /home/awaksberg/.rvm/gems/ruby-2.5.1/gems/test-kitchen-1.23.5/lib/kitchen/command/list.rb:30:in `call'
E, [2019-01-17T09:43:25.055936 #24689] ERROR -- Kitchen: /home/awaksberg/.rvm/gems/ruby-2.5.1/gems/test-kitchen-1.23.5/lib/kitchen/cli.rb:52:in `perform'
E, [2019-01-17T09:43:25.055947 #24689] ERROR -- Kitchen: /home/awaksberg/.rvm/gems/ruby-2.5.1/gems/test-kitchen-1.23.5/lib/kitchen/cli.rb:120:in `list'
E, [2019-01-17T09:43:25.055957 #24689] ERROR -- Kitchen: /home/awaksberg/.rvm/gems/ruby-2.5.1/gems/thor-0.20.3/lib/thor/command.rb:27:in `run'
E, [2019-01-17T09:43:25.055966 #24689] ERROR -- Kitchen: /home/awaksberg/.rvm/gems/ruby-2.5.1/gems/thor-0.20.3/lib/thor/invocation.rb:126:in `invoke_command'
E, [2019-01-17T09:43:25.055975 #24689] ERROR -- Kitchen: /home/awaksberg/.rvm/gems/ruby-2.5.1/gems/thor-0.20.3/lib/thor.rb:387:in `dispatch'
E, [2019-01-17T09:43:25.055984 #24689] ERROR -- Kitchen: /home/awaksberg/.rvm/gems/ruby-2.5.1/gems/thor-0.20.3/lib/thor/base.rb:466:in `start'
E, [2019-01-17T09:43:25.055993 #24689] ERROR -- Kitchen: /home/awaksberg/.rvm/gems/ruby-2.5.1/gems/test-kitchen-1.23.5/bin/kitchen:13:in `block in <top (required)>'
E, [2019-01-17T09:43:25.056002 #24689] ERROR -- Kitchen: /home/awaksberg/.rvm/gems/ruby-2.5.1/gems/test-kitchen-1.23.5/lib/kitchen/errors.rb:171:in `with_friendly_errors'
E, [2019-01-17T09:43:25.056011 #24689] ERROR -- Kitchen: /home/awaksberg/.rvm/gems/ruby-2.5.1/gems/test-kitchen-1.23.5/bin/kitchen:13:in `<top (required)>'
E, [2019-01-17T09:43:25.056020 #24689] ERROR -- Kitchen: /home/awaksberg/.rvm/gems/ruby-2.5.1/bin/kitchen:23:in `load'
E, [2019-01-17T09:43:25.056029 #24689] ERROR -- Kitchen: /home/awaksberg/.rvm/gems/ruby-2.5.1/bin/kitchen:23:in `<main>'
E, [2019-01-17T09:43:25.056039 #24689] ERROR -- Kitchen: /home/awaksberg/.rvm/gems/ruby-2.5.1/bin/ruby_executable_hooks:24:in `eval'
E, [2019-01-17T09:43:25.056048 #24689] ERROR -- Kitchen: /home/awaksberg/.rvm/gems/ruby-2.5.1/bin/ruby_executable_hooks:24:in `<main>'
E, [2019-01-17T09:43:25.056057 #24689] ERROR -- Kitchen: ----End Backtrace-----

View file

@ -0,0 +1,32 @@
---
- hosts: localhost
connection: local
vars:
influxdb_users:
- name: paul
password: test
admin: yes
- name: adrien
password: test2
- name: antoine
state: absent
influxdb_databases:
- new_database
influxdb_privileges:
- user: adrien
database: new_database
privilege: WRITE
influxdb_config:
'[collectd]':
enabled: true
port: 25826
database: collectd
typesdb: /usr/share/collectd/types.db
roles:
- ansible-role-influxdb
pre_tasks:
- name: install collectd package
apt:
name: collectd-core

View file

@ -0,0 +1,50 @@
require 'serverspec'
set :backend, :exec
puts
puts '================================'
puts %x(ansible --version)
puts '================================'
describe package('influxdb') do
it { should be_installed }
end
describe file('/etc/influxdb/influxdb.conf') do
it { should be_file }
it { should be_mode 644 }
it { should be_owned_by 'root' }
it { should be_grouped_into 'root' }
it { should contain 'enabled = true' }
end
describe service('influxdb') do
it { should be_enabled }
it { should be_running.under('systemd') }
end
describe port(8086) do
it { should be_listening.with('tcp6') }
end
describe port(25_826) do
it { should be_listening.with('udp6') }
end
describe command('influx -execute "SHOW USERS"') do
its(:exit_status) { should eq 0 }
its(:stdout) { should match(/paul\s+true/) }
its(:stdout) { should match(/adrien\s+false/) }
its(:stdout) { should_not match 'antoine' }
end
describe command('influx -execute "SHOW DATABASES"') do
its(:exit_status) { should eq 0 }
its(:stdout) { should match 'new_database' }
end
describe command('influx -execute "SHOW GRANTS FOR adrien"') do
its(:exit_status) { should eq 0 }
its(:stdout) { should match(/new_database\s+WRITE/) }
end

View file

@ -0,0 +1 @@
localhost