mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
vultr: new module utils and common docs (#30868)
* vultr: new module utils and common docs * vultr: minor fixes after review
This commit is contained in:
parent
869cf3fbdb
commit
c098c42ab9
3 changed files with 259 additions and 0 deletions
220
lib/ansible/module_utils/vultr.py
Normal file
220
lib/ansible/module_utils/vultr.py
Normal file
|
@ -0,0 +1,220 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# (c) 2017, René Moser <mail@renemoser.net>
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
import os
|
||||
import time
|
||||
import urllib
|
||||
from ansible.module_utils.six.moves import configparser
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils.urls import fetch_url
|
||||
|
||||
|
||||
VULTR_API_ENDPOINT = "https://api.vultr.com"
|
||||
|
||||
|
||||
def vultr_argument_spec():
|
||||
return dict(
|
||||
api_key=dict(default=os.environ.get('VULTR_API_KEY'), no_log=True),
|
||||
api_timeout=dict(type='int', default=os.environ.get('VULTR_API_TIMEOUT') or 60),
|
||||
api_retries=dict(type='int', default=os.environ.get('VULTR_API_RETRIES') or 5),
|
||||
api_account=dict(default=os.environ.get('VULTR_API_ACCOUNT') or 'default'),
|
||||
validate_certs=dict(default=True, type='bool'),
|
||||
)
|
||||
|
||||
|
||||
class Vultr:
|
||||
|
||||
def __init__(self, module, namespace):
|
||||
self.module = module
|
||||
|
||||
# Namespace use for returns
|
||||
self.namespace = namespace
|
||||
self.result = {
|
||||
'changed': False,
|
||||
namespace: dict(),
|
||||
'diff': dict(before=dict(), after=dict())
|
||||
}
|
||||
|
||||
# For caching HTTP API responses
|
||||
self.api_cache = dict()
|
||||
|
||||
# Reads the config from vultr.ini
|
||||
try:
|
||||
config = self.read_ini_config()
|
||||
except KeyError:
|
||||
config = {}
|
||||
|
||||
self.api_config = {
|
||||
'api_key': self.module.params.get('api_key') or config.get('key'),
|
||||
'api_timeout': self.module.params.get('api_timeout') or config.get('timeout'),
|
||||
'api_retries': self.module.params.get('api_retries') or config.get('retries'),
|
||||
}
|
||||
|
||||
# Common vultr returns
|
||||
self.result['vultr_api'] = {
|
||||
'api_account': self.module.params.get('api_account'),
|
||||
'api_timeout': self.api_config['api_timeout'],
|
||||
}
|
||||
|
||||
# Headers to be passed to the API
|
||||
self.headers = {
|
||||
'API-Key': "%s" % self.api_config['api_key'],
|
||||
'User-Agent': "Ansible Vultr",
|
||||
'Accept': 'application/json',
|
||||
}
|
||||
|
||||
def read_ini_config(self):
|
||||
ini_group = self.module.params.get('api_account')
|
||||
|
||||
keys = ['key', 'timeout', 'retries']
|
||||
env_conf = {}
|
||||
for key in keys:
|
||||
if 'VULTR_API_%s' % key.upper() not in os.environ:
|
||||
break
|
||||
else:
|
||||
env_conf[key] = os.environ['VULTR_API_%s' % key.upper()]
|
||||
else:
|
||||
return env_conf
|
||||
|
||||
paths = (
|
||||
os.path.join(os.path.expanduser('~'), '.vultr.ini'),
|
||||
os.path.join(os.getcwd(), 'vultr.ini'),
|
||||
)
|
||||
if 'VULTR_API_CONFIG' in os.environ:
|
||||
paths += (os.path.expanduser(os.environ['VULTR_API_CONFIG']),)
|
||||
if not any((os.path.exists(c) for c in paths)):
|
||||
self.module.fail_json(msg="Config file not found. Tried : %s" % ", ".join(paths))
|
||||
|
||||
conf = configparser.ConfigParser()
|
||||
conf.read(paths)
|
||||
return dict(conf.items(ini_group))
|
||||
|
||||
def fail_json(self, **kwargs):
|
||||
self.result.update(kwargs)
|
||||
self.module.fail_json(**self.result)
|
||||
|
||||
def get_yes_or_no(self, key):
|
||||
if self.module.params.get(key) is not None:
|
||||
return 'yes' if self.module.params.get(key) is True else 'no'
|
||||
|
||||
def switch_enable_disable(self, resource, param_key, resource_key=None):
|
||||
if resource_key is None:
|
||||
resource_key = param_key
|
||||
|
||||
param = self.module.params.get(param_key)
|
||||
if param is None:
|
||||
return
|
||||
|
||||
r_value = resource.get(resource_key)
|
||||
if isinstance(param, bool):
|
||||
if param is True and r_value not in ['yes', 'enable']:
|
||||
return "enable"
|
||||
elif param is False and r_value not in ['no', 'disable']:
|
||||
return "disable"
|
||||
else:
|
||||
if r_value is None:
|
||||
return "enable"
|
||||
else:
|
||||
return "disable"
|
||||
|
||||
def api_query(self, path="/", method="GET", data=None):
|
||||
url = VULTR_API_ENDPOINT + path
|
||||
|
||||
if data:
|
||||
data_encoded = dict()
|
||||
for k, v in data.items():
|
||||
if v is not None:
|
||||
data_encoded[k] = v
|
||||
data = urllib.urlencode(data_encoded)
|
||||
|
||||
for s in range(0, self.api_config['api_retries']):
|
||||
response, info = fetch_url(
|
||||
module=self.module,
|
||||
url=url,
|
||||
data=data,
|
||||
method=method,
|
||||
headers=self.headers,
|
||||
timeout=self.api_config['api_timeout'],
|
||||
)
|
||||
|
||||
# Did we hit the rate limit?
|
||||
if info.get('status') and info.get('status') != 503:
|
||||
break
|
||||
|
||||
# Vultr has a rate limiting requests per second, try to be polite
|
||||
time.sleep(1)
|
||||
|
||||
else:
|
||||
self.fail_json(msg="Reached API retries limit %s for URL %s, method %s with data %s. Returned %s, with body: %s %s" % (
|
||||
self.api_config['api_retries'],
|
||||
url,
|
||||
method,
|
||||
data,
|
||||
info['status'],
|
||||
info['msg'],
|
||||
info.get('body')
|
||||
))
|
||||
|
||||
if info.get('status') != 200:
|
||||
self.fail_json(msg="URL %s, method %s with data %s. Returned %s, with body: %s %s" % (
|
||||
url,
|
||||
method,
|
||||
data,
|
||||
info['status'],
|
||||
info['msg'],
|
||||
info.get('body')
|
||||
))
|
||||
|
||||
res = response.read()
|
||||
if not res:
|
||||
return {}
|
||||
|
||||
try:
|
||||
return self.module.from_json(to_text(res))
|
||||
except ValueError as e:
|
||||
self.module.fail_json(msg="Could not process response into json: %s" % e)
|
||||
|
||||
def query_resource_by_key(self, key, value, resource='regions', query_by='list', params=None, use_cache=False):
|
||||
if not value:
|
||||
return {}
|
||||
|
||||
if use_cache:
|
||||
if resource in self.api_cache:
|
||||
if self.api_cache[resource] and self.api_cache[resource].get(key) == value:
|
||||
return self.api_cache[resource]
|
||||
|
||||
r_list = self.api_query(path="/v1/%s/%s" % (resource, query_by), data=params)
|
||||
|
||||
if not r_list:
|
||||
return {}
|
||||
|
||||
for r_id, r_data in r_list.items():
|
||||
if r_data[key] == value:
|
||||
self.api_cache.update({
|
||||
resource: r_data
|
||||
})
|
||||
return r_data
|
||||
|
||||
self.module.fail_json(msg="Could not find %s %s: %s" % (resource, key, value))
|
||||
|
||||
def get_result(self, resource):
|
||||
if resource:
|
||||
for search_key, config in self.returns.items():
|
||||
if search_key in resource:
|
||||
if 'convert_to' in config:
|
||||
if config['convert_to'] == 'int':
|
||||
resource[search_key] = int(resource[search_key])
|
||||
elif config['convert_to'] == 'float':
|
||||
resource[search_key] = float(resource[search_key])
|
||||
elif config['convert_to'] == 'bool':
|
||||
resource[search_key] = True if resource[search_key] == 'yes' else False
|
||||
|
||||
if 'key' in config:
|
||||
self.result[self.namespace][config['key']] = resource[search_key]
|
||||
else:
|
||||
self.result[self.namespace][search_key] = resource[search_key]
|
||||
return self.result
|
0
lib/ansible/modules/cloud/vultr/__init__.py
Normal file
0
lib/ansible/modules/cloud/vultr/__init__.py
Normal file
39
lib/ansible/utils/module_docs_fragments/vultr.py
Normal file
39
lib/ansible/utils/module_docs_fragments/vultr.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017 René Moser <mail@renemoser.net>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
|
||||
class ModuleDocFragment(object):
|
||||
|
||||
# Standard documentation fragment
|
||||
DOCUMENTATION = '''
|
||||
options:
|
||||
api_key:
|
||||
description:
|
||||
- API key of the Vultr API.
|
||||
- The ENV variable C(VULTR_API_KEY) is used as default, when defined.
|
||||
api_timeout:
|
||||
description:
|
||||
- HTTP timeout to Vultr API.
|
||||
- The ENV variable C(VULTR_API_TIMEOUT) is used as default, when defined.
|
||||
default: 10
|
||||
api_retries:
|
||||
description:
|
||||
- Amount of retries in case of the Vultr API retuns an HTTP 503 code.
|
||||
- The ENV variable C(VULTR_API_RETRIES) is used as default, when defined.
|
||||
default: 10
|
||||
api_account:
|
||||
description:
|
||||
- Name of the ini section in the C(vultr.ini) file.
|
||||
- The ENV variable C(VULTR_API_ACCOUNT) is used as default, when defined.
|
||||
default: default
|
||||
validate_certs:
|
||||
description:
|
||||
- Validate SSL certs of the Vultr API.
|
||||
default: true
|
||||
type: bool
|
||||
requirements:
|
||||
- "python >= 2.6"
|
||||
notes:
|
||||
- Also see the API documentation on https://www.vultr.com/api/.
|
||||
'''
|
Loading…
Reference in a new issue