Created
September 21, 2019 07:26
-
-
Save savishy/51958a10a67a017e2f2308c3487de5fa to your computer and use it in GitHub Desktop.
Ansible Inventory Plugin for OneOps
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
[defaults] | |
# Search path for inventory plugin | |
inventory_plugins = ./inventory/ | |
[inventory] | |
# enable plugin | |
enable_plugins = oneopsplugin, host_list, script, auto, yaml, ini |
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
plugin: oneopsplugin | |
oo_root: https://oneops.your.org.com | |
oo_org: oneops_org_name | |
oo_env: oneops_env_name | |
oo_assembly: oneops_assembly_name | |
oo_platforms: | |
oneops_platform: | |
ansible_user: user_with_ssh_access | |
ansible_ssh_private_key_file: ~/.ssh/id_rsa | |
oo_group_children: [] |
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
import requests,json,urllib3,os | |
# disable SSL warnings | |
urllib3.disable_warnings() | |
# import lib for logging. | |
try: | |
from __main__ import display | |
except ImportError: | |
from ansible.utils.display import Display | |
display = Display() | |
from ansible.plugins.inventory import BaseInventoryPlugin | |
DOCUMENTATION = ''' | |
name: oneopsplugin | |
plugin_type: inventory | |
short_description: OneOps inventory source | |
description: | |
- Use OneOps API to retrieve compute instances from the specified environment. | |
- Group computes by platform and create an Ansible inventory. | |
- NOTE: only specific platforms will be retrieved, those which match a dictionary. | |
- Takes a YAML configuration file ('oneops.yml') that specifies the OneOps coordinates. | |
options: | |
plugin: | |
description: token that ensures this is a source file for the 'oneopsplugin' plugin | |
required: True | |
choices: ['oneopsplugin'] | |
oo_root: | |
description: OneOps Host URL. | |
type: string | |
required: True | |
oo_org: | |
description: OneOps Organization Name. Note that your API Token must have access to this organization. | |
type: string | |
required: True | |
oo_assembly: | |
description: OneOps Assembly Name. Note that your API token must have access to this assembly. | |
type: string | |
required: True | |
oo_env: | |
description: OneOps Environment that contains the platforms and associated computes. | |
type: string | |
required: True | |
oo_platforms: | |
description: A list of OneOps Platforms that you want to use to generate the inventory. | |
type: dictionary | |
required: True | |
oo_group_children: | |
description: A dictionary that contains lists of custom groupings (e.g. groups of groups) that you want to create. | |
type: dictionary | |
required: True | |
''' | |
class OneOpsInventory: | |
def __init__(self,oo_root,oo_org,oo_assembly,oo_env,oo_platforms): | |
self.oo_api_token = os.environ['ONEOPS_API_TOKEN'] | |
self.oo_root = oo_root | |
self.oo_org = oo_org | |
self.oo_assembly = oo_assembly | |
self.oo_env = oo_env | |
self.oo_platforms = oo_platforms | |
def _get_oneops_platforms(self): | |
''' | |
Call OneOps API to get OneOps Platforms in Env. | |
Filter out by allowed platforms. | |
''' | |
endpoint = '/'.join([self.oo_root,self.oo_org,'assemblies',self.oo_assembly, | |
'operations','environments',self.oo_env,'platforms.json']) | |
raw = requests.get(endpoint, | |
auth=(self.oo_api_token,''), | |
verify=False) | |
raw.raise_for_status() | |
# return platform names which are present in dictionary. | |
return [r['ciName'] for r in json.loads(raw.content.decode('utf-8')) if r['ciName'] in self.oo_platforms.keys()] | |
def _get_oneops_computes(self,oo_platform): | |
''' | |
Call OneOps API to get OneOps Computes. | |
''' | |
oo_platform_fqdn = '.'.join([oo_platform,self.oo_env,self.oo_assembly, | |
self.oo_org,'stg-az-southcentralus-2', | |
'prod','us','walmart','net' | |
]) | |
endpoint = '/'.join([self.oo_root,self.oo_org,'assemblies',self.oo_assembly, | |
'operations','environments',self.oo_env,'platforms',oo_platform, | |
'components','compute','instances.json?instances_state=all']) | |
r = requests.get(endpoint, | |
auth=(self.oo_api_token,''), | |
verify=False) | |
retval_hosts = [] | |
retval_meta_hostvars = {} | |
for r in json.loads(r.content.decode('utf-8')): | |
hostname = r['ciAttributes']['instance_name'] | |
display.vvvv(str(r['ciAttributes'])) | |
ipaddr = r['ciAttributes']['public_ip'] | |
display.vvvv('platform: {0} hostname: {1} ipaddr: {2}'.format(oo_platform,hostname,ipaddr)) | |
retval_hosts.append(hostname) | |
retval_meta_hostvars[hostname] = {} | |
retval_meta_hostvars[hostname]['ansible_host'] = ipaddr | |
retval_meta_hostvars[hostname]['ansible_user'] = self.oo_platforms[oo_platform]['ansible_user'] | |
retval_meta_hostvars[hostname]['ansible_ssh_private_key_file'] = self.oo_platforms[oo_platform]['ansible_ssh_private_key_file'] | |
retval_meta_hostvars[hostname]['oo_platform_fqdn'] = oo_platform_fqdn | |
return (retval_hosts,retval_meta_hostvars) | |
def oneops_inventory(self): | |
''' | |
Call internal methods and return an Ansible inventory object. | |
''' | |
retval = { | |
'_meta': { | |
'hostvars': {} | |
}, | |
'all': { | |
'children': [] | |
} | |
} | |
oo_platforms = self._get_oneops_platforms() | |
for oo_platform in oo_platforms: | |
group_name = oo_platform.split('-')[-1] | |
retval[group_name] = {'hosts':[]} | |
(hosts,meta) = (self._get_oneops_computes(oo_platform=oo_platform)) | |
# concat 'hosts' list. | |
retval[group_name]['hosts'] += hosts | |
# update '_meta' dictionary. | |
retval['_meta']['hostvars'].update(meta) | |
retval['all']['children'].append(group_name) | |
return retval | |
class InventoryModule(BaseInventoryPlugin): | |
NAME = 'oneopsplugin' # used internally by Ansible, it should match the file name but not required | |
def verify_file(self, path): | |
''' return true/false if this is possibly a valid file for this plugin to consume ''' | |
valid = False | |
if super(InventoryModule, self).verify_file(path): | |
# base class verifies that file exists and is readable by current user | |
if path.endswith('.yml') or path.endswith('.yaml'): | |
valid = True | |
return valid | |
def parse(self, inventory, loader, path, cache=False): | |
# call base method to ensure properties are available for use with other helper method | |
super(InventoryModule, self).parse(inventory, loader, path, cache) | |
display.vvvv('inventory source: {}'.format(path)) | |
# this method will parse 'common format' inventory sources and | |
# update any options declared in DOCUMENTATION as needed | |
config = self._read_config_data(path) | |
# if NOT using _read_config_data you should call set_options directly, | |
# to process any defined configuration for this plugin, | |
# if you dont define any options you can skip | |
# self.set_options() | |
# example consuming options from inventory source | |
oo_inventory = OneOpsInventory(oo_root=self.get_option('oo_root'), | |
oo_org=self.get_option('oo_org'), | |
oo_assembly=self.get_option('oo_assembly'), | |
oo_env=self.get_option('oo_env'), | |
oo_platforms=self.get_option('oo_platforms')) | |
inventory = oo_inventory.oneops_inventory() | |
display.vvvv(str(inventory)) | |
#parse data and create inventory objects: | |
for group in inventory: | |
if group not in ['_meta','all']: | |
# update list of groups. | |
self.inventory.add_group(group) | |
if 'hosts' in inventory[group]: | |
for host in inventory[group]['hosts']: | |
# add host to inventory with group. | |
self.inventory.add_host(host,group=group) | |
# process hostvars for this host. | |
hostvars = inventory['_meta']['hostvars'][host] | |
for hostvar in hostvars: | |
self.inventory.set_variable(host,hostvar,inventory['_meta']['hostvars'][host][hostvar]) | |
# create custom grouping as defined in inventory source. | |
oo_group_children = self.get_option('oo_group_children') | |
for group in oo_group_children: | |
self.inventory.add_group(group) | |
for child in oo_group_children[group]: | |
self.inventory.add_child(group,child) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment