Vultr: Introduce the Vultr inventory plugin (#44400)
This commit introduce the Vultr inventory plugin.
This commit is contained in:
parent
07375be490
commit
72d4880b85
2 changed files with 165 additions and 12 deletions
|
@ -14,6 +14,7 @@ from ansible.module_utils.urls import fetch_url
|
|||
|
||||
|
||||
VULTR_API_ENDPOINT = "https://api.vultr.com"
|
||||
VULTR_USER_AGENT = 'Ansible Vultr'
|
||||
|
||||
|
||||
def vultr_argument_spec():
|
||||
|
@ -49,7 +50,7 @@ class Vultr:
|
|||
|
||||
try:
|
||||
config = self.read_env_variables()
|
||||
config.update(self.read_ini_config())
|
||||
config.update(Vultr.read_ini_config(self.module.params.get('api_account')))
|
||||
except KeyError:
|
||||
config = {}
|
||||
|
||||
|
@ -79,7 +80,7 @@ class Vultr:
|
|||
# Headers to be passed to the API
|
||||
self.headers = {
|
||||
'API-Key': "%s" % self.api_config['api_key'],
|
||||
'User-Agent': "Ansible Vultr",
|
||||
'User-Agent': VULTR_USER_AGENT,
|
||||
'Accept': 'application/json',
|
||||
}
|
||||
|
||||
|
@ -93,9 +94,8 @@ class Vultr:
|
|||
|
||||
return env_conf
|
||||
|
||||
def read_ini_config(self):
|
||||
ini_group = self.module.params.get('api_account')
|
||||
|
||||
@staticmethod
|
||||
def read_ini_config(ini_group):
|
||||
paths = (
|
||||
os.path.join(os.path.expanduser('~'), '.vultr.ini'),
|
||||
os.path.join(os.getcwd(), 'vultr.ini'),
|
||||
|
@ -236,12 +236,14 @@ class Vultr:
|
|||
|
||||
self.module.fail_json(msg="Could not find %s with %s: %s" % (resource, key, value))
|
||||
|
||||
def normalize_result(self, resource):
|
||||
fields_to_remove = set(resource.keys()) - set(self.returns.keys())
|
||||
@staticmethod
|
||||
def normalize_result(resource, schema, remove_missing_keys=True):
|
||||
if remove_missing_keys:
|
||||
fields_to_remove = set(resource.keys()) - set(schema.keys())
|
||||
for field in fields_to_remove:
|
||||
resource.pop(field)
|
||||
|
||||
for search_key, config in self.returns.items():
|
||||
for search_key, config in schema.items():
|
||||
if search_key in resource:
|
||||
if 'convert_to' in config:
|
||||
if config['convert_to'] == 'int':
|
||||
|
@ -263,9 +265,9 @@ class Vultr:
|
|||
def get_result(self, resource):
|
||||
if resource:
|
||||
if isinstance(resource, list):
|
||||
self.result[self.namespace] = [self.normalize_result(item) for item in resource]
|
||||
self.result[self.namespace] = [Vultr.normalize_result(item, self.returns) for item in resource]
|
||||
else:
|
||||
self.result[self.namespace] = self.normalize_result(resource)
|
||||
self.result[self.namespace] = Vultr.normalize_result(resource, self.returns)
|
||||
|
||||
return self.result
|
||||
|
||||
|
|
151
lib/ansible/plugins/inventory/vultr.py
Normal file
151
lib/ansible/plugins/inventory/vultr.py
Normal file
|
@ -0,0 +1,151 @@
|
|||
# (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
|
||||
# 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
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
name: vultr
|
||||
plugin_type: inventory
|
||||
author:
|
||||
- "Yanis Guenane (@Spredzy)"
|
||||
short_description: Vultr inventory source
|
||||
description:
|
||||
- Get inventory hosts from Vultr public cloud.
|
||||
- Uses C(api_config), C(~/.vultr.ini), C(./vultr.ini) or VULTR_API_CONFIG path to config file.
|
||||
options:
|
||||
plugin:
|
||||
description: token that ensures this is a source file for the 'vultr' plugin.
|
||||
required: True
|
||||
choices: ['vultr']
|
||||
api_account:
|
||||
description: Specify the account to be used.
|
||||
default: default
|
||||
api_config:
|
||||
description: Path to the vultr configuration file. If not specified will be taken from regular Vultr configuration.
|
||||
env:
|
||||
- name: VULTR_API_CONFIG
|
||||
api_key:
|
||||
description: Vultr API key. If not specified will be taken from regular Vultr configuration.
|
||||
env:
|
||||
- name: VULTR_API_KEY
|
||||
hostname:
|
||||
description: Field to match the hostname
|
||||
type: string
|
||||
default: v4_main_ip
|
||||
choices:
|
||||
- v4_main_ip
|
||||
- v6_main_ip
|
||||
- name
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
# vultr_inventory.yml file in YAML format
|
||||
# Example command line: ansible-inventory --list -i vultr_inventory.yml
|
||||
|
||||
plugin: vultr
|
||||
'''
|
||||
|
||||
import json
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.plugins.inventory import BaseInventoryPlugin
|
||||
from ansible.module_utils.six.moves import configparser
|
||||
from ansible.module_utils.urls import open_url
|
||||
from ansible.module_utils._text import to_native
|
||||
from ansible.module_utils.vultr import Vultr, VULTR_USER_AGENT
|
||||
|
||||
|
||||
SCHEMA = {
|
||||
'SUBID': dict(key='id'),
|
||||
'label': dict(key='name'),
|
||||
'date_created': dict(),
|
||||
'allowed_bandwidth_gb': dict(convert_to='int'),
|
||||
'auto_backups': dict(key='auto_backup_enabled', convert_to='bool'),
|
||||
'current_bandwidth_gb': dict(),
|
||||
'kvm_url': dict(),
|
||||
'default_password': dict(),
|
||||
'internal_ip': dict(),
|
||||
'disk': dict(),
|
||||
'cost_per_month': dict(convert_to='float'),
|
||||
'location': dict(key='region'),
|
||||
'main_ip': dict(key='v4_main_ip'),
|
||||
'network_v4': dict(key='v4_network'),
|
||||
'gateway_v4': dict(key='v4_gateway'),
|
||||
'os': dict(),
|
||||
'pending_charges': dict(convert_to='float'),
|
||||
'power_status': dict(),
|
||||
'ram': dict(),
|
||||
'plan': dict(),
|
||||
'server_state': dict(),
|
||||
'status': dict(),
|
||||
'firewall_group': dict(),
|
||||
'tag': dict(),
|
||||
'v6_main_ip': dict(),
|
||||
'v6_network': dict(),
|
||||
'v6_network_size': dict(),
|
||||
'v6_networks': dict(),
|
||||
'vcpu_count': dict(convert_to='int'),
|
||||
}
|
||||
|
||||
|
||||
def _load_conf(path, account):
|
||||
|
||||
if path:
|
||||
conf = configparser.ConfigParser()
|
||||
conf.read(path)
|
||||
|
||||
if not conf._sections.get(account):
|
||||
return None
|
||||
|
||||
return dict(conf.items(account))
|
||||
else:
|
||||
return Vultr.read_ini_config(account)
|
||||
|
||||
|
||||
def _retrieve_servers(api_key):
|
||||
api_url = 'https://api.vultr.com/v1/server/list'
|
||||
|
||||
try:
|
||||
response = open_url(
|
||||
api_url, headers={'API-Key': api_key, 'Content-type': 'application/json'},
|
||||
http_agent=VULTR_USER_AGENT,
|
||||
)
|
||||
servers_list = json.loads(response.read())
|
||||
if not servers_list:
|
||||
return []
|
||||
|
||||
return [server for id, server in servers_list.items()]
|
||||
except ValueError as e:
|
||||
raise AnsibleError("Incorrect JSON payload")
|
||||
except Exception as e:
|
||||
raise AnsibleError("Error while fetching %s: %s" % (api_url, to_native(e)))
|
||||
|
||||
|
||||
class InventoryModule(BaseInventoryPlugin):
|
||||
NAME = 'vultr'
|
||||
|
||||
def parse(self, inventory, loader, path, cache=True):
|
||||
super(InventoryModule, self).parse(inventory, loader, path)
|
||||
self._read_config_data(path=path)
|
||||
|
||||
api_account = self.get_option('api_account') or 'default'
|
||||
conf = _load_conf(self.get_option('api_config'), api_account)
|
||||
|
||||
try:
|
||||
api_key = self.get_option('api_key') or conf.get('key')
|
||||
except Exception as e:
|
||||
raise AnsibleError('Could not find an API key. Check the configuration files.')
|
||||
|
||||
hostname_preference = self.get_option('hostname') or 'v4_main_ip'
|
||||
|
||||
for server in _retrieve_servers(api_key):
|
||||
server = Vultr.normalize_result(server, SCHEMA)
|
||||
for group in ['region', 'os']:
|
||||
self.inventory.add_group(group=server[group])
|
||||
self.inventory.add_host(group=server[group], host=server['name'])
|
||||
|
||||
for attribute, value in server.items():
|
||||
self.inventory.set_variable(server['name'], attribute, value)
|
||||
self.inventory.set_variable(server['name'], 'ansible_host', server[hostname_preference])
|
Loading…
Reference in a new issue