summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnsible Core Team <info@ansible.com>2020-03-09 09:40:30 +0000
committerAnsible Core Team <info@ansible.com>2020-03-09 09:40:30 +0000
commit54b2c8f1131bdcbe19e43b72816c9107b67ae8ca (patch)
treee7a930b68c5cc781e98b232cffd31a446fae2843
parent6e048cc2689d033b7757174d582077dd4af494b5 (diff)
downloadansible-54b2c8f1131bdcbe19e43b72816c9107b67ae8ca.tar.gz
Migrated to community.grafana
-rw-r--r--lib/ansible/modules/monitoring/grafana/grafana_dashboard.py556
-rw-r--r--lib/ansible/modules/monitoring/grafana/grafana_datasource.py683
-rw-r--r--lib/ansible/modules/monitoring/grafana/grafana_plugin.py257
-rw-r--r--lib/ansible/plugins/callback/grafana_annotations.py273
-rw-r--r--lib/ansible/plugins/lookup/grafana_dashboard.py174
-rw-r--r--test/integration/targets/grafana_datasource/aliases2
-rw-r--r--test/integration/targets/grafana_datasource/meta/main.yml2
-rw-r--r--test/integration/targets/grafana_datasource/tasks/cloudwatch.yml67
-rw-r--r--test/integration/targets/grafana_datasource/tasks/elastic.yml77
-rw-r--r--test/integration/targets/grafana_datasource/tasks/influx.yml61
-rw-r--r--test/integration/targets/grafana_datasource/tasks/main.yml8
-rw-r--r--test/integration/targets/grafana_datasource/tasks/postgres.yml61
-rw-r--r--test/sanity/ignore.txt11
13 files changed, 0 insertions, 2232 deletions
diff --git a/lib/ansible/modules/monitoring/grafana/grafana_dashboard.py b/lib/ansible/modules/monitoring/grafana/grafana_dashboard.py
deleted file mode 100644
index c0177eb9ac..0000000000
--- a/lib/ansible/modules/monitoring/grafana/grafana_dashboard.py
+++ /dev/null
@@ -1,556 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2017, Thierry Sallé (@seuf)
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-
-ANSIBLE_METADATA = {
- 'status': ['preview'],
- 'supported_by': 'community',
- 'metadata_version': '1.1'
-}
-
-DOCUMENTATION = '''
----
-module: grafana_dashboard
-author:
- - Thierry Sallé (@seuf)
-version_added: "2.5"
-short_description: Manage Grafana dashboards
-description:
- - Create, update, delete, export Grafana dashboards via API.
-options:
- url:
- description:
- - The Grafana URL.
- required: true
- aliases: [ grafana_url ]
- version_added: 2.7
- url_username:
- description:
- - The Grafana API user.
- default: admin
- aliases: [ grafana_user ]
- version_added: 2.7
- url_password:
- description:
- - The Grafana API password.
- default: admin
- aliases: [ grafana_password ]
- version_added: 2.7
- grafana_api_key:
- description:
- - The Grafana API key.
- - If set, I(grafana_user) and I(grafana_password) will be ignored.
- org_id:
- description:
- - The Grafana Organisation ID where the dashboard will be imported / exported.
- - Not used when I(grafana_api_key) is set, because the grafana_api_key only belongs to one organisation..
- default: 1
- folder:
- description:
- - The Grafana folder where this dashboard will be imported to.
- default: General
- version_added: '2.10'
- state:
- description:
- - State of the dashboard.
- required: true
- choices: [ absent, export, present ]
- default: present
- slug:
- description:
- - Deprecated since Grafana 5. Use grafana dashboard uid instead.
- - slug of the dashboard. It's the friendly url name of the dashboard.
- - When C(state) is C(present), this parameter can override the slug in the meta section of the json file.
- - If you want to import a json dashboard exported directly from the interface (not from the api),
- you have to specify the slug parameter because there is no meta section in the exported json.
- uid:
- version_added: 2.7
- description:
- - uid of the dashboard to export when C(state) is C(export) or C(absent).
- path:
- description:
- - The path to the json file containing the Grafana dashboard to import or export.
- overwrite:
- description:
- - Override existing dashboard when state is present.
- type: bool
- default: 'no'
- commit_message:
- description:
- - Set a commit message for the version history.
- - Only used when C(state) is C(present).
- - C(message) alias is deprecated in Ansible 2.10, since it is used internally by Ansible Core Engine.
- aliases: [ 'message' ]
- validate_certs:
- description:
- - If C(no), SSL certificates will not be validated.
- - This should only be used on personally controlled sites using self-signed certificates.
- type: bool
- default: 'yes'
- client_cert:
- description:
- - PEM formatted certificate chain file to be used for SSL client authentication.
- - This file can also include the key as well, and if the key is included, client_key is not required
- version_added: 2.7
- client_key:
- description:
- - PEM formatted file that contains your private key to be used for SSL client
- - authentication. If client_cert contains both the certificate and key, this option is not required
- version_added: 2.7
- use_proxy:
- description:
- - Boolean of whether or not to use proxy.
- default: 'yes'
- type: bool
- version_added: 2.7
-'''
-
-EXAMPLES = '''
-- hosts: localhost
- connection: local
- tasks:
- - name: Import Grafana dashboard foo
- grafana_dashboard:
- grafana_url: http://grafana.company.com
- grafana_api_key: "{{ grafana_api_key }}"
- state: present
- commit_message: Updated by ansible
- overwrite: yes
- path: /path/to/dashboards/foo.json
-
- - name: Export dashboard
- grafana_dashboard:
- grafana_url: http://grafana.company.com
- grafana_user: "admin"
- grafana_password: "{{ grafana_password }}"
- org_id: 1
- state: export
- uid: "000000653"
- path: "/path/to/dashboards/000000653.json"
-'''
-
-RETURN = '''
----
-uid:
- description: uid or slug of the created / deleted / exported dashboard.
- returned: success
- type: str
- sample: 000000063
-'''
-
-import json
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.urls import fetch_url, url_argument_spec
-from ansible.module_utils.six.moves.urllib.parse import urlencode
-from ansible.module_utils._text import to_native
-from ansible.module_utils._text import to_text
-
-__metaclass__ = type
-
-
-class GrafanaAPIException(Exception):
- pass
-
-
-class GrafanaMalformedJson(Exception):
- pass
-
-
-class GrafanaExportException(Exception):
- pass
-
-
-class GrafanaDeleteException(Exception):
- pass
-
-
-def grafana_switch_organisation(module, grafana_url, org_id, headers):
- r, info = fetch_url(module, '%s/api/user/using/%s' % (grafana_url, org_id), headers=headers, method='POST')
- if info['status'] != 200:
- raise GrafanaAPIException('Unable to switch to organization %s : %s' % (org_id, info))
-
-
-def grafana_headers(module, data):
- headers = {'content-type': 'application/json; charset=utf8'}
- if 'grafana_api_key' in data and data['grafana_api_key']:
- headers['Authorization'] = "Bearer %s" % data['grafana_api_key']
- else:
- module.params['force_basic_auth'] = True
- grafana_switch_organisation(module, data['grafana_url'], data['org_id'], headers)
-
- return headers
-
-
-def get_grafana_version(module, grafana_url, headers):
- grafana_version = None
- r, info = fetch_url(module, '%s/api/frontend/settings' % grafana_url, headers=headers, method='GET')
- if info['status'] == 200:
- try:
- settings = json.loads(to_text(r.read()))
- grafana_version = settings['buildInfo']['version'].split('.')[0]
- except UnicodeError as e:
- raise GrafanaAPIException('Unable to decode version string to Unicode')
- except Exception as e:
- raise GrafanaAPIException(e)
- else:
- raise GrafanaAPIException('Unable to get grafana version : %s' % info)
-
- return int(grafana_version)
-
-
-def grafana_folder_exists(module, grafana_url, folder_name, headers):
- # the 'General' folder is a special case, it's ID is always '0'
- if folder_name == 'General':
- return True, 0
-
- try:
- r, info = fetch_url(module, '%s/api/folders' % grafana_url, headers=headers, method='GET')
-
- if info['status'] != 200:
- raise GrafanaAPIException("Unable to query Grafana API for folders (name: %s): %d" % (folder_name, info['status']))
-
- folders = json.loads(r.read())
-
- for folder in folders:
- if folder['title'] == folder_name:
- return True, folder['id']
- except Exception as e:
- raise GrafanaAPIException(e)
-
- return False, 0
-
-
-def grafana_dashboard_exists(module, grafana_url, uid, headers):
- dashboard_exists = False
- dashboard = {}
-
- grafana_version = get_grafana_version(module, grafana_url, headers)
- if grafana_version >= 5:
- uri = '%s/api/dashboards/uid/%s' % (grafana_url, uid)
- else:
- uri = '%s/api/dashboards/db/%s' % (grafana_url, uid)
-
- r, info = fetch_url(module, uri, headers=headers, method='GET')
-
- if info['status'] == 200:
- dashboard_exists = True
- try:
- dashboard = json.loads(r.read())
- except Exception as e:
- raise GrafanaAPIException(e)
- elif info['status'] == 404:
- dashboard_exists = False
- else:
- raise GrafanaAPIException('Unable to get dashboard %s : %s' % (uid, info))
-
- return dashboard_exists, dashboard
-
-
-def grafana_dashboard_search(module, grafana_url, folder_id, title, headers):
-
- # search by title
- uri = '%s/api/search?%s' % (grafana_url, urlencode({
- 'folderIds': folder_id,
- 'query': title,
- 'type': 'dash-db'
- }))
- r, info = fetch_url(module, uri, headers=headers, method='GET')
-
- if info['status'] == 200:
- try:
- dashboards = json.loads(r.read())
- for d in dashboards:
- if d['title'] == title:
- return grafana_dashboard_exists(module, grafana_url, d['uid'], headers)
- except Exception as e:
- raise GrafanaAPIException(e)
- else:
- raise GrafanaAPIException('Unable to search dashboard %s : %s' % (title, info))
-
- return False, None
-
-
-# for comparison, we sometimes need to ignore a few keys
-def grafana_dashboard_changed(payload, dashboard):
- # you don't need to set the version, but '0' is incremented to '1' by Grafana's API
- if payload['dashboard']['version'] == 0:
- del(payload['dashboard']['version'])
- del(dashboard['dashboard']['version'])
-
- # the meta key is not part of the 'payload' ever
- if 'meta' in dashboard:
- del(dashboard['meta'])
-
- # new dashboards don't require an id attribute (or, it can be 'null'), Grafana's API will generate it
- if payload['dashboard']['id'] is None:
- del(dashboard['dashboard']['id'])
- del(payload['dashboard']['id'])
-
- if payload == dashboard:
- return True
-
- return False
-
-
-def grafana_create_dashboard(module, data):
-
- # define data payload for grafana API
- try:
- with open(data['path'], 'r') as json_file:
- payload = json.load(json_file)
- except Exception as e:
- raise GrafanaAPIException("Can't load json file %s" % to_native(e))
-
- # Check that the dashboard JSON is nested under the 'dashboard' key
- if 'dashboard' not in payload:
- payload = {'dashboard': payload}
-
- # define http header
- headers = grafana_headers(module, data)
-
- grafana_version = get_grafana_version(module, data['grafana_url'], headers)
- if grafana_version < 5:
- if data.get('slug'):
- uid = data['slug']
- elif 'meta' in payload and 'slug' in payload['meta']:
- uid = payload['meta']['slug']
- else:
- raise GrafanaMalformedJson('No slug found in json. Needed with grafana < 5')
- else:
- if data.get('uid'):
- uid = data['uid']
- elif 'uid' in payload['dashboard']:
- uid = payload['dashboard']['uid']
- else:
- uid = None
-
- result = {}
-
- # test if the folder exists
- if grafana_version >= 5:
- folder_exists, folder_id = grafana_folder_exists(module, data['grafana_url'], data['folder'], headers)
- if folder_exists is False:
- result['msg'] = "Dashboard folder '%s' does not exist." % data['folder']
- result['uid'] = uid
- result['changed'] = False
- return result
-
- payload['folderId'] = folder_id
-
- # test if dashboard already exists
- if uid:
- dashboard_exists, dashboard = grafana_dashboard_exists(
- module, data['grafana_url'], uid, headers=headers)
- else:
- dashboard_exists, dashboard = grafana_dashboard_search(
- module, data['grafana_url'], folder_id, payload['dashboard']['title'], headers=headers)
-
- if dashboard_exists is True:
- if grafana_dashboard_changed(payload, dashboard):
- # update
- if 'overwrite' in data and data['overwrite']:
- payload['overwrite'] = True
- if 'commit_message' in data and data['commit_message']:
- payload['message'] = data['commit_message']
-
- r, info = fetch_url(module, '%s/api/dashboards/db' % data['grafana_url'],
- data=json.dumps(payload), headers=headers, method='POST')
- if info['status'] == 200:
- if grafana_version >= 5:
- try:
- dashboard = json.loads(r.read())
- uid = dashboard['uid']
- except Exception as e:
- raise GrafanaAPIException(e)
- result['uid'] = uid
- result['msg'] = "Dashboard %s updated" % payload['dashboard']['title']
- result['changed'] = True
- else:
- body = json.loads(info['body'])
- raise GrafanaAPIException('Unable to update the dashboard %s : %s (HTTP: %d)' %
- (uid, body['commit_message'], info['status']))
- else:
- # unchanged
- result['uid'] = uid
- result['msg'] = "Dashboard %s unchanged." % payload['dashboard']['title']
- result['changed'] = False
- else:
- # create
- if folder_exists is True:
- payload['folderId'] = folder_id
-
- r, info = fetch_url(module, '%s/api/dashboards/db' % data['grafana_url'],
- data=json.dumps(payload), headers=headers, method='POST')
- if info['status'] == 200:
- result['msg'] = "Dashboard %s created" % payload['dashboard']['title']
- result['changed'] = True
- if grafana_version >= 5:
- try:
- dashboard = json.loads(r.read())
- uid = dashboard['uid']
- except Exception as e:
- raise GrafanaAPIException(e)
- result['uid'] = uid
- else:
- raise GrafanaAPIException('Unable to create the new dashboard %s : %s - %s.' %
- (payload['dashboard']['title'], info['status'], info))
-
- return result
-
-
-def grafana_delete_dashboard(module, data):
-
- # define http headers
- headers = grafana_headers(module, data)
-
- grafana_version = get_grafana_version(module, data['grafana_url'], headers)
- if grafana_version < 5:
- if data.get('slug'):
- uid = data['slug']
- else:
- raise GrafanaMalformedJson('No slug parameter. Needed with grafana < 5')
- else:
- if data.get('uid'):
- uid = data['uid']
- else:
- raise GrafanaDeleteException('No uid specified %s')
-
- # test if dashboard already exists
- dashboard_exists, dashboard = grafana_dashboard_exists(module, data['grafana_url'], uid, headers=headers)
-
- result = {}
- if dashboard_exists is True:
- # delete
- if grafana_version < 5:
- r, info = fetch_url(module, '%s/api/dashboards/db/%s' % (data['grafana_url'], uid), headers=headers, method='DELETE')
- else:
- r, info = fetch_url(module, '%s/api/dashboards/uid/%s' % (data['grafana_url'], uid), headers=headers, method='DELETE')
- if info['status'] == 200:
- result['msg'] = "Dashboard %s deleted" % uid
- result['changed'] = True
- result['uid'] = uid
- else:
- raise GrafanaAPIException('Unable to update the dashboard %s : %s' % (uid, info))
- else:
- # dashboard does not exist, do nothing
- result = {'msg': "Dashboard %s does not exist." % uid,
- 'changed': False,
- 'uid': uid}
-
- return result
-
-
-def grafana_export_dashboard(module, data):
-
- # define http headers
- headers = grafana_headers(module, data)
-
- grafana_version = get_grafana_version(module, data['grafana_url'], headers)
- if grafana_version < 5:
- if data.get('slug'):
- uid = data['slug']
- else:
- raise GrafanaMalformedJson('No slug parameter. Needed with grafana < 5')
- else:
- if data.get('uid'):
- uid = data['uid']
- else:
- raise GrafanaExportException('No uid specified')
-
- # test if dashboard already exists
- dashboard_exists, dashboard = grafana_dashboard_exists(module, data['grafana_url'], uid, headers=headers)
-
- if dashboard_exists is True:
- try:
- with open(data['path'], 'w') as f:
- f.write(json.dumps(dashboard))
- except Exception as e:
- raise GrafanaExportException("Can't write json file : %s" % to_native(e))
- result = {'msg': "Dashboard %s exported to %s" % (uid, data['path']),
- 'uid': uid,
- 'changed': True}
- else:
- result = {'msg': "Dashboard %s does not exist." % uid,
- 'uid': uid,
- 'changed': False}
-
- return result
-
-
-def main():
- # use the predefined argument spec for url
- argument_spec = url_argument_spec()
- # remove unnecessary arguments
- del argument_spec['force']
- del argument_spec['force_basic_auth']
- del argument_spec['http_agent']
- argument_spec.update(
- state=dict(choices=['present', 'absent', 'export'], default='present'),
- url=dict(aliases=['grafana_url'], required=True),
- url_username=dict(aliases=['grafana_user'], default='admin'),
- url_password=dict(aliases=['grafana_password'], default='admin', no_log=True),
- grafana_api_key=dict(type='str', no_log=True),
- org_id=dict(default=1, type='int'),
- folder=dict(type='str', default='General'),
- uid=dict(type='str'),
- slug=dict(type='str'),
- path=dict(type='str'),
- overwrite=dict(type='bool', default=False),
- commit_message=dict(type='str', aliases=['message'], deprecated_aliases=[dict(name='message', version='2.14')]),
- )
- module = AnsibleModule(
- argument_spec=argument_spec,
- supports_check_mode=False,
- required_together=[['url_username', 'url_password', 'org_id']],
- mutually_exclusive=[['grafana_user', 'grafana_api_key'], ['uid', 'slug']],
- )
-
- if 'message' in module.params:
- module.fail_json(msg="'message' is reserved keyword, please change this parameter to 'commit_message'")
-
- try:
- if module.params['state'] == 'present':
- result = grafana_create_dashboard(module, module.params)
- elif module.params['state'] == 'absent':
- result = grafana_delete_dashboard(module, module.params)
- else:
- result = grafana_export_dashboard(module, module.params)
- except GrafanaAPIException as e:
- module.fail_json(
- failed=True,
- msg="error : %s" % to_native(e)
- )
- return
- except GrafanaMalformedJson as e:
- module.fail_json(
- failed=True,
- msg="error : %s" % to_native(e)
- )
- return
- except GrafanaDeleteException as e:
- module.fail_json(
- failed=True,
- msg="error : Can't delete dashboard : %s" % to_native(e)
- )
- return
- except GrafanaExportException as e:
- module.fail_json(
- failed=True,
- msg="error : Can't export dashboard : %s" % to_native(e)
- )
- return
-
- module.exit_json(
- failed=False,
- **result
- )
- return
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/monitoring/grafana/grafana_datasource.py b/lib/ansible/modules/monitoring/grafana/grafana_datasource.py
deleted file mode 100644
index 21bc3f667a..0000000000
--- a/lib/ansible/modules/monitoring/grafana/grafana_datasource.py
+++ /dev/null
@@ -1,683 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2017, Thierry Sallé (@seuf)
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-
-ANSIBLE_METADATA = {
- 'status': ['preview'],
- 'supported_by': 'community',
- 'metadata_version': '1.1'
-}
-
-DOCUMENTATION = '''
----
-module: grafana_datasource
-author:
- - Thierry Sallé (@seuf)
- - Martin Wang (@martinwangjian)
-version_added: "2.5"
-short_description: Manage Grafana datasources
-description:
- - Create/update/delete Grafana datasources via API.
-options:
- grafana_url:
- description:
- - The Grafana URL.
- required: true
- name:
- description:
- - The name of the datasource.
- required: true
- ds_type:
- description:
- - The type of the datasource.
- required: true
- choices: [ graphite, prometheus, elasticsearch, influxdb, opentsdb, mysql, postgres, cloudwatch, alexanderzobnin-zabbix-datasource]
- url:
- description:
- - The URL of the datasource.
- required: true
- aliases: [ ds_url ]
- access:
- description:
- - The access mode for this datasource.
- choices: [ direct, proxy ]
- default: proxy
- url_username:
- description:
- - The Grafana API user.
- default: admin
- aliases: [ grafana_user ]
- version_added: 2.7
- url_password:
- description:
- - The Grafana API password.
- default: admin
- aliases: [ grafana_password ]
- version_added: 2.7
- grafana_api_key:
- description:
- - The Grafana API key.
- - If set, C(grafana_user) and C(grafana_password) will be ignored.
- database:
- description:
- - Name of the database for the datasource.
- - This options is required when the C(ds_type) is C(influxdb), C(elasticsearch) (index name), C(mysql) or C(postgres).
- required: false
- user:
- description:
- - The datasource login user for influxdb datasources.
- password:
- description:
- - The datasource password
- basic_auth_user:
- description:
- - The datasource basic auth user.
- - Setting this option with basic_auth_password will enable basic auth.
- basic_auth_password:
- description:
- - The datasource basic auth password, when C(basic auth) is C(yes).
- with_credentials:
- description:
- - Whether credentials such as cookies or auth headers should be sent with cross-site requests.
- type: bool
- default: 'no'
- tls_client_cert:
- description:
- - The client TLS certificate.
- - If C(tls_client_cert) and C(tls_client_key) are set, this will enable TLS authentication.
- - Starts with ----- BEGIN CERTIFICATE -----
- tls_client_key:
- description:
- - The client TLS private key
- - Starts with ----- BEGIN RSA PRIVATE KEY -----
- tls_ca_cert:
- description:
- - The TLS CA certificate for self signed certificates.
- - Only used when C(tls_client_cert) and C(tls_client_key) are set.
- tls_skip_verify:
- description:
- - Skip the TLS datasource certificate verification.
- type: bool
- default: False
- version_added: 2.6
- is_default:
- description:
- - Make this datasource the default one.
- type: bool
- default: 'no'
- org_id:
- description:
- - Grafana Organisation ID in which the datasource should be created.
- - Not used when C(grafana_api_key) is set, because the C(grafana_api_key) only belong to one organisation.
- default: 1
- state:
- description:
- - Status of the datasource
- choices: [ absent, present ]
- default: present
- es_version:
- description:
- - Elasticsearch version (for C(ds_type = elasticsearch) only)
- - Version 56 is for elasticsearch 5.6+ where you can specify the C(max_concurrent_shard_requests) option.
- choices: [ 2, 5, 56 ]
- default: 5
- max_concurrent_shard_requests:
- description:
- - Starting with elasticsearch 5.6, you can specify the max concurrent shard per requests.
- default: 256
- time_field:
- description:
- - Name of the time field in elasticsearch ds.
- - For example C(@timestamp)
- default: timestamp
- time_interval:
- description:
- - Minimum group by interval for C(influxdb) or C(elasticsearch) datasources.
- - for example C(>10s)
- interval:
- description:
- - For elasticsearch C(ds_type), this is the index pattern used.
- choices: ['', 'Hourly', 'Daily', 'Weekly', 'Monthly', 'Yearly']
- tsdb_version:
- description:
- - The opentsdb version.
- - Use C(1) for <=2.1, C(2) for ==2.2, C(3) for ==2.3.
- choices: [ 1, 2, 3 ]
- default: 1
- tsdb_resolution:
- description:
- - The opentsdb time resolution.
- choices: [ millisecond, second ]
- default: second
- sslmode:
- description:
- - SSL mode for C(postgres) datasource type.
- choices: [ disable, require, verify-ca, verify-full ]
- trends:
- required: false
- description:
- - Use trends or not for zabbix datasource type
- type: bool
- version_added: 2.6
- client_cert:
- required: false
- description:
- - TLS certificate path used by ansible to query grafana api
- version_added: 2.8
- client_key:
- required: false
- description:
- - TLS private key path used by ansible to query grafana api
- version_added: 2.8
- validate_certs:
- description:
- - Whether to validate the Grafana certificate.
- type: bool
- default: 'yes'
- use_proxy:
- description:
- - Boolean of whether or not to use proxy.
- default: 'yes'
- type: bool
- version_added: 2.8
- aws_auth_type:
- description:
- - Type for AWS authentication for CloudWatch datasource type (authType of grafana api)
- default: 'keys'
- choices: [ keys, credentials, arn ]
- version_added: 2.8
- aws_default_region:
- description:
- - AWS default region for CloudWatch datasource type
- default: 'us-east-1'
- choices: [
- ap-northeast-1, ap-northeast-2, ap-southeast-1, ap-southeast-2, ap-south-1,
- ca-central-1,
- cn-north-1, cn-northwest-1,
- eu-central-1, eu-west-1, eu-west-2, eu-west-3,
- sa-east-1,
- us-east-1, us-east-2, us-gov-west-1, us-west-1, us-west-2
- ]
- version_added: 2.8
- aws_credentials_profile:
- description:
- - Profile for AWS credentials for CloudWatch datasource type when C(aws_auth_type) is C(credentials)
- default: ''
- required: false
- version_added: 2.8
- aws_access_key:
- description:
- - AWS access key for CloudWatch datasource type when C(aws_auth_type) is C(keys)
- default: ''
- required: false
- version_added: 2.8
- aws_secret_key:
- description:
- - AWS secret key for CloudWatch datasource type when C(aws_auth_type) is C(keys)
- default: ''
- required: false
- version_added: 2.8
- aws_assume_role_arn:
- description:
- - AWS IAM role arn to assume for CloudWatch datasource type when C(aws_auth_type) is C(arn)
- default: ''
- required: false
- version_added: 2.8
- aws_custom_metrics_namespaces:
- description:
- - Namespaces of Custom Metrics for CloudWatch datasource type
- default: ''
- required: false
- version_added: 2.8
-
-'''
-
-EXAMPLES = '''
----
-- name: Create elasticsearch datasource
- grafana_datasource:
- name: "datasource-elastic"
- grafana_url: "https://grafana.company.com"
- grafana_user: "admin"
- grafana_password: "xxxxxx"
- org_id: "1"
- ds_type: "elasticsearch"
- ds_url: "https://elastic.company.com:9200"
- database: "[logstash_]YYYY.MM.DD"
- basic_auth_user: "grafana"
- basic_auth_password: "******"
- time_field: "@timestamp"
- time_interval: "1m"
- interval: "Daily"
- es_version: 56
- max_concurrent_shard_requests: 42
- tls_ca_cert: "/etc/ssl/certs/ca.pem"
-
-- name: Create influxdb datasource
- grafana_datasource:
- name: "datasource-influxdb"
- grafana_url: "https://grafana.company.com"
- grafana_user: "admin"
- grafana_password: "xxxxxx"
- org_id: "1"
- ds_type: "influxdb"
- ds_url: "https://influx.company.com:8086"
- database: "telegraf"
- time_interval: ">10s"
- tls_ca_cert: "/etc/ssl/certs/ca.pem"
-
-- name: Create postgres datasource
- grafana_datasource:
- name: "datasource-postgres"
- grafana_url: "https://grafana.company.com"
- grafana_user: "admin"
- grafana_password: "xxxxxx"
- org_id: "1"
- ds_type: "postgres"
- ds_url: "postgres.company.com:5432"
- database: "db"
- user: "postgres"
- password: "iampgroot"
- sslmode: "verify-full"
-
-- name: Create cloudwatch datasource
- grafana_datasource:
- name: "datasource-cloudwatch"
- grafana_url: "https://grafana.company.com"
- grafana_user: "admin"
- grafana_password: "xxxxxx"
- org_id: "1"
- ds_type: "cloudwatch"
- url: "http://monitoring.us-west-1.amazonaws.com"
- aws_auth_type: "keys"
- aws_default_region: "us-west-1"
- aws_access_key: "speakFriendAndEnter"
- aws_secret_key: "mel10n"
- aws_custom_metrics_namespaces: "n1,n2"
-'''
-
-RETURN = '''
----
-name:
- description: name of the datasource created.
- returned: success
- type: str
- sample: test-ds
-id:
- description: Id of the datasource
- returned: success
- type: int
- sample: 42
-before:
- description: datasource returned by grafana api
- returned: changed
- type: dict
- sample: { "access": "proxy",
- "basicAuth": false,
- "database": "test_*",
- "id": 1035,
- "isDefault": false,
- "jsonData": {
- "esVersion": 5,
- "timeField": "@timestamp",
- "timeInterval": "1m",
- },
- "name": "grafana_datasource_test",
- "orgId": 1,
- "type": "elasticsearch",
- "url": "http://elastic.company.com:9200",
- "user": "",
- "password": "",
- "withCredentials": false }
-after:
- description: datasource updated by module
- returned: changed
- type: dict
- sample: { "access": "proxy",
- "basicAuth": false,
- "database": "test_*",
- "id": 1035,
- "isDefault": false,
- "jsonData": {
- "esVersion": 5,
- "timeField": "@timestamp",
- "timeInterval": "10s",
- },
- "name": "grafana_datasource_test",
- "orgId": 1,
- "type": "elasticsearch",
- "url": "http://elastic.company.com:9200",
- "user": "",
- "password": "",
- "withCredentials": false }
-'''
-
-import json
-import base64
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.six.moves.urllib.parse import quote
-from ansible.module_utils.urls import fetch_url, url_argument_spec
-from ansible.module_utils._text import to_text
-
-__metaclass__ = type
-
-
-class GrafanaAPIException(Exception):
- pass
-
-
-def grafana_switch_organisation(module, grafana_url, org_id, headers):
- r, info = fetch_url(module, '%s/api/user/using/%d' % (grafana_url, org_id), headers=headers, method='POST')
- if info['status'] != 200:
- raise GrafanaAPIException('Unable to switch to organization %s : %s' % (org_id, info))
-
-
-def grafana_headers(module, data):
- headers = {'content-type': 'application/json; charset=utf8'}
- if 'grafana_api_key' in data and data['grafana_api_key']:
- headers['Authorization'] = "Bearer %s" % data['grafana_api_key']
- else:
- module.params['force_basic_auth'] = True
- grafana_switch_organisation(module, data['grafana_url'], data['org_id'], headers)
-
- return headers
-
-
-def grafana_datasource_exists(module, grafana_url, name, headers):
- datasource_exists = False
- ds = {}
- r, info = fetch_url(module, '%s/api/datasources/name/%s' % (grafana_url, quote(name)), headers=headers, method='GET')
- if info['status'] == 200:
- datasource_exists = True
- ds = json.loads(to_text(r.read(), errors='surrogate_or_strict'))
- elif info['status'] == 404:
- datasource_exists = False
- else:
- raise GrafanaAPIException('Unable to get datasource %s : %s' % (name, info))
-
- return datasource_exists, ds
-
-
-def grafana_create_datasource(module, data):
-
- # define data payload for grafana API
- payload = {'orgId': data['org_id'],
- 'name': data['name'],
- 'type': data['ds_type'],
- 'access': data['access'],
- 'url': data['url'],
- 'database': data['database'],
- 'withCredentials': data['with_credentials'],
- 'isDefault': data['is_default'],
- 'user': data['user'],
- 'password': data['password']}
-
- # define basic auth
- if 'basic_auth_user' in data and data['basic_auth_user'] and 'basic_auth_password' in data and data['basic_auth_password']:
- payload['basicAuth'] = True
- payload['basicAuthUser'] = data['basic_auth_user']
- payload['basicAuthPassword'] = data['basic_auth_password']
- else:
- payload['basicAuth'] = False
-
- # define tls auth
- json_data = {}
- if data.get('tls_client_cert') and data.get('tls_client_key'):
- json_data['tlsAuth'] = True
- if data.get('tls_ca_cert'):
- payload['secureJsonData'] = {
- 'tlsCACert': data['tls_ca_cert'],
- 'tlsClientCert': data['tls_client_cert'],
- 'tlsClientKey': data['tls_client_key']
- }
- json_data['tlsAuthWithCACert'] = True
- else:
- payload['secureJsonData'] = {
- 'tlsClientCert': data['tls_client_cert'],
- 'tlsClientKey': data['tls_client_key']
- }
- else:
- json_data['tlsAuth'] = False
- json_data['tlsAuthWithCACert'] = False
- if data.get('tls_ca_cert'):
- payload['secureJsonData'] = {
- 'tlsCACert': data['tls_ca_cert']
- }
-
- if data.get('tls_skip_verify'):
- json_data['tlsSkipVerify'] = True
-
- # datasource type related parameters
- if data['ds_type'] == 'elasticsearch':
- json_data['esVersion'] = data['es_version']
- json_data['timeField'] = data['time_field']
- if data.get('interval'):
- json_data['interval'] = data['interval']
- if data['es_version'] >= 56:
- json_data['maxConcurrentShardRequests'] = data['max_concurrent_shard_requests']
-
- if data['ds_type'] == 'elasticsearch' or data['ds_type'] == 'influxdb':
- if data.get('time_interval'):
- json_data['timeInterval'] = data['time_interval']
-
- if data['ds_type'] == 'opentsdb':
- json_data['tsdbVersion'] = data['tsdb_version']
- if data['tsdb_resolution'] == 'second':
- json_data['tsdbResolution'] = 1
- else:
- json_data['tsdbResolution'] = 2
-
- if data['ds_type'] == 'postgres':
- json_data['sslmode'] = data['sslmode']
- if data.get('password'):
- payload['secureJsonData'] = {'password': data.get('password')}
-
- if data['ds_type'] == 'alexanderzobnin-zabbix-datasource':
- if data.get('trends'):
- json_data['trends'] = True
-
- if data['ds_type'] == 'cloudwatch':
- if data.get('aws_credentials_profle'):
- payload['database'] = data.get('aws_credentials_profile')
-
- json_data['authType'] = data['aws_auth_type']
- json_data['defaultRegion'] = data['aws_default_region']
-
- if data.get('aws_custom_metrics_namespaces'):
- json_data['customMetricsNamespaces'] = data.get('aws_custom_metrics_namespaces')
- if data.get('aws_assume_role_arn'):
- json_data['assumeRoleArn'] = data.get('aws_assume_role_arn')
- if data.get('aws_access_key') and data.get('aws_secret_key'):
- payload['secureJsonData'] = {'accessKey': data.get('aws_access_key'), 'secretKey': data.get('aws_secret_key')}
-
- payload['jsonData'] = json_data
-
- # define http header
- headers = grafana_headers(module, data)
-
- # test if datasource already exists
- datasource_exists, ds = grafana_datasource_exists(module, data['grafana_url'], data['name'], headers=headers)
-
- result = {}
- if datasource_exists is True:
- del ds['typeLogoUrl']
- if ds.get('version'):
- del ds['version']
- if ds.get('readOnly'):
- del ds['readOnly']
- if ds['basicAuth'] is False:
- del ds['basicAuthUser']
- del ds['basicAuthPassword']
- if 'jsonData' in ds:
- if 'tlsAuth' in ds['jsonData'] and ds['jsonData']['tlsAuth'] is False:
- del ds['secureJsonFields']
- if 'tlsAuth' not in ds['jsonData']:
- del ds['secureJsonFields']
- payload['id'] = ds['id']
- if ds == payload:
- # unchanged
- result['name'] = data['name']
- result['id'] = ds['id']
- result['msg'] = "Datasource %s unchanged." % data['name']
- result['changed'] = False
- else:
- # update
- r, info = fetch_url(module, '%s/api/datasources/%d' % (data['grafana_url'], ds['id']), data=json.dumps(payload), headers=headers, method='PUT')
- if info['status'] == 200:
- res = json.loads(to_text(r.read(), errors='surrogate_or_strict'))
- result['name'] = data['name']
- result['id'] = ds['id']
- result['before'] = ds
- result['after'] = payload
- result['msg'] = "Datasource %s updated %s" % (data['name'], res['message'])
- result['changed'] = True
- else:
- raise GrafanaAPIException('Unable to update the datasource id %d : %s' % (ds['id'], info))
- else:
- # create
- r, info = fetch_url(module, '%s/api/datasources' % data['grafana_url'], data=json.dumps(payload), headers=headers, method='POST')
- if info['status'] == 200:
- res = json.loads(to_text(r.read(), errors='surrogate_or_strict'))
- result['msg'] = "Datasource %s created : %s" % (data['name'], res['message'])
- result['changed'] = True
- result['name'] = data['name']
- result['id'] = res['id']
- else:
- raise GrafanaAPIException('Unable to create the new datasource %s : %s - %s.' % (data['name'], info['status'], info))
-
- return result
-
-
-def grafana_delete_datasource(module, data):
-
- headers = grafana_headers(module, data)
-
- # test if datasource already exists
- datasource_exists, ds = grafana_datasource_exists(module, data['grafana_url'], data['name'], headers=headers)
-
- result = {}
- if datasource_exists is True:
- # delete
- r, info = fetch_url(module, '%s/api/datasources/name/%s' % (data['grafana_url'], quote(data['name'])), headers=headers, method='DELETE')
- if info['status'] == 200:
- res = json.loads(to_text(r.read(), errors='surrogate_or_strict'))
- result['msg'] = "Datasource %s deleted : %s" % (data['name'], res['message'])
- result['changed'] = True
- result['name'] = data['name']
- result['id'] = 0
- else:
- raise GrafanaAPIException('Unable to update the datasource id %s : %s' % (ds['id'], info))
- else:
- # datasource does not exist, do nothing
- result = {'msg': "Datasource %s does not exist." % data['name'],
- 'changed': False,
- 'id': 0,
- 'name': data['name']}
-
- return result
-
-
-def main():
- # use the predefined argument spec for url
- argument_spec = url_argument_spec()
- # remove unnecessary arguments
- del argument_spec['force']
- del argument_spec['force_basic_auth']
- del argument_spec['http_agent']
-
- argument_spec.update(
- name=dict(required=True, type='str'),
- state=dict(choices=['present', 'absent'],
- default='present'),
- grafana_url=dict(type='str', required=True),
- url_username=dict(aliases=['grafana_user'], default='admin'),
- url_password=dict(aliases=['grafana_password'], default='admin', no_log=True),
- ds_type=dict(choices=['graphite',
- 'prometheus',
- 'elasticsearch',
- 'influxdb',
- 'opentsdb',
- 'mysql',
- 'postgres',
- 'cloudwatch',
- 'alexanderzobnin-zabbix-datasource']),
- url=dict(required=True, type='str', aliases=['ds_url']),
- access=dict(default='proxy', choices=['proxy', 'direct']),
- grafana_api_key=dict(type='str', no_log=True),
- database=dict(type='str'),
- user=dict(default='', type='str'),
- password=dict(default='', no_log=True, type='str'),
- basic_auth_user=dict(type='str'),
- basic_auth_password=dict(type='str', no_log=True),
- with_credentials=dict(default=False, type='bool'),
- tls_client_cert=dict(type='str', no_log=True),
- tls_client_key=dict(type='str', no_log=True),
- tls_ca_cert=dict(type='str', no_log=True),
- tls_skip_verify=dict(type='bool', default=False),
- is_default=dict(default=False, type='bool'),
- org_id=dict(default=1, type='int'),
- es_version=dict(type='int', default=5, choices=[2, 5, 56]),
- max_concurrent_shard_requests=dict(type='int', default=256),
- time_field=dict(default='@timestamp', type='str'),
- time_interval=dict(type='str'),
- interval=dict(type='str', choices=['', 'Hourly', 'Daily', 'Weekly', 'Monthly', 'Yearly'], default=''),
- tsdb_version=dict(type='int', default=1, choices=[1, 2, 3]),
- tsdb_resolution=dict(type='str', default='second', choices=['second', 'millisecond']),
- sslmode=dict(default='disable', choices=['disable', 'require', 'verify-ca', 'verify-full']),
- trends=dict(default=False, type='bool'),
- aws_auth_type=dict(default='keys', choices=['keys', 'credentials', 'arn']),
- aws_default_region=dict(default='us-east-1', choices=['ap-northeast-1', 'ap-northeast-2', 'ap-southeast-1', 'ap-southeast-2', 'ap-south-1',
- 'ca-central-1',
- 'cn-north-1', 'cn-northwest-1',
- 'eu-central-1', 'eu-west-1', 'eu-west-2', 'eu-west-3',
- 'sa-east-1',
- 'us-east-1', 'us-east-2', 'us-gov-west-1', 'us-west-1', 'us-west-2']),
- aws_access_key=dict(default='', no_log=True, type='str'),
- aws_secret_key=dict(default='', no_log=True, type='str'),
- aws_credentials_profile=dict(default='', type='str'),
- aws_assume_role_arn=dict(default='', type='str'),
- aws_custom_metrics_namespaces=dict(type='str'),
- )
-
- module = AnsibleModule(
- argument_spec=argument_spec,
- supports_check_mode=False,
- required_together=[['url_username', 'url_password', 'org_id'], ['tls_client_cert', 'tls_client_key']],
- mutually_exclusive=[['url_username', 'grafana_api_key'], ['tls_ca_cert', 'tls_skip_verify']],
- required_if=[
- ['ds_type', 'opentsdb', ['tsdb_version', 'tsdb_resolution']],
- ['ds_type', 'influxdb', ['database']],
- ['ds_type', 'elasticsearch', ['database', 'es_version', 'time_field', 'interval']],
- ['ds_type', 'mysql', ['database']],
- ['ds_type', 'postgres', ['database', 'sslmode']],
- ['ds_type', 'cloudwatch', ['aws_auth_type', 'aws_default_region']],
- ['es_version', 56, ['max_concurrent_shard_requests']]
- ],
- )
-
- try:
- if module.params['state'] == 'present':
- result = grafana_create_datasource(module, module.params)
- else:
- result = grafana_delete_datasource(module, module.params)
- except GrafanaAPIException as e:
- module.fail_json(
- failed=True,
- msg="error %s : %s " % (type(e), e)
- )
- return
-
- module.exit_json(
- failed=False,
- **result
- )
- return
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/monitoring/grafana/grafana_plugin.py b/lib/ansible/modules/monitoring/grafana/grafana_plugin.py
deleted file mode 100644
index 418253a108..0000000000
--- a/lib/ansible/modules/monitoring/grafana/grafana_plugin.py
+++ /dev/null
@@ -1,257 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2017, Thierry Sallé (@seuf)
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-
-ANSIBLE_METADATA = {
- 'status': ['preview'],
- 'supported_by': 'community',
- 'metadata_version': '1.1'
-}
-
-DOCUMENTATION = '''
----
-module: grafana_plugin
-author:
- - Thierry Sallé (@seuf)
-version_added: "2.5"
-short_description: Manage Grafana plugins via grafana-cli
-description:
- - Install and remove Grafana plugins.
- - See U(https://grafana.com/docs/plugins/installation/) for upstream documentation.
-options:
- name:
- description:
- - Name of the plugin.
- required: true
- version:
- description:
- - Version of the plugin to install.
- - Defaults to C(latest).
- grafana_plugins_dir:
- description:
- - Directory where the Grafana plugin will be installed.
- - If omitted, defaults to C(/var/lib/grafana/plugins).
- grafana_repo:
- description:
- - URL to the Grafana plugin repository.
- - "If omitted, grafana-cli will use the default value: U(https://grafana.com/api/plugins)."
- grafana_plugin_url:
- description:
- - Full URL to the plugin zip file instead of downloading the file from U(https://grafana.com/api/plugins).
- - Requires grafana 4.6.x or later.
- state:
- description:
- - Whether the plugin should be installed.
- choices:
- - present
- - absent
- default: present
-'''
-
-EXAMPLES = '''
----
-- name: Install/update Grafana piechart panel plugin
- grafana_plugin:
- name: grafana-piechart-panel
- version: latest
- state: present
-'''
-
-RETURN = '''
----
-version:
- description: version of the installed/removed/updated plugin.
- type: str
- returned: always
-'''
-
-import base64
-import json
-import os
-from ansible.module_utils.basic import AnsibleModule
-
-__metaclass__ = type
-
-
-class GrafanaCliException(Exception):
- pass
-
-
-def grafana_cli_bin(params):
- '''
- Get the grafana-cli binary path with global options.
- Raise a GrafanaCliException if the grafana-cli is not present or not in PATH
-
- :param params: ansible module params. Used to fill grafana-cli global params.
- '''
- program = 'grafana-cli'
- grafana_cli = None
-
- def is_exe(fpath):
- return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
-
- fpath, fname = os.path.split(program)
- if fpath:
- if is_exe(program):
- grafana_cli = program
- else:
- for path in os.environ["PATH"].split(os.pathsep):
- path = path.strip('"')
- exe_file = os.path.join(path, program)
- if is_exe(exe_file):
- grafana_cli = exe_file
- break
-
- if grafana_cli is None:
- raise GrafanaCliException('grafana-cli binary is not present or not in PATH')
- else:
- if 'grafana_plugin_url' in params and params['grafana_plugin_url']:
- grafana_cli = '{0} {1} {2}'.format(grafana_cli, '--pluginUrl', params['grafana_plugin_url'])
- if 'grafana_plugins_dir' in params and params['grafana_plugins_dir']:
- grafana_cli = '{0} {1} {2}'.format(grafana_cli, '--pluginsDir', params['grafana_plugins_dir'])
- if 'grafana_repo' in params and params['grafana_repo']:
- grafana_cli = '{0} {1} {2}'.format(grafana_cli, '--repo', params['grafana_repo'])
- if 'validate_certs' in params and params['validate_certs'] is False:
- grafana_cli = '{0} {1}'.format(grafana_cli, '--insecure')
-
- return '{0} {1}'.format(grafana_cli, 'plugins')
-
-
-def get_grafana_plugin_version(module, params):
- '''
- Fetch grafana installed plugin version. Return None if plugin is not installed.
-
- :param module: ansible module object. used to run system commands.
- :param params: ansible module params.
- '''
- grafana_cli = grafana_cli_bin(params)
- rc, stdout, stderr = module.run_command('{0} ls'.format(grafana_cli))
- stdout_lines = stdout.split("\n")
- for line in stdout_lines:
- if line.find(' @ ') != -1:
- line = line.rstrip()
- plugin_name, plugin_version = line.split(' @ ')
- if plugin_name == params['name']:
- return plugin_version
- return None
-
-
-def get_grafana_plugin_version_latest(module, params):
- '''
- Fetch the latest version available from grafana-cli.
- Return the newest version number or None not found.
-
- :param module: ansible module object. used to run system commands.
- :param params: ansible module params.
- '''
- grafana_cli = grafana_cli_bin(params)
- rc, stdout, stderr = module.run_command('{0} list-versions {1}'.format(grafana_cli,
- params['name']))
- stdout_lines = stdout.split("\n")
- if stdout_lines[0]:
- return stdout_lines[0].rstrip()
- return None
-
-
-def grafana_plugin(module, params):
- '''
- Install update or remove grafana plugin
-
- :param module: ansible module object. used to run system commands.
- :param params: ansible module params.
- '''
- grafana_cli = grafana_cli_bin(params)
-
- if params['state'] == 'present':
- grafana_plugin_version = get_grafana_plugin_version(module, params)
- if grafana_plugin_version is not None:
- if 'version' in params and params['version']:
- if params['version'] == grafana_plugin_version:
- return {'msg': 'Grafana plugin already installed',
- 'changed': False,
- 'version': grafana_plugin_version}
- else:
- if params['version'] == 'latest' or params['version'] is None:
- latest_version = get_grafana_plugin_version_latest(module, params)
- if latest_version == grafana_plugin_version:
- return {'msg': 'Grafana plugin already installed',
- 'changed': False,
- 'version': grafana_plugin_version}
- cmd = '{0} update {1}'.format(grafana_cli, params['name'])
- else:
- cmd = '{0} install {1} {2}'.format(grafana_cli, params['name'], params['version'])
- else:
- return {'msg': 'Grafana plugin already installed',
- 'changed': False,
- 'version': grafana_plugin_version}
- else:
- if 'version' in params:
- if params['version'] == 'latest' or params['version'] is None:
- cmd = '{0} install {1}'.format(grafana_cli, params['name'])
- else:
- cmd = '{0} install {1} {2}'.format(grafana_cli, params['name'], params['version'])
- else:
- cmd = '{0} install {1}'.format(grafana_cli, params['name'])
- else:
- cmd = '{0} uninstall {1}'.format(grafana_cli, params['name'])
-
- rc, stdout, stderr = module.run_command(cmd)
- if rc == 0:
- stdout_lines = stdout.split("\n")
- for line in stdout_lines:
- if line.find(params['name']):
- if line.find(' @ ') != -1:
- line = line.rstrip()
- plugin_name, plugin_version = line.split(' @ ')
- else:
- plugin_version = None
- return {'msg': 'Grafana plugin {0} installed : {1}'.format(params['name'], cmd),
- 'changed': True,
- 'version': plugin_version}
- else:
- raise GrafanaCliException("'{0}' execution returned an error : [{1}] {2} {3}".format(cmd, rc, stdout, stderr))
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- name=dict(required=True,
- type='str'),
- version=dict(type='str'),
- grafana_plugins_dir=dict(type='str'),
- grafana_repo=dict(type='str'),
- grafana_plugin_url=dict(type='str'),
- state=dict(choices=['present', 'absent'],
- default='present')
- ),
- supports_check_mode=False
- )
-
- try:
- result = grafana_plugin(module, module.params)
- except GrafanaCliException as e:
- module.fail_json(
- failed=True,
- msg="{0}".format(e)
- )
- return
- except Exception as e:
- module.fail_json(
- failed=True,
- msg="{0} : {1} ".format(type(e), e)
- )
- return
-
- module.exit_json(
- failed=False,
- **result
- )
- return
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/plugins/callback/grafana_annotations.py b/lib/ansible/plugins/callback/grafana_annotations.py
deleted file mode 100644
index d1d6ed82e7..0000000000
--- a/lib/ansible/plugins/callback/grafana_annotations.py
+++ /dev/null
@@ -1,273 +0,0 @@
-# -*- coding: utf-8 -*-
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-import socket
-import getpass
-from base64 import b64encode
-from datetime import datetime
-
-from ansible.module_utils._text import to_text
-from ansible.module_utils.urls import open_url
-from ansible.plugins.callback import CallbackBase
-
-
-DOCUMENTATION = """
- callback: grafana_annotations
- callback_type: notification
- short_description: send ansible events as annotations on charts to grafana over http api.
- author: "Rémi REY (@rrey)"
- description:
- - This callback will report start, failed and stats events to Grafana as annotations (https://grafana.com)
- version_added: "2.6"
- requirements:
- - whitelisting in configuration
- options:
- grafana_url:
- description: Grafana annotations api URL
- required: True
- env:
- - name: GRAFANA_URL
- ini:
- - section: callback_grafana_annotations
- key: grafana_url
- type: string
- validate_certs:
- description: validate the SSL certificate of the Grafana server. (For HTTPS url)
- env:
- - name: GRAFANA_VALIDATE_CERT
- ini:
- - section: callback_grafana_annotations
- key: validate_grafana_certs
- - section: callback_grafana_annotations
- key: validate_certs
- default: True
- type: bool
- aliases: [ validate_grafana_certs ]
- http_agent:
- description: The HTTP 'User-agent' value to set in HTTP requets.
- env:
- - name: HTTP_AGENT
- ini:
- - section: callback_grafana_annotations
- key: http_agent
- default: 'Ansible (grafana_annotations callback)'
- type: string
- grafana_api_key:
- description: Grafana API key, allowing to authenticate when posting on the HTTP API.
- If not provided, grafana_login and grafana_password will
- be required.
- env:
- - name: GRAFANA_API_KEY
- ini:
- - section: callback_grafana_annotations
- key: grafana_api_key
- type: string
- grafana_user:
- description: Grafana user used for authentication. Ignored if grafana_api_key is provided.
- env:
- - name: GRAFANA_USER
- ini:
- - section: callback_grafana_annotations
- key: grafana_user
- default: ansible
- type: string
- grafana_password:
- description: Grafana password used for authentication. Ignored if grafana_api_key is provided.
- env:
- - name: GRAFANA_PASSWORD
- ini:
- - section: callback_grafana_annotations
- key: grafana_password
- default: ansible
- type: string
- grafana_dashboard_id:
- description: The grafana dashboard id where the annotation shall be created.
- env:
- - name: GRAFANA_DASHBOARD_ID
- ini:
- - section: callback_grafana_annotations
- key: grafana_dashboard_id
- type: integer
- grafana_panel_ids:
- description: The grafana panel ids where the annotation shall be created.
- Give a single integer or a comma-separated list of integers.
- env:
- - name: GRAFANA_PANEL_IDS
- ini:
- - section: callback_grafana_annotations
- key: grafana_panel_ids
- default: []
- type: list
-"""
-
-
-PLAYBOOK_START_TXT = """\
-Started playbook {playbook}
-
-From '{hostname}'
-By user '{username}'
-"""
-
-PLAYBOOK_ERROR_TXT = """\
-Playbook {playbook} Failure !
-
-From '{hostname}'
-By user '{username}'
-
-'{task}' failed on {host}
-
-debug: {result}
-"""
-
-PLAYBOOK_STATS_TXT = """\
-Playbook {playbook}
-Duration: {duration}
-Status: {status}
-
-From '{hostname}'
-By user '{username}'
-
-Result:
-{summary}
-"""
-
-
-def to_millis(dt):
- return int(dt.strftime('%s')) * 1000
-
-
-class CallbackModule(CallbackBase):
- """
- ansible grafana callback plugin
- ansible.cfg:
- callback_plugins = <path_to_callback_plugins_folder>
- callback_whitelist = grafana_annotations
- and put the plugin in <path_to_callback_plugins_folder>
- """
-
- CALLBACK_VERSION = 2.0
- CALLBACK_TYPE = 'aggregate'
- CALLBACK_NAME = 'grafana_annotations'
- CALLBACK_NEEDS_WHITELIST = True
-
- def __init__(self, display=None):
-
- super(CallbackModule, self).__init__(display=display)
-
- self.headers = {'Content-Type': 'application/json'}
- self.force_basic_auth = False
- self.hostname = socket.gethostname()
- self.username = getpass.getuser()
- self.start_time = datetime.now()
- self.errors = 0
-
- def set_options(self, task_keys=None, var_options=None, direct=None):
-
- super(CallbackModule, self).set_options(task_keys=task_keys, var_options=var_options, direct=direct)
-
- self.grafana_api_key = self.get_option('grafana_api_key')
- self.grafana_url = self.get_option('grafana_url')
- self.validate_grafana_certs = self.get_option('validate_certs')
- self.http_agent = self.get_option('http_agent')
- self.grafana_user = self.get_option('grafana_user')
- self.grafana_password = self.get_option('grafana_password')
- self.dashboard_id = self.get_option('grafana_dashboard_id')
- self.panel_ids = self.get_option('grafana_panel_ids')
-
- if self.grafana_api_key:
- self.headers['Authorization'] = "Bearer %s" % self.grafana_api_key
- else:
- self.force_basic_auth = True
-
- if self.grafana_url is None:
- self.disabled = True
- self._display.warning('Grafana URL was not provided. The '
- 'Grafana URL can be provided using '
- 'the `GRAFANA_URL` environment variable.')
- self._display.debug('Grafana URL: %s' % self.grafana_url)
-
- def v2_playbook_on_start(self, playbook):
- self.playbook = playbook._file_name
- text = PLAYBOOK_START_TXT.format(playbook=self.playbook, hostname=self.hostname,
- username=self.username)
- data = {
- 'time': to_millis(self.start_time),
- 'text': text,
- 'tags': ['ansible', 'ansible_event_start', self.playbook]
- }
- self._send_annotation(data)
-
- def v2_playbook_on_stats(self, stats):
- end_time = datetime.now()
- duration = end_time - self.start_time
- summarize_stat = {}
- for host in stats.processed.keys():
- summarize_stat[host] = stats.summarize(host)
-
- status = "FAILED"
- if self.errors == 0:
- status = "OK"
-
- text = PLAYBOOK_STATS_TXT.format(playbook=self.playbook, hostname=self.hostname,
- duration=duration.total_seconds(),
- status=status, username=self.username,
- summary=json.dumps(summarize_stat))
-
- data = {
- 'time': to_millis(self.start_time),
- 'timeEnd': to_millis(end_time),
- 'isRegion': True,
- 'text': text,
- 'tags': ['ansible', 'ansible_report', self.playbook]
- }
- self._send_annotations(data)
-
- def v2_runner_on_failed(self, result, **kwargs):
- text = PLAYBOOK_ERROR_TXT.format(playbook=self.playbook, hostname=self.hostname,
- username=self.username, task=result._task,
- host=result._host.name, result=self._dump_results(result._result))
- data = {
- 'time': to_millis(datetime.now()),
- 'text': text,
- 'tags': ['ansible', 'ansible_event_failure', self.playbook]
- }
- self.errors += 1
- self._send_annotations(data)
-
- def _send_annotations(self, data):
- if self.dashboard_id:
- data["dashboardId"] = int(self.dashboard_id)
- if self.panel_ids:
- for panel_id in self.panel_ids:
- data["panelId"] = int(panel_id)
- self._send_annotation(data)
- else:
- self._send_annotation(data)
-
- def _send_annotation(self, annotation):
- try:
- response = open_url(self.grafana_url, data=json.dumps(annotation), headers=self.headers,
- method="POST",
- validate_certs=self.validate_grafana_certs,
- url_username=self.grafana_user, url_password=self.grafana_password,
- http_agent=self.http_agent, force_basic_auth=self.force_basic_auth)
- except Exception as e:
- self._display.error(u'Could not submit message to Grafana: %s' % to_text(e))
diff --git a/lib/ansible/plugins/lookup/grafana_dashboard.py b/lib/ansible/plugins/lookup/grafana_dashboard.py
deleted file mode 100644
index 886bc8f0a0..0000000000
--- a/lib/ansible/plugins/lookup/grafana_dashboard.py
+++ /dev/null
@@ -1,174 +0,0 @@
-# (c) 2018 Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-DOCUMENTATION = """
-lookup: grafana_dashboard
-author: Thierry Salle (@seuf)
-version_added: "2.7"
-short_description: list or search grafana dashboards
-description:
- - This lookup returns a list of grafana dashboards with possibility to filter them by query.
-options:
- grafana_url:
- description: url of grafana.
- env:
- - name: GRAFANA_URL
- default: http://127.0.0.1:3000
- grafana_api_key:
- description:
- - api key of grafana.
- - when C(grafana_api_key) is set, the options C(grafan_user), C(grafana_password) and C(grafana_org_id) are ignored.
- - Attention, please remove the two == at the end of the grafana_api_key
- - because ansible lookup plugins options are split on = (see example).
- env:
- - name: GRAFANA_API_KEY
- grafana_user:
- description: grafana authentication user.
- env:
- - name: GRAFANA_USER
- default: admin
- grafana_password:
- description: grafana authentication password.
- env:
- - name: GRAFANA_PASSWORD
- default: admin
- grafana_org_id:
- description: grafana organisation id.
- env:
- - name: GRAFANA_ORG_ID
- default: 1
- search:
- description: optional filter for dashboard search.
- env:
- - name: GRAFANA_DASHBOARD_SEARCH
-"""
-
-EXAMPLES = """
-- name: get project foo grafana dashboards
- set_fact:
- grafana_dashboards: "{{ lookup('grafana_dashboard', 'grafana_url=http://grafana.company.com grafana_user=admin grafana_password=admin search=foo') }}"
-
-- name: get all grafana dashboards
- set_fact:
- grafana_dashboards: "{{ lookup('grafana_dashboard', 'grafana_url=http://grafana.company.com grafana_api_key=' ~ grafana_api_key|replace('==', '')) }}"
-"""
-
-import base64
-import json
-import os
-from ansible.errors import AnsibleError, AnsibleParserError
-from ansible.plugins.lookup import LookupBase
-from ansible.module_utils.urls import basic_auth_header, open_url
-from ansible.module_utils._text import to_bytes, to_native
-from ansible.module_utils.six.moves.urllib.error import HTTPError
-from ansible.utils.display import Display
-
-display = Display()
-
-
-ANSIBLE_GRAFANA_URL = 'http://127.0.0.1:3000'
-ANSIBLE_GRAFANA_API_KEY = None
-ANSIBLE_GRAFANA_USER = 'admin'
-ANSIBLE_GRAFANA_PASSWORD = 'admin'
-ANSIBLE_GRAFANA_ORG_ID = 1
-ANSIBLE_GRAFANA_DASHBOARD_SEARCH = None
-
-if os.getenv('GRAFANA_URL') is not None:
- ANSIBLE_GRAFANA_URL = os.environ['GRAFANA_URL']
-
-if os.getenv('GRAFANA_API_KEY') is not None:
- ANSIBLE_GRAFANA_API_KEY = os.environ['GRAFANA_API_KEY']
-
-if os.getenv('GRAFANA_USER') is not None:
- ANSIBLE_GRAFANA_USER = os.environ['GRAFANA_USER']
-
-if os.getenv('GRAFANA_PASSWORD') is not None:
- ANSIBLE_GRAFANA_PASSWORD = os.environ['GRAFANA_PASSWORD']
-
-if os.getenv('GRAFANA_ORG_ID') is not None:
- ANSIBLE_GRAFANA_ORG_ID = os.environ['GRAFANA_ORG_ID']
-
-if os.getenv('GRAFANA_DASHBOARD_SEARCH') is not None:
- ANSIBLE_GRAFANA_DASHBOARD_SEARCH = os.environ['GRAFANA_DASHBOARD_SEARCH']
-
-
-class GrafanaAPIException(Exception):
- pass
-
-
-class GrafanaAPI:
- def __init__(self, **kwargs):
- self.grafana_url = kwargs.get('grafana_url', ANSIBLE_GRAFANA_URL)
- self.grafana_api_key = kwargs.get('grafana_api_key', ANSIBLE_GRAFANA_API_KEY)
- self.grafana_user = kwargs.get('grafana_user', ANSIBLE_GRAFANA_USER)
- self.grafana_password = kwargs.get('grafana_password', ANSIBLE_GRAFANA_PASSWORD)
- self.grafana_org_id = kwargs.get('grafana_org_id', ANSIBLE_GRAFANA_ORG_ID)
- self.search = kwargs.get('search', ANSIBLE_GRAFANA_DASHBOARD_SEARCH)
-
- def grafana_switch_organisation(self, headers):
- try:
- r = open_url('%s/api/user/using/%s' % (self.grafana_url, self.grafana_org_id), headers=headers, method='POST')
- except HTTPError as e:
- raise GrafanaAPIException('Unable to switch to organization %s : %s' % (self.grafana_org_id, to_native(e)))
- if r.getcode() != 200:
- raise GrafanaAPIException('Unable to switch to organization %s : %s' % (self.grafana_org_id, str(r.getcode())))
-
- def grafana_headers(self):
- headers = {'content-type': 'application/json; charset=utf8'}
- if self.grafana_api_key:
- headers['Authorization'] = "Bearer %s==" % self.grafana_api_key
- else:
- headers['Authorization'] = basic_auth_header(self.grafana_user, self.grafana_password)
- self.grafana_switch_organisation(headers)
-
- return headers
-
- def grafana_list_dashboards(self):
- # define http headers
- headers = self.grafana_headers()
-
- dashboard_list = []
- try:
- if self.search:
- r = open_url('%s/api/search?query=%s' % (self.grafana_url, self.search), headers=headers, method='GET')
- else:
- r = open_url('%s/api/search/' % self.grafana_url, headers=headers, method='GET')
- except HTTPError as e:
- raise GrafanaAPIException('Unable to search dashboards : %s' % to_native(e))
- if r.getcode() == 200:
- try:
- dashboard_list = json.loads(r.read())
- except Exception as e:
- raise GrafanaAPIException('Unable to parse json list %s' % to_native(e))
- else:
- raise GrafanaAPIException('Unable to list grafana dashboards : %s' % str(r.getcode()))
-
- return dashboard_list
-
-
-class LookupModule(LookupBase):
-
- def run(self, terms, variables=None, **kwargs):
-
- grafana_args = terms[0].split(' ')
- grafana_dict = {}
- ret = []
-
- for param in grafana_args:
- try:
- key, value = param.split('=')
- except ValueError:
- raise AnsibleError("grafana_dashboard lookup plugin needs key=value pairs, but received %s" % terms)
- grafana_dict[key] = value
-
- grafana = GrafanaAPI(**grafana_dict)
-
- ret = grafana.grafana_list_dashboards()
-
- return ret
diff --git a/test/integration/targets/grafana_datasource/aliases b/test/integration/targets/grafana_datasource/aliases
deleted file mode 100644
index f8e28c7e46..0000000000
--- a/test/integration/targets/grafana_datasource/aliases
+++ /dev/null
@@ -1,2 +0,0 @@
-shippable/posix/group1
-skip/aix
diff --git a/test/integration/targets/grafana_datasource/meta/main.yml b/test/integration/targets/grafana_datasource/meta/main.yml
deleted file mode 100644
index af628245fb..0000000000
--- a/test/integration/targets/grafana_datasource/meta/main.yml
+++ /dev/null
@@ -1,2 +0,0 @@
-dependencies:
- - setup_grafana
diff --git a/test/integration/targets/grafana_datasource/tasks/cloudwatch.yml b/test/integration/targets/grafana_datasource/tasks/cloudwatch.yml
deleted file mode 100644
index 1119eb1ac1..0000000000
--- a/test/integration/targets/grafana_datasource/tasks/cloudwatch.yml
+++ /dev/null
@@ -1,67 +0,0 @@
----
-
-- name: Create cloudwatch datasource
- grafana_datasource:
- name: "datasource-cloudwatch"
- grafana_url: "http://127.0.0.1:3000"
- grafana_user: "admin"
- grafana_password: "admin"
- org_id: "1"
- ds_type: "cloudwatch"
- url: "http://monitoring.us-west-1.amazonaws.com"
- aws_auth_type: "keys"
- aws_default_region: "us-west-1"
- aws_access_key: "speakFriendAndEnter"
- aws_secret_key: "mel10n"
- aws_custom_metrics_namespaces: "n1,n2"
- register: result
-
-- debug:
- var: result
-
-- assert:
- that:
- - "result.changed == true"
- - "result.name == 'datasource-cloudwatch'"
- - "result.msg == 'Datasource datasource-cloudwatch created : Datasource added'"
-
-- name: Check cloudwatch datasource creation idempotency
- grafana_datasource:
- name: "datasource-cloudwatch"
- grafana_url: "http://127.0.0.1:3000"
- grafana_user: "admin"
- grafana_password: "admin"
- org_id: "1"
- ds_type: "cloudwatch"
- url: "http://monitoring.us-west-1.amazonaws.com"
- aws_auth_type: "keys"
- aws_default_region: "us-west-1"
- aws_access_key: "speakFriendAndEnter"
- aws_secret_key: "mel10n"
- aws_custom_metrics_namespaces: "n1,n2"
- register: result
-
-- debug:
- var: result
-
-- assert:
- that:
- # Idempotency is not working currently
- # "result.changed == false"
- - "result.name == 'datasource-cloudwatch'"
- - "result.after.access == 'proxy'"
- - "result.after.basicAuth == false"
- - "result.after.database == None"
- - "result.after.isDefault == false"
- - "result.after.jsonData.authType == 'keys'"
- - "result.after.jsonData.customMetricsNamespaces == 'n1,n2'"
- - "result.after.jsonData.defaultRegion == 'us-west-1'"
- - "result.after.jsonData.tlsAuth == false"
- - "result.after.jsonData.tlsAuthWithCACert == false"
- - "result.after.name == 'datasource-cloudwatch'"
- - "result.after.orgId == 1"
- - "result.after.password == ''"
- - "result.after.type == 'cloudwatch'"
- - "result.after.url == 'http://monitoring.us-west-1.amazonaws.com'"
- - "result.after.user == ''"
- - "result.after.withCredentials == false"
diff --git a/test/integration/targets/grafana_datasource/tasks/elastic.yml b/test/integration/targets/grafana_datasource/tasks/elastic.yml
deleted file mode 100644
index 471a2ece5b..0000000000
--- a/test/integration/targets/grafana_datasource/tasks/elastic.yml
+++ /dev/null
@@ -1,77 +0,0 @@
----
-
-- name: Create elasticsearch datasource
- grafana_datasource:
- name: "datasource-elastic"
- grafana_url: "http://127.0.0.1:3000"
- grafana_user: "admin"
- grafana_password: "admin"
- org_id: "1"
- ds_type: "elasticsearch"
- ds_url: "https://elastic.company.com:9200"
- database: "[logstash_]YYYY.MM.DD"
- basic_auth_user: "grafana"
- basic_auth_password: "******"
- time_field: "@timestamp"
- time_interval: "1m"
- interval: "Daily"
- es_version: 56
- max_concurrent_shard_requests: 42
- tls_ca_cert: "/etc/ssl/certs/ca.pem"
- register: result
-
-- debug:
- var: result
-
-- assert:
- that:
- - "result.changed == true"
- - "result.name == 'datasource-elastic'"
- - "result.msg == 'Datasource datasource-elastic created : Datasource added'"
-
-- name: Check elasticsearch datasource creation idempotency
- grafana_datasource:
- name: "datasource-elastic"
- grafana_url: "http://127.0.0.1:3000"
- grafana_user: "admin"
- grafana_password: "admin"
- org_id: "1"
- ds_type: "elasticsearch"
- ds_url: "https://elastic.company.com:9200"
- database: "[logstash_]YYYY.MM.DD"
- basic_auth_user: "grafana"
- basic_auth_password: "******"
- time_field: "@timestamp"
- time_interval: "1m"
- interval: "Daily"
- es_version: 56
- max_concurrent_shard_requests: 42
- tls_ca_cert: "/etc/ssl/certs/ca.pem"
- register: result
-
-- debug:
- var: result
-
-- assert:
- that:
- # Idempotency is not working currently
- # "result.changed == false"
- - "result.name == 'datasource-elastic'"
- - "result.after.basicAuth == true"
- - "result.after.basicAuthUser == 'grafana'"
- - "result.after.access == 'proxy'"
- - "result.after.database == '[logstash_]YYYY.MM.DD'"
- - "result.after.isDefault == false"
- - "result.after.jsonData.esVersion == 56"
- - "result.after.jsonData.interval == 'Daily'"
- - "result.after.jsonData.maxConcurrentShardRequests == 42"
- - "result.after.jsonData.timeField == '@timestamp'"
- - "result.after.jsonData.tlsAuth == false"
- - "result.after.jsonData.tlsAuthWithCACert == false"
- - "result.after.name == 'datasource-elastic'"
- - "result.after.orgId == 1"
- - "result.after.password == ''"
- - "result.after.type == 'elasticsearch'"
- - "result.after.url == 'https://elastic.company.com:9200'"
- - "result.after.user == ''"
- - "result.after.withCredentials == false"
diff --git a/test/integration/targets/grafana_datasource/tasks/influx.yml b/test/integration/targets/grafana_datasource/tasks/influx.yml
deleted file mode 100644
index 821ea07e18..0000000000
--- a/test/integration/targets/grafana_datasource/tasks/influx.yml
+++ /dev/null
@@ -1,61 +0,0 @@
----
-
-- name: Create influxdb datasource
- grafana_datasource:
- name: "datasource-influxdb"
- grafana_url: "http://127.0.0.1:3000"
- grafana_user: "admin"
- grafana_password: "admin"
- org_id: "1"
- ds_type: "influxdb"
- ds_url: "https://influx.company.com:8086"
- database: "telegraf"
- time_interval: ">10s"
- tls_ca_cert: "/etc/ssl/certs/ca.pem"
- register: result
-
-- debug:
- var: result
-
-- assert:
- that:
- - "result.changed == true"
- - "result.name == 'datasource-influxdb'"
- - "result.msg == 'Datasource datasource-influxdb created : Datasource added'"
-
-- name: Check influxdb datasource creation idempotency
- grafana_datasource:
- name: "datasource-influxdb"
- grafana_url: "http://127.0.0.1:3000"
- grafana_user: "admin"
- grafana_password: "admin"
- org_id: "1"
- ds_type: "influxdb"
- ds_url: "https://influx.company.com:8086"
- database: "telegraf"
- time_interval: ">10s"
- tls_ca_cert: "/etc/ssl/certs/ca.pem"
- register: result
-
-- debug:
- var: result
-
-- assert:
- that:
- # Idempotency is not working currently
- # "result.changed == false"
- - "result.name == 'datasource-influxdb'"
- - "result.after.basicAuth == false"
- - "result.after.access == 'proxy'"
- - "result.after.database == 'telegraf'"
- - "result.after.isDefault == false"
- - "result.after.jsonData.timeInterval == '>10s'"
- - "result.after.jsonData.tlsAuth == false"
- - "result.after.jsonData.tlsAuthWithCACert == false"
- - "result.after.name == 'datasource-influxdb'"
- - "result.after.orgId == 1"
- - "result.after.password == ''"
- - "result.after.type == 'influxdb'"
- - "result.after.url == 'https://influx.company.com:8086'"
- - "result.after.user == ''"
- - "result.after.withCredentials == false"
diff --git a/test/integration/targets/grafana_datasource/tasks/main.yml b/test/integration/targets/grafana_datasource/tasks/main.yml
deleted file mode 100644
index 73a1f60f05..0000000000
--- a/test/integration/targets/grafana_datasource/tasks/main.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-- block:
- - include: elastic.yml
- - include: influx.yml
- - include: postgres.yml
- - include: cloudwatch.yml
- when:
- - ansible_distribution == 'Ubuntu'
- - ansible_distribution_release != 'trusty'
diff --git a/test/integration/targets/grafana_datasource/tasks/postgres.yml b/test/integration/targets/grafana_datasource/tasks/postgres.yml
deleted file mode 100644
index e540515e07..0000000000
--- a/test/integration/targets/grafana_datasource/tasks/postgres.yml
+++ /dev/null
@@ -1,61 +0,0 @@
----
-
-- name: Create postgres datasource
- grafana_datasource:
- name: "datasource-postgres"
- grafana_url: "http://127.0.0.1:3000"
- grafana_user: "admin"
- grafana_password: "admin"
- org_id: "1"
- ds_type: "postgres"
- ds_url: "postgres.company.com:5432"
- database: "db"
- user: "postgres"
- password: "iampgroot"
- sslmode: "verify-full"
- register: result
-
-- debug:
- var: result
-
-- assert:
- that:
- - "result.changed == true"
- - "result.name == 'datasource-postgres'"
- - "result.msg == 'Datasource datasource-postgres created : Datasource added'"
-
-- name: Check postgres datasource creation idempotency
- grafana_datasource:
- name: "datasource-postgres"
- grafana_url: "http://127.0.0.1:3000"
- grafana_user: "admin"
- grafana_password: "admin"
- org_id: "1"
- ds_type: "postgres"
- ds_url: "postgres.company.com:5432"
- database: "db"
- user: "postgres"
- password: "iampgroot"
- sslmode: "verify-full"
- register: result
-
-- debug:
- var: result
-
-- assert:
- that:
- # Idempotency is not working currently
- # "result.changed == false"
- - "result.name == 'datasource-postgres'"
- - "result.after.basicAuth == false"
- - "result.after.database == 'db'"
- - "result.after.isDefault == false"
- - "result.after.jsonData.sslmode == 'verify-full'"
- - "result.after.jsonData.tlsAuth == false"
- - "result.after.jsonData.tlsAuthWithCACert == false"
- - "result.after.name == 'datasource-postgres'"
- - "result.after.orgId == 1"
- - "result.after.type == 'postgres'"
- - "result.after.url == 'postgres.company.com:5432'"
- - "result.after.user == 'postgres'"
- - "result.after.withCredentials == false"
diff --git a/test/sanity/ignore.txt b/test/sanity/ignore.txt
index a912e1f554..c403c13468 100644
--- a/test/sanity/ignore.txt
+++ b/test/sanity/ignore.txt
@@ -1740,17 +1740,6 @@ lib/ansible/modules/files/synchronize.py validate-modules:undocumented-parameter
lib/ansible/modules/files/unarchive.py validate-modules:nonexistent-parameter-documented
lib/ansible/modules/files/unarchive.py validate-modules:parameter-list-no-elements
lib/ansible/modules/identity/cyberark/cyberark_authentication.py validate-modules:parameter-type-not-in-doc
-lib/ansible/modules/monitoring/grafana/grafana_dashboard.py validate-modules:doc-missing-type
-lib/ansible/modules/monitoring/grafana/grafana_dashboard.py validate-modules:doc-required-mismatch
-lib/ansible/modules/monitoring/grafana/grafana_dashboard.py validate-modules:invalid-argument-name
-lib/ansible/modules/monitoring/grafana/grafana_dashboard.py validate-modules:mutually_exclusive-unknown
-lib/ansible/modules/monitoring/grafana/grafana_dashboard.py validate-modules:parameter-type-not-in-doc
-lib/ansible/modules/monitoring/grafana/grafana_datasource.py validate-modules:doc-default-does-not-match-spec
-lib/ansible/modules/monitoring/grafana/grafana_datasource.py validate-modules:doc-missing-type
-lib/ansible/modules/monitoring/grafana/grafana_datasource.py validate-modules:doc-required-mismatch
-lib/ansible/modules/monitoring/grafana/grafana_datasource.py validate-modules:parameter-type-not-in-doc
-lib/ansible/modules/monitoring/grafana/grafana_plugin.py validate-modules:doc-missing-type
-lib/ansible/modules/monitoring/grafana/grafana_plugin.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/net_tools/basics/get_url.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/net_tools/basics/uri.py pylint:blacklisted-name
lib/ansible/modules/net_tools/basics/uri.py validate-modules:doc-required-mismatch