├── README.md ├── csv2json.py ├── csv_inventory.yaml ├── csv_inventory └── myinventory.csv ├── inventory_plugins ├── my_csv_plugin.py └── my_csv_plugin.pyc ├── playbook.yaml └── test_ios_config_replace.yml /README.md: -------------------------------------------------------------------------------- 1 | ## Demo repository for custom inventory plugins 2 | Please see: https://termlen0.github.io/2019/11/16/observations/ for details 3 | -------------------------------------------------------------------------------- /csv2json.py: -------------------------------------------------------------------------------- 1 | import csv, json 2 | 3 | 4 | 5 | def get_structured_inventory(inventory_file): 6 | 7 | #Initialize a dict 8 | inventory_data = {} 9 | #Read the CSV and add it to the dictionary 10 | with open(inventory_file, 'r') as fh: 11 | csvdict = csv.DictReader(fh) 12 | for rows in csvdict: 13 | #import pdb;pdb.set_trace() 14 | hostname = rows['Device Name'] 15 | inventory_data[hostname] = rows 16 | return inventory_data 17 | 18 | 19 | 20 | if __name__ == "__main__" : 21 | inventory_file = "csv_inventory/myinventory.csv" 22 | myinventory = get_structured_inventory(inventory_file) 23 | print(json.dumps(myinventory, indent=4)) 24 | 25 | -------------------------------------------------------------------------------- /csv_inventory.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | #csv_plugin.yaml 3 | 4 | plugin: my_csv_plugin # Name of the plugin 5 | path_to_inventory: csv_inventory # Directory location of CSV 6 | csv_file: myinventory.csv # Name of the inventory file 7 | -------------------------------------------------------------------------------- /csv_inventory/myinventory.csv: -------------------------------------------------------------------------------- 1 | Device Name,Mgmt IP,Location,Function,Platform 2 | ORDcore01,10.122.1.114,ORD,core,ios 3 | ORDcore02,10.122.1.115,ORD,core,ios 4 | ORDdist01,10.122.1.116,ORD,distribution,nxos 5 | ORDdist02,10.122.1.117,ORD,distribution,nxos 6 | ORDagg01,10.122.1.118,ORD,aggregation,nxos 7 | ORDagg02,10.122.1.119,ORD,aggregation,nxos 8 | ORDagg03,10.122.1.120,ORD,aggregation,nxos 9 | ORDagg04,10.122.1.121,ORD,aggregation,nxos 10 | ORDaccess01,10.122.1.122,ORD,access,ios 11 | ORDaccess02,10.122.1.123,ORD,access,ios 12 | ORDaccess03,10.122.1.124,ORD,access,nxos 13 | ORDaccess04,10.122.1.125,ORD,access,ios 14 | ORDaccess05,10.122.1.126,ORD,access,ios 15 | ORDaccess06,10.122.1.127,ORD,access,nxos 16 | ORDaccess07,10.122.1.128,ORD,access,ios 17 | ORDaccess08,10.122.1.129,ORD,access,ios 18 | ORDaccess09,10.122.1.130,ORD,access,nxos 19 | ORDaccess10,10.122.1.131,ORD,access,ios 20 | MCOcore01,10.141.1.114,MCO,core,junos 21 | MCOcore02,10.141.1.115,MCO,core,junos 22 | MCOdist01,10.141.1.116,MCO,distribution,eos 23 | MCOdist02,10.141.1.117,MCO,distribution,eos 24 | MCOagg01,10.141.1.118,MCO,aggregation,eos 25 | MCOagg02,10.141.1.119,MCO,aggregation,eos 26 | MCOagg03,10.141.1.120,MCO,aggregation,eos 27 | MCOagg04,10.141.1.121,MCO,aggregation,eos 28 | MCOaccess01,10.141.1.141,MCO,access,ios 29 | MCOaccess02,10.141.1.123,MCO,access,eos 30 | MCOaccess03,10.141.1.124,MCO,access,nxos 31 | MCOaccess04,10.141.1.125,MCO,access,eos 32 | MCOaccess05,10.141.1.126,MCO,access,eos 33 | MCOaccess06,10.141.1.127,MCO,access,nxos 34 | MCOaccess07,10.141.1.128,MCO,access,ios 35 | MCOaccess08,10.141.1.129,MCO,access,ios 36 | MCOaccess09,10.141.1.130,MCO,access,nxos 37 | MCOaccess10,10.141.1.131,MCO,access,eos 38 | -------------------------------------------------------------------------------- /inventory_plugins/my_csv_plugin.py: -------------------------------------------------------------------------------- 1 | from __future__ import (absolute_import, division, print_function) 2 | __metaclass__ = type 3 | 4 | DOCUMENTATION = r''' 5 | name: my_csv_plugin 6 | plugin_type: inventory 7 | short_description: Returns Ansible inventory from CSV 8 | description: Returns Ansible inventory from CSV 9 | options: 10 | plugin: 11 | description: Name of the plugin 12 | required: true 13 | choices: ['my_csv_plugin'] 14 | path_to_inventory: 15 | description: Directory location of the CSV inventory 16 | required: true 17 | csv_file: 18 | description: File name of the CSV inventory file 19 | required: true 20 | ''' 21 | 22 | 23 | 24 | from ansible.plugins.inventory import BaseInventoryPlugin 25 | from ansible.errors import AnsibleError, AnsibleParserError 26 | import csv 27 | 28 | 29 | class InventoryModule(BaseInventoryPlugin): 30 | NAME = 'my_csv_plugin' 31 | 32 | 33 | def verify_file(self, path): 34 | '''Return true/false if this is possibly a valid file for this plugin to 35 | consume 36 | 37 | ''' 38 | valid = False 39 | if super(InventoryModule, self).verify_file(path): 40 | # base class verifies that file exists and is readable by current 41 | # user 42 | if path.endswith(('csv_inventory.yaml', 43 | 'csv_inventory.yml')): 44 | valid = True 45 | return valid 46 | 47 | def _get_structured_inventory(self, inventory_file): 48 | 49 | #Initialize a dict 50 | inventory_data = {} 51 | #Read the CSV and add it to the dictionary 52 | with open(inventory_file, 'r') as fh: 53 | csvdict = csv.DictReader(fh) 54 | for rows in csvdict: 55 | hostname = rows['Device Name'] 56 | inventory_data[hostname] = rows 57 | return inventory_data 58 | 59 | def _populate(self): 60 | '''Return the hosts and groups''' 61 | self.inventory_file = self.inv_dir + '/' + self.inv_file 62 | self.myinventory = self._get_structured_inventory(self.inventory_file) 63 | #Create the location, function and platform groups 64 | locations = [] 65 | functions = [] 66 | platforms = [] 67 | for data in self.myinventory.values(): 68 | if not data['Location'] in locations: 69 | locations.append(data['Location']) 70 | if not data['Function'] in functions: 71 | functions.append(data['Function']) 72 | if not data['Platform'] in platforms: 73 | platforms.append(data['Platform']) 74 | for location in locations: 75 | self.inventory.add_group(location) 76 | for function in functions: 77 | self.inventory.add_group(function) 78 | for platform in platforms: 79 | self.inventory.add_group(platform) 80 | #Add the hosts to the groups 81 | for hostname,data in self.myinventory.items(): 82 | self.inventory.add_host(host=hostname, group=data['Location']) 83 | self.inventory.add_host(host=hostname, group=data['Function']) 84 | self.inventory.add_host(host=hostname, group=data['Platform']) 85 | self.inventory.set_variable(hostname, 'ansible_host', data['Mgmt IP']) 86 | self.inventory.set_variable(hostname, 'ansible_network_os', data['Platform']) 87 | 88 | 89 | def parse(self, inventory, loader, path, cache): 90 | '''Return dynamic inventory from source ''' 91 | super(InventoryModule, self).parse(inventory, loader, path, cache) 92 | # Read the inventory YAML file 93 | self._read_config_data(path) 94 | try: 95 | # Store the options from the YAML file 96 | self.plugin = self.get_option('plugin') 97 | self.inv_dir = self.get_option('path_to_inventory') 98 | self.inv_file = self.get_option('csv_file') 99 | except Exception as e: 100 | raise AnsibleParserError( 101 | 'All correct options required: {}'.format(e)) 102 | # Call our internal helper to populate the dynamic inventory 103 | self._populate() 104 | -------------------------------------------------------------------------------- /inventory_plugins/my_csv_plugin.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/termlen0/custom-inventory-plugin/e681bb04971ae10004c4f7f03f397d22839b0faa/inventory_plugins/my_csv_plugin.pyc -------------------------------------------------------------------------------- /playbook.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | #playbook.yaml 3 | 4 | - name: DISPLAY THE INVENTORY VARS 5 | hosts: nxos, core # These are dynamically generated groups from the plugin 6 | gather_facts: no 7 | tasks: 8 | - name: DISPLAY THE HOST VARS 9 | debug: 10 | msg: "The mgmt IP is {{ ansible_host }} and platorm is {{ ansible_network_os }}" 11 | 12 | -------------------------------------------------------------------------------- /test_ios_config_replace.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: rtr1 3 | gather_facts: no 4 | tasks: 5 | - name: Replace config 6 | ios_command: 7 | commands: 8 | - configure replace flash:running.config force 9 | --------------------------------------------------------------------------------