Last active
February 25, 2020 12:18
-
-
Save mccbryan3/fbde13e8100cd96aee4480158053daaf to your computer and use it in GitHub Desktop.
Dynamic inventory script for Ansible using the OME API to find device Type of 1000
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
#!/usr/bin/env python | |
# Copyright: (c) 2018, Keiran Steele | |
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | |
import os | |
import sys | |
import argparse | |
try: | |
import requests | |
except ImportError: | |
sys.exit('requests package is required for this inventory script') | |
try: | |
import json | |
except ImportError: | |
import simplejson as json | |
inline_config = { | |
"config_vars" : { | |
"base_host_url" : None, | |
"base_api_url" : "/api/DeviceService/Devices?$top=1000", | |
"username" : None, #Only put your username here for testing purposes | |
"password" : None, #Only put your password here for testing purposes | |
}, | |
"group_by" : { | |
"Model" | |
}, | |
"hosts_vars" : { | |
"ip" : { | |
"ansible_ssh_host" : "NetworkAddress" | |
}, | |
"general" : { | |
"model" : "Model", | |
"service_tag" : "DeviceServiceTag" | |
} | |
} | |
} | |
def cli_arguments(): | |
""" | |
Script cli arguments | |
Ansible calls "--list" as an argument by default | |
""" | |
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) | |
parser.add_argument("--list", help="Print all hosts with vars as Ansible dynamic inventory syntax.", | |
action="store_true") | |
parser.add_argument("--host", help="Print specific host vars as Ansible dynamic inventory syntax.", | |
action="store") | |
arguments = parser.parse_args() | |
return arguments | |
class OpenManageInventory(object): | |
def __init__(self, script_args, config): | |
""" | |
Define and populate attributes from either environment variables or inline configuation data | |
""" | |
self.list = script_args.list | |
self.host = script_args.host | |
if os.environ.get('OM_USERNAME'): | |
self.username = os.environ.get('OM_USERNAME') | |
elif config['config_vars']['username']: | |
self.username = config['config_vars']['username'] | |
else: | |
raise ValueError('No Username Provided') | |
if os.environ.get('OM_PASSWORD'): | |
self.password = os.environ.get('OM_PASSWORD') | |
elif config['config_vars']['password']: | |
self.username = config['config_vars']['password'] | |
else: | |
raise ValueError('No Password Provided') | |
if os.environ.get('OM_HOSTURL'): | |
self.host_url = os.environ.get('OM_HOSTURL') | |
elif config['config_vars']['base_host_url']: | |
self.host_url = config['config_vars']['base_host_url'] | |
else: | |
raise ValueError('No URL provided for the OpenManage host') | |
if config['config_vars']['base_api_url']: | |
self.base_api_url = config['config_vars']['base_api_url'] | |
else: | |
raise ValueError('No API URL provided.') | |
if config['group_by']: | |
self.group_by = config['group_by'] | |
else: | |
self.group_by = {} | |
if config['hosts_vars']: | |
self.hosts_vars = config['hosts_vars'] | |
else: | |
self.hosts_vars = {} | |
def get_devices_list(self, host_url, base_api_url, username, password): | |
""" | |
Calls the Dell OME API for a list of devices and their associated data | |
Returns: | |
hosts_list | |
""" | |
api_url = host_url + base_api_url | |
hosts_list = [] | |
while api_url: | |
# Get hosts list | |
r = requests.get(api_url, auth=(username, password), verify=False) | |
r.raise_for_status() | |
api_output = r.json() | |
api_output_data = api_output["value"] | |
if isinstance(api_output, dict) and "value" in api_output: | |
hosts_list += api_output_data | |
try: | |
nextpage = api_output["@odata.nextLink"] | |
except: | |
nextpage = None | |
api_url = None | |
if nextpage != None: | |
api_url = host_url + nextpage | |
return hosts_list | |
@staticmethod | |
def add_host_to_group(server_name, group_value, inventory_dict): | |
""" | |
Add a host to a single group | |
""" | |
group_name = group_value | |
if server_name and group_value: | |
if group_name not in inventory_dict: | |
inventory_dict.update({group_name: []}) | |
#if server_name not in inventory_dict[group_name]: | |
inventory_dict[group_name].append(server_name) | |
return inventory_dict | |
def add_host_to_inventory(self, groups, inventory_dict, host_data): | |
""" | |
Add host to the inventory dict and put in the ungrouped group if no other group is provided. | |
If a group is provided and the group value exists in the host data, the host will be put in that group. | |
Returns: | |
Updated inventory dict | |
""" | |
server_name = host_data.get("DeviceName") | |
if groups: | |
for group in groups: | |
if host_data: | |
group_value = host_data[group] | |
if group_value: | |
self.add_host_to_group(server_name, group_value, inventory_dict) | |
else: | |
self._put_host_to_ungrouped(inventory_dict, server_name) | |
else: | |
self._put_host_to_ungrouped(inventory_dict, server_name) | |
return inventory_dict | |
@staticmethod | |
def _put_host_to_ungrouped(inventory_dict, server_name): | |
""" | |
Add host to the "ungrouped" group | |
""" | |
if "ungrouped" not in inventory_dict: | |
inventory_dict.setdefault("ungrouped", [server_name]) | |
else: | |
if server_name not in inventory_dict["ungrouped"]: | |
inventory_dict["ungrouped"].append(server_name) | |
def get_host_vars(self, host_data, host_vars): | |
""" | |
Iterate through host_vars and add variables to the host_vars_dict based on the source for each category. | |
Returns: | |
Dictionary of vars for host. | |
""" | |
host_vars_dict = dict() | |
if host_vars: | |
# categories_source indicates which part of of the host_data dict to get vars from | |
categories_source = { | |
"ip" : host_data['DeviceManagement'][0], | |
"general" : host_data | |
} | |
for category in host_vars: | |
data_dict = categories_source[category] | |
for var_name, var_data in host_vars[category].items(): | |
var_value = data_dict.get(var_data) | |
if var_value is not None: | |
host_vars_dict.update({var_name: var_value}) | |
return host_vars_dict | |
def update_host_meta_vars(self, inventory_dict, host_name, host_vars): | |
""" | |
Updates inventory dict with host vars | |
Returns: | |
Updated Inventory dict | |
""" | |
if host_vars and not self.host: | |
inventory_dict['_meta']['hostvars'].update({host_name: host_vars}) | |
elif host_vars and self.host: | |
inventory_dict.update({host_name: host_vars}) | |
return inventory_dict | |
def generate_inventory(self): | |
""" | |
Generate the dynamic inventory for Ansible | |
Returns: | |
A dict object with the Ansible inventory of hosts and their vars. | |
""" | |
inventory_dict = dict() | |
openmanage_devices_list = self.get_devices_list(self.host_url, self.base_api_url, self.username, self.password) | |
if openmanage_devices_list: | |
inventory_dict.update({"_meta": {"hostvars": {}}}) | |
for current_host in openmanage_devices_list: | |
server_name = current_host.get("DeviceName") | |
server_type = current_host.get("Type") | |
if server_type == 1000: | |
self.add_host_to_inventory(self.group_by, inventory_dict, current_host) | |
host_vars = self.get_host_vars(current_host, self.hosts_vars) | |
inventory_dict = self.update_host_meta_vars(inventory_dict, server_name, host_vars) | |
return inventory_dict | |
def print_inventory_json(self, inventory_dict): | |
""" | |
Print Inventory. | |
""" | |
if self.host: | |
result = inventory_dict.setdefault(self.host, {}) | |
elif self.list: | |
result = inventory_dict | |
else: | |
result = {} | |
print(json.dumps(result)) | |
# Main | |
def main(): | |
args = cli_arguments() | |
#config_data = get_config_data(inline_config) | |
openmanage = OpenManageInventory(args, inline_config) | |
ansible_inventory = openmanage.generate_inventory() | |
openmanage.print_inventory_json(ansible_inventory) | |
# Run main | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment