Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jpmens/8c70669773b80a4602bb0bfd9e8d6852 to your computer and use it in GitHub Desktop.
Save jpmens/8c70669773b80a4602bb0bfd9e8d6852 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 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 <serge@vanginderachter.be>
# Copyright (c) 2017 Ansible Project
# Copyright (c) 2020 Serge van Ginderachter <serge@vanginderachter.be>
# 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 <serge@vanginderachter.be>
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