Created
May 26, 2020 09:17
-
-
Save srgvg/94849c3fcc09baef43bb4067f4966cca to your computer and use it in GitHub Desktop.
This is a boiler plate example that could be used to write an inventory plugin It shows the use case of retrieving data from a remote API, which might be a slow or costly action, you may want to cache. What needs to be initialized in Ansible to use a cache is shown, too.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This is a boiler plate example that could be used to write an inventory plugin. | |
# It shows the use case of retrieving data from a remote API, which might be a | |
# slow or costly action, you may want to cache. | |
# What needs to be initialized in Ansible to use a cache is shown, too. | |
# This example by by Serge van Ginderachter <[email protected]> | |
# Copyright (c) 2017 Ansible Project | |
# Copyright (c) 2020 Serge van Ginderachter <[email protected]> | |
# GNU General Public License v3.0+ | |
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | |
# Make coding more python3-ish | |
from __future__ import absolute_import, division, print_function | |
__metaclass__ = type | |
import os | |
import re | |
import json | |
# Python 2/3 Compatibility | |
try: | |
from urlparse import urljoin | |
except ImportError: | |
from urllib.parse import urljoin | |
from ansible.module_utils.urls import Request | |
from ansible import constants as C | |
from ansible.errors import AnsibleParserError | |
from ansible.plugins.inventory import BaseInventoryPlugin, Cacheable | |
from ansible.module_utils.parsing.convert_bool import boolean | |
try: | |
from __main__ import display | |
except ImportError: | |
from ansible.utils.display import Display | |
display = Display() | |
DOCUMENTATION = """ | |
name: remoteapi | |
plugin_type: inventory | |
authors: | |
- Serge van Ginderachter <[email protected]> | |
short_description: > | |
Retrieves hosts information from and transforms it into | |
Ansible Inventory | |
description: | |
extends_documentation_fragment: | |
- inventory_cache | |
options: | |
plugin: | |
description: the name of this plugin, it should always be set | |
to 'remoteapi' for this plugin to recognize it as it's own. | |
env: | |
- name: ANSIBLE_INVENTORY_ENABLED | |
required: True | |
choices: ['remoteapi'] | |
remoteapi_url: | |
type: string | |
required: True | |
remoteapi_username: | |
type: string | |
required: True | |
remoteapi_password: | |
type: string | |
required: True | |
remoteapi_skip_tls_check: | |
type: boolean | |
default: False | |
""" | |
EXAMPLES = """ | |
This is a boiler plate example that could be used to write an inventory plugin. | |
It shows the use case of retrieving data from a remote API, which might be a | |
slow or costly action, you may want to cache. | |
What needs to be initialized in Ansible to use a cache is shown, too. | |
""" | |
class InventoryModule(BaseInventoryPlugin, Cacheable): | |
''' | |
Main Object that makes this an Ansible Inventory plugin | |
''' | |
NAME = "remoteapi" | |
def verify_file(self, path): | |
''' | |
this function is called by Ansible to verify if a given inventory file | |
is the configuration file for this plugin | |
''' | |
valid = False | |
if super(InventoryModule, self).verify_file(path): | |
file_name, ext = os.path.splitext(path) | |
if ext in C.YAML_FILENAME_EXTENSIONS: | |
valid = True | |
return valid | |
def parse(self, inventory, loader, path, cache=False): | |
''' | |
main function, called by ansible to retrieve and create an inventory | |
''' | |
super(InventoryModule, self).parse( | |
inventory, loader, path, cache=cache | |
) | |
# needed to be able to use inventory caching | |
cache_key = self.get_cache_key(path) | |
if not cache: | |
cache = self.get_option("cache") | |
# read the config file, and retrieve the settings we need | |
config_data = self._read_config_data(path) | |
remoteapi_url = config_data.get("remoteapi_url") | |
remoteapi_username = config_data.get("remoteapi_username") | |
remoteapi_password = config_data.get("remoteapi_password") | |
remoteapi_skip_tls_check = config_data.get("remoteapi_skip_tls_check", False) | |
display.debug( | |
"Running with config: remoteapi_url='{}, remoteapi_username='{}', remoteapi_skip_tls_check='{}'".format( | |
remoteapi_url, remoteapi_username, remoteapi_skip_tls_check | |
) | |
) | |
if not (remoteapi_url and remoteapi_username and remoteapi_password): | |
raise AnsibleParserError( | |
"Missing connection info (remoteapi_url, ", | |
"remoteapi_username, remoteapi_password) in %s" % path, | |
) | |
# create a cmdb/remoteapi object with the retrieved configuration | |
cmdb = MyRemoteAPI( | |
remoteapi_url, remoteapi_username, remoteapi_password, remoteapi_skip_tls_check | |
) | |
# create the inventory | |
self.create_inventory(cmdb, cache, cache_key) | |
def create_inventory(self, cmdb, cache, cache_key): | |
''' | |
function where the main logic gets executed to create the inventory | |
if you want to extend the inventory, e.g. retrieve more information, | |
you will probaly want to start here | |
''' | |
display.debug("Getting inventory data") | |
data = self.get_data(cmdb, cache, cache_key) | |
self.inventory.add_group("foo") | |
self.inventory.add_group("bar") | |
self.inventory.add_child("foo", "bar") | |
def get_data(self, remoteapi, cache, cache_key): | |
''' | |
retrieve the raw data from remoteapi, or from cache | |
''' | |
# if a cache is available, retrieve it and store it in 'data', if not | |
# flag to update it | |
update_cache = False | |
if cache: | |
try: | |
data = self.cache.get(cache_key) | |
except KeyError: | |
update_cache = True | |
display.debug("Cache enabled" if cache else "Cache disabled") | |
display.debug( | |
"Updating cache" | |
if update_cache | |
else "Using cache {}".format(cache_key) | |
) | |
# create or update cache if needed, store it in 'data' | |
if not cache or update_cache: | |
data = {} | |
for e in MyRemoteAPI.ENDPOINTS: | |
display.debug("Retrieving data from endpoint {}.".format(e)) | |
data.update(remoteapi.getter(e)) | |
self.cache.set(cache_key, data) | |
return data |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment