summaryrefslogtreecommitdiffstats
path: root/ansible/library/rancher1_api.py
diff options
context:
space:
mode:
Diffstat (limited to 'ansible/library/rancher1_api.py')
-rw-r--r--ansible/library/rancher1_api.py300
1 files changed, 204 insertions, 96 deletions
diff --git a/ansible/library/rancher1_api.py b/ansible/library/rancher1_api.py
index ce3df1b8..006de9ce 100644
--- a/ansible/library/rancher1_api.py
+++ b/ansible/library/rancher1_api.py
@@ -12,8 +12,16 @@ module: rancher1_api
short_description: Client library for rancher API
description:
- This module modifies a rancher 1.6 using it's API (v1).
- - WIP, as of now it can only change a current value to a new one.
-
+ - It supports some rancher features by the virtue of a 'mode'.
+ - 'modes' hide from you some necessary cruft and expose you to the only
+ important and interestig variables wich must be set. The mode mechanism
+ makes this module more easy to use and you don't have to create an
+ unnecessary boilerplate for the API.
+ - Only a few modes are/will be implemented so far - as they are/will be
+ needed. In the future the 'raw' mode can be added to enable you to craft
+ your own API requests, but that would be on the same level of a user
+ experience as running curl commands, and because the rancher 1.6 is already
+ obsoleted by the project, it would be a wasted effort.
options:
rancher:
description:
@@ -23,29 +31,44 @@ options:
required: true
aliases:
- server
- - rancher_url
+ - rancher_server
- rancher_api
- api
- - url
- category:
+ account_key:
description:
- - The path in JSON API without the last element.
+ - The public and secret part of the API key-pair separated by colon.
+ - You can find all your keys in web UI.
+ - For example:
+ B1716C4133D3825051CB:3P2eb3QhokFKYUiXRNZLxvGNSRYgh6LHjuMicCHQ
required: false
- default: settings
- aliases:
- - rancher_category
- - api_category
- option:
+ mode:
description:
- - The name of the settings option.
+ - A recognized mode how to deal with some concrete configuration task
+ in rancher API to ease the usage.
+ - The implemented modes so far are:
+ 'settings':
+ Many options under <api_server>/v1/settings API url and some can
+ be seen also under advanced options in the web UI.
+ 'access_control':
+ It setups user and password for the account (defaults to 'admin')
+ and it enables the local authentication - so the web UI and API
+ will require username/password (UI) or apikey (API).
required: true
aliases:
- - name
- - key
+ - rancher_mode
+ - api_mode
+ choices:
- settings
- value:
+ - access_control
+ data:
description:
- - A new value to replace the current one.
+ - Dictionary with key/value pairs. The actual names and meaning of pairs
+ depends on the used mode.
+ - 'settings' mode:
+ option: Option/path in JSON API (url).
+ value: A new value to replace the current one.
+ - 'access_control' mode:
+ None - not yet implemented - placeholder only.
required: true
timeout:
description:
@@ -54,6 +77,12 @@ options:
default: 10.0
"""
+default_timeout = 10.0
+
+
+class ModeError(Exception):
+ pass
+
def _decorate_rancher_api_request(request_method):
@@ -76,7 +105,7 @@ def _decorate_rancher_api_request(request_method):
@_decorate_rancher_api_request
-def get_rancher_api_value(url, headers=None, timeout=10.0,
+def get_rancher_api_value(url, headers=None, timeout=default_timeout,
username=None, password=None):
if username and password:
@@ -91,7 +120,7 @@ def get_rancher_api_value(url, headers=None, timeout=10.0,
@_decorate_rancher_api_request
-def set_rancher_api_value(url, payload, headers=None, timeout=10.0,
+def set_rancher_api_value(url, payload, headers=None, timeout=default_timeout,
username=None, password=None):
if username and password:
@@ -107,106 +136,114 @@ def set_rancher_api_value(url, payload, headers=None, timeout=10.0,
data=json.dumps(payload))
-def create_rancher_api_payload(json_data, new_value):
+def create_rancher_api_url(server, mode, option):
+ request_url = server.strip('/') + '/v1/'
- payload = {}
+ if mode == 'raw':
+ request_url += option.strip('/')
+ elif mode == 'settings':
+ request_url += 'settings/' + option.strip('/')
+ elif mode == 'access_control':
+ request_url += option.strip('/')
- try:
- api_id = json_data['id']
- api_activeValue = json_data['activeValue']
- api_name = json_data['name']
- api_source = json_data['source']
- except Exception:
- raise ValueError
-
- payload.update({"activeValue": api_activeValue,
- "id": api_id,
- "name": api_name,
- "source": api_source,
- "value": new_value})
-
- if api_activeValue != new_value:
- differs = True
- else:
- differs = False
+ return request_url
- return differs, payload
+def get_keypair(keypair):
+ if keypair:
+ keypair = keypair.split(':')
+ if len(keypair) == 2:
+ return keypair[0], keypair[1]
-def is_valid_rancher_api_option(json_data):
+ return None, None
- try:
- api_activeValue = json_data['activeValue']
- api_source = json_data['source']
- except Exception:
- return False
- if api_activeValue is None and api_source is None:
- return False
+def mode_settings(api_url, data=None, headers=None, timeout=default_timeout,
+ access_key=None, secret_key=None, dry_run=False):
- return True
+ def is_valid_rancher_api_option(json_data):
+ try:
+ api_activeValue = json_data['activeValue']
+ api_source = json_data['source']
+ except Exception:
+ return False
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- rancher=dict(type='str', required=True,
- aliases=['server',
- 'rancher_api',
- 'rancher_url',
- 'api',
- 'url']),
- category=dict(type='str', default='settings',
- aliases=['rancher_category', 'api_category']),
- option=dict(type='str', required=True,
- aliases=['name', 'key', 'settings']),
- value=dict(type='str', required=True),
- timeout=dict(type='float', default=10.0),
- ),
- supports_check_mode=True
- )
+ if api_activeValue is None and api_source is None:
+ return False
- rancher_url = module.params['rancher'].strip('/')
- rancher_option = module.params['option'].strip('/')
- rancher_category = module.params['category']
- rancher_value = module.params['value']
- rancher_timeout = module.params['timeout']
- # cattle_access_key = ''
- # cattle_secret_key = ''
+ return True
- # Assemble API url
- request_url = rancher_url + '/v1/' + rancher_category + '/' \
- + rancher_option
+ def create_rancher_api_payload(json_data, new_value):
- http_headers = {'Content-Type': 'application/json',
- 'Accept': 'application/json'}
+ payload = {}
+ differs = False
+
+ try:
+ api_id = json_data['id']
+ api_activeValue = json_data['activeValue']
+ api_name = json_data['name']
+ api_source = json_data['source']
+ except Exception:
+ raise ValueError
+
+ payload.update({"activeValue": api_activeValue,
+ "id": api_id,
+ "name": api_name,
+ "source": api_source,
+ "value": new_value})
+
+ if api_activeValue != new_value:
+ differs = True
+
+ return differs, payload
+
+ # check if data contains all required fields
+ try:
+ if not isinstance(data['option'], str) or data['option'] == '':
+ raise ModeError("ERROR: 'option' must contain a name of the \
+ option")
+ except KeyError:
+ raise ModeError("ERROR: Mode 'settings' requires the field: 'option': \
+ %s" % str(data))
+ try:
+ if not isinstance(data['value'], str) or data['value'] == '':
+ raise ModeError("ERROR: 'value' must contain a value")
+ except KeyError:
+ raise ModeError("ERROR: Mode 'settings' requires the field: 'value': \
+ %s" % str(data))
+
+ # assemble request URL
+ request_url = api_url + 'settings/' + data['option'].strip('/')
# API get current value
try:
json_response = get_rancher_api_value(request_url,
- headers=http_headers,
- timeout=rancher_timeout)
+ username=access_key,
+ password=secret_key,
+ headers=headers,
+ timeout=timeout)
except requests.HTTPError as e:
- module.fail_json(msg=str(e))
+ raise ModeError(str(e))
except requests.Timeout as e:
- module.fail_json(msg=str(e))
+ raise ModeError(str(e))
if not json_response:
- module.fail_json(msg='ERROR: BAD RESPONSE (GET) - no json value \
- in the response')
+ raise ModeError('ERROR: BAD RESPONSE (GET) - no json value in the \
+ response')
if is_valid_rancher_api_option(json_response):
valid = True
try:
differs, payload = create_rancher_api_payload(json_response,
- rancher_value)
+ data['value'])
except ValueError:
- module.fail_json(msg='ERROR: INVALID JSON - missing json values \
- in the response')
+ raise ModeError('ERROR: INVALID JSON - missing json values in \
+ the response')
else:
valid = False
- if valid and differs and module.check_mode:
+ if valid and differs and dry_run:
# ansible dry-run mode
changed = True
elif valid and differs:
@@ -214,16 +251,18 @@ def main():
try:
json_response = set_rancher_api_value(request_url,
payload,
- headers=http_headers,
- timeout=rancher_timeout)
+ username=access_key,
+ password=secret_key,
+ headers=headers,
+ timeout=timeout)
except requests.HTTPError as e:
- module.fail_json(msg=str(e))
+ raise ModeError(str(e))
except requests.Timeout as e:
- module.fail_json(msg=str(e))
+ raise ModeError(str(e))
if not json_response:
- module.fail_json(msg='ERROR: BAD RESPONSE (PUT) - no json value \
- in the response')
+ raise ModeError('ERROR: BAD RESPONSE (PUT) - no json value in \
+ the response')
else:
changed = True
else:
@@ -231,9 +270,78 @@ def main():
if changed:
msg = "Option '%s' is now set to the new value: %s" \
- % (rancher_option, rancher_value)
+ % (data['option'], data['value'])
else:
- msg = "Option '%s' is unchanged." % (rancher_option)
+ msg = "Option '%s' is unchanged." % (data['option'])
+
+ return changed, msg
+
+
+def mode_handler(server, rancher_mode, data=None, timeout=default_timeout,
+ account_key=None, dry_run=False):
+
+ changed = False
+ msg = 'UNKNOWN: UNAPPLICABLE MODE'
+
+ # check API key-pair
+ if account_key:
+ access_key, secret_key = get_keypair(account_key)
+ if not (access_key and secret_key):
+ raise ModeError('ERROR: INVALID API KEY-PAIR')
+
+ # all requests share these headers
+ http_headers = {'Content-Type': 'application/json',
+ 'Accept': 'application/json'}
+
+ # assemble API url
+ api_url = server.strip('/') + '/v1/'
+
+ if rancher_mode == 'settings':
+ changed, msg = mode_settings(api_url, data=data,
+ headers=http_headers,
+ timeout=timeout,
+ access_key=access_key,
+ secret_key=secret_key,
+ dry_run=dry_run)
+ elif rancher_mode == 'access_control':
+ msg = "SKIP: 'access_control' Not yet implemented"
+
+ return changed, msg
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ rancher=dict(type='str', required=True,
+ aliases=['server',
+ 'rancher_api',
+ 'rancher_server',
+ 'api']),
+ account_key=dict(type='str', required=False),
+ mode=dict(required=True,
+ choices=['settings', 'access_control'],
+ aliases=['api_mode']),
+ data=dict(type='dict', required=True),
+ timeout=dict(type='float', default=default_timeout),
+ ),
+ supports_check_mode=True
+ )
+
+ rancher_server = module.params['rancher']
+ rancher_account_key = module.params['account_key']
+ rancher_mode = module.params['mode']
+ rancher_data = module.params['data']
+ rancher_timeout = module.params['timeout']
+
+ try:
+ changed, msg = mode_handler(rancher_server,
+ rancher_mode,
+ data=rancher_data,
+ account_key=rancher_account_key,
+ timeout=rancher_timeout,
+ dry_run=module.check_mode)
+ except ModeError as e:
+ module.fail_json(msg=str(e))
module.exit_json(changed=changed, msg=msg)