Grafana datasource module : Use url_argument_spec from urls (#40402)

* Added client_cert and client_key modules parem

* Use url_argument_spec to init module arguments

* Do not compare version and readOnly

* Convert HTTPResponse content to text before json.loads

* Added password in secureJsonPayload when datasource type is postgres
pull/45445/head
Seuf 6 years ago committed by Sam Doran
parent 0015d4cef3
commit 69bbd32264

@ -39,19 +39,24 @@ options:
description: description:
- The URL of the datasource. - The URL of the datasource.
required: true required: true
aliases: [ ds_url ]
access: access:
description: description:
- The access mode for this datasource. - The access mode for this datasource.
choices: [ direct, proxy ] choices: [ direct, proxy ]
default: proxy default: proxy
grafana_user: url_username:
description: description:
- The Grafana API user. - The Grafana API user.
default: admin default: admin
grafana_password: aliases: [ grafana_user ]
version_added: 2.7
url_password:
description: description:
- The Grafana API password. - The Grafana API password.
default: admin default: admin
aliases: [ grafana_password ]
version_added: 2.7
grafana_api_key: grafana_api_key:
description: description:
- The Grafana API key. - The Grafana API key.
@ -157,11 +162,27 @@ options:
- Use trends or not for zabbix datasource type - Use trends or not for zabbix datasource type
type: bool type: bool
version_added: 2.6 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: validate_certs:
description: description:
- Whether to validate the Grafana certificate. - Whether to validate the Grafana certificate.
type: bool type: bool
default: 'yes' default: 'yes'
use_proxy:
description:
- Boolean of whether or not to use proxy.
default: 'yes'
type: bool
version_added: 2.8
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -174,7 +195,7 @@ EXAMPLES = '''
grafana_password: "xxxxxx" grafana_password: "xxxxxx"
org_id: "1" org_id: "1"
ds_type: "elasticisearch" ds_type: "elasticisearch"
url: "https://elastic.company.com:9200" ds_url: "https://elastic.company.com:9200"
database: "[logstash_]YYYY.MM.DD" database: "[logstash_]YYYY.MM.DD"
basic_auth_user: "grafana" basic_auth_user: "grafana"
basic_auth_password: "******" basic_auth_password: "******"
@ -193,7 +214,7 @@ EXAMPLES = '''
grafana_password: "xxxxxx" grafana_password: "xxxxxx"
org_id: "1" org_id: "1"
ds_type: "influxdb" ds_type: "influxdb"
url: "https://influx.company.com:8086" ds_url: "https://influx.company.com:8086"
database: "telegraf" database: "telegraf"
time_interval: ">10s" time_interval: ">10s"
tls_ca_cert: "/etc/ssl/certs/ca.pem" tls_ca_cert: "/etc/ssl/certs/ca.pem"
@ -259,8 +280,8 @@ import json
import base64 import base64
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url from ansible.module_utils.urls import fetch_url, url_argument_spec
from ansible.module_utils._text import to_bytes from ansible.module_utils._text import to_text
__metaclass__ = type __metaclass__ = type
@ -275,13 +296,24 @@ def grafana_switch_organisation(module, grafana_url, org_id, headers):
raise GrafanaAPIException('Unable to switch to organization %s : %s' % (org_id, info)) 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): def grafana_datasource_exists(module, grafana_url, name, headers):
datasource_exists = False datasource_exists = False
ds = {} ds = {}
r, info = fetch_url(module, '%s/api/datasources/name/%s' % (grafana_url, name), headers=headers, method='GET') r, info = fetch_url(module, '%s/api/datasources/name/%s' % (grafana_url, name), headers=headers, method='GET')
if info['status'] == 200: if info['status'] == 200:
datasource_exists = True datasource_exists = True
ds = json.loads(r.read()) ds = json.loads(to_text(r.read(), errors='surrogate_or_strict'))
elif info['status'] == 404: elif info['status'] == 404:
datasource_exists = False datasource_exists = False
else: else:
@ -361,6 +393,8 @@ def grafana_create_datasource(module, data):
if data['ds_type'] == 'postgres': if data['ds_type'] == 'postgres':
json_data['sslmode'] = data['sslmode'] json_data['sslmode'] = data['sslmode']
if data.get('password'):
payload['secureJsonData'] = {'password': data.get('password')}
if data['ds_type'] == 'alexanderzobnin-zabbix-datasource': if data['ds_type'] == 'alexanderzobnin-zabbix-datasource':
if data.get('trends'): if data.get('trends'):
@ -369,13 +403,7 @@ def grafana_create_datasource(module, data):
payload['jsonData'] = json_data payload['jsonData'] = json_data
# define http header # define http header
headers = {'content-type': 'application/json; charset=utf8'} headers = grafana_headers(module, data)
if 'grafana_api_key' in data and data['grafana_api_key'] is not None:
headers['Authorization'] = "Bearer %s" % data['grafana_api_key']
else:
auth = base64.b64encode(to_bytes('%s:%s' % (data['grafana_user'], data['grafana_password'])).replace('\n', ''))
headers['Authorization'] = 'Basic %s' % auth
grafana_switch_organisation(module, data['grafana_url'], data['org_id'], headers)
# test if datasource already exists # test if datasource already exists
datasource_exists, ds = grafana_datasource_exists(module, data['grafana_url'], data['name'], headers=headers) datasource_exists, ds = grafana_datasource_exists(module, data['grafana_url'], data['name'], headers=headers)
@ -383,6 +411,10 @@ def grafana_create_datasource(module, data):
result = {} result = {}
if datasource_exists is True: if datasource_exists is True:
del ds['typeLogoUrl'] del ds['typeLogoUrl']
if ds.get('version'):
del ds['version']
if ds.get('readOnly'):
del ds['readOnly']
if ds['basicAuth'] is False: if ds['basicAuth'] is False:
del ds['basicAuthUser'] del ds['basicAuthUser']
del ds['basicAuthPassword'] del ds['basicAuthPassword']
@ -402,7 +434,7 @@ def grafana_create_datasource(module, data):
# update # update
r, info = fetch_url(module, '%s/api/datasources/%d' % (data['grafana_url'], ds['id']), data=json.dumps(payload), headers=headers, method='PUT') 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: if info['status'] == 200:
res = json.loads(r.read()) res = json.loads(to_text(r.read(), errors='surrogate_or_strict'))
result['name'] = data['name'] result['name'] = data['name']
result['id'] = ds['id'] result['id'] = ds['id']
result['before'] = ds result['before'] = ds
@ -415,7 +447,7 @@ def grafana_create_datasource(module, data):
# create # create
r, info = fetch_url(module, '%s/api/datasources' % data['grafana_url'], data=json.dumps(payload), headers=headers, method='POST') r, info = fetch_url(module, '%s/api/datasources' % data['grafana_url'], data=json.dumps(payload), headers=headers, method='POST')
if info['status'] == 200: if info['status'] == 200:
res = json.loads(r.read()) res = json.loads(to_text(r.read(), errors='surrogate_or_strict'))
result['msg'] = "Datasource %s created : %s" % (data['name'], res['message']) result['msg'] = "Datasource %s created : %s" % (data['name'], res['message'])
result['changed'] = True result['changed'] = True
result['name'] = data['name'] result['name'] = data['name']
@ -428,14 +460,7 @@ def grafana_create_datasource(module, data):
def grafana_delete_datasource(module, data): def grafana_delete_datasource(module, data):
# define http headers headers = grafana_headers(module, data)
headers = {'content-type': 'application/json'}
if 'grafana_api_key' in data and data['grafana_api_key']:
headers['Authorization'] = "Bearer %s" % data['grafana_api_key']
else:
auth = base64.b64encode(to_bytes('%s:%s' % (data['grafana_user'], data['grafana_password'])).replace('\n', ''))
headers['Authorization'] = 'Basic %s' % auth
grafana_switch_organisation(module, data['grafana_url'], data['org_id'], headers)
# test if datasource already exists # test if datasource already exists
datasource_exists, ds = grafana_datasource_exists(module, data['grafana_url'], data['name'], headers=headers) datasource_exists, ds = grafana_datasource_exists(module, data['grafana_url'], data['name'], headers=headers)
@ -445,7 +470,7 @@ def grafana_delete_datasource(module, data):
# delete # delete
r, info = fetch_url(module, '%s/api/datasources/name/%s' % (data['grafana_url'], data['name']), headers=headers, method='DELETE') r, info = fetch_url(module, '%s/api/datasources/name/%s' % (data['grafana_url'], data['name']), headers=headers, method='DELETE')
if info['status'] == 200: if info['status'] == 200:
res = json.loads(r.read()) res = json.loads(to_text(r.read(), errors='surrogate_or_strict'))
result['msg'] = "Datasource %s deleted : %s" % (data['name'], res['message']) result['msg'] = "Datasource %s deleted : %s" % (data['name'], res['message'])
result['changed'] = True result['changed'] = True
result['name'] = data['name'] result['name'] = data['name']
@ -463,12 +488,20 @@ def grafana_delete_datasource(module, data):
def main(): def main():
module = AnsibleModule( # use the predefined argument spec for url
argument_spec=dict( 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'), name=dict(required=True, type='str'),
state=dict(choices=['present', 'absent'], state=dict(choices=['present', 'absent'],
default='present'), default='present'),
grafana_url=dict(required=True, type='str'), 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', ds_type=dict(choices=['graphite',
'prometheus', 'prometheus',
'elasticsearch', 'elasticsearch',
@ -477,10 +510,8 @@ def main():
'mysql', 'mysql',
'postgres', 'postgres',
'alexanderzobnin-zabbix-datasource']), 'alexanderzobnin-zabbix-datasource']),
url=dict(required=True, type='str'), url=dict(required=True, type='str', aliases=['ds_url']),
access=dict(default='proxy', choices=['proxy', 'direct']), access=dict(default='proxy', choices=['proxy', 'direct']),
grafana_user=dict(default='admin'),
grafana_password=dict(default='admin', no_log=True),
grafana_api_key=dict(type='str', no_log=True), grafana_api_key=dict(type='str', no_log=True),
database=dict(type='str'), database=dict(type='str'),
user=dict(default='', type='str'), user=dict(default='', type='str'),
@ -503,11 +534,13 @@ def main():
tsdb_resolution=dict(type='str', default='second', choices=['second', 'millisecond']), tsdb_resolution=dict(type='str', default='second', choices=['second', 'millisecond']),
sslmode=dict(default='disable', choices=['disable', 'require', 'verify-ca', 'verify-full']), sslmode=dict(default='disable', choices=['disable', 'require', 'verify-ca', 'verify-full']),
trends=dict(default=False, type='bool'), trends=dict(default=False, type='bool'),
validate_certs=dict(type='bool', default=True) )
),
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=False, supports_check_mode=False,
required_together=[['grafana_user', 'grafana_password', 'org_id'], ['tls_client_cert', 'tls_client_key']], required_together=[['url_username', 'url_password', 'org_id'], ['tls_client_cert', 'tls_client_key']],
mutually_exclusive=[['grafana_user', 'grafana_api_key'], ['tls_ca_cert', 'tls_skip_verify']], mutually_exclusive=[['url_username', 'grafana_api_key'], ['tls_ca_cert', 'tls_skip_verify']],
required_if=[ required_if=[
['ds_type', 'opentsdb', ['tsdb_version', 'tsdb_resolution']], ['ds_type', 'opentsdb', ['tsdb_version', 'tsdb_resolution']],
['ds_type', 'influxdb', ['database']], ['ds_type', 'influxdb', ['database']],

Loading…
Cancel
Save