{"id":987,"date":"2016-10-16T19:56:26","date_gmt":"2016-10-16T17:56:26","guid":{"rendered":"http:\/\/www.netnea.com\/cms\/?p=987"},"modified":"2022-12-13T11:43:41","modified_gmt":"2022-12-13T10:43:41","slug":"using-ansible-to-fetch-information-from-ios-devices","status":"publish","type":"post","link":"https:\/\/www.netnea.com\/cms\/2016\/10\/16\/using-ansible-to-fetch-information-from-ios-devices\/","title":{"rendered":"Using Ansible to Fetch Information from IOS Devices"},"content":{"rendered":"<p>In this article, we&#8217;ll look at various Ansible modules that can be used to fetch information from Cisco IOS devices: <a href=\"https:\/\/docs.ansible.com\/ansible\/ios_facts_module.html\">ios_facts<\/a>, <a href=\"http:\/\/docs.ansible.com\/ansible\/snmp_facts_module.html\">snmp_facts<\/a> and <a href=\"https:\/\/docs.ansible.com\/ansible\/ios_command_module.html\">ios_command<\/a>. Regardless of the used module, we&#8217;ll store the output in a JSON file that can easily be used in other tools.<\/p>\n<h1>ios_facts<\/h1>\n<p><a href=\"https:\/\/docs.ansible.com\/ansible\/ios_facts_module.html\">ios_facts<\/a> is the obvious choice. It connects to the target using SSH and gathers information with CLI commands. Here&#8217;s a sample playbook:<\/p>\n<pre>\u00a0$ cat fetch_iosfacts.yml\n- hosts: ios\n\u00a0 connection: local\n\u00a0 vars:\n\u00a0 tasks:\n\u00a0\u00a0\u00a0 - name: ssh facts\n\u00a0\u00a0\u00a0\u00a0\u00a0 register: iosfacts_out\n\u00a0\u00a0\u00a0\u00a0\u00a0 ios_facts:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 provider: \"{{ credentials }}\"\n\u00a0\u00a0\u00a0 - copy: content=\"{{ iosfacts_out | to_nice_json }}\" dest=\"out\/{{inventory_hostname}}_iosfacts.json\"<\/pre>\n<p>The resulting file is very similar to ordinary Ansible facts you&#8217;d get from any other non-IOS host:<\/p>\n<pre>{\n\u00a0\u00a0\u00a0 \"ansible_facts\": {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"ansible_net_all_ipv4_addresses\": [\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"192.168.43.19\"\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ],\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"ansible_net_all_ipv6_addresses\": [],\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"ansible_net_filesystems\": [\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"fstage:\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"flash:\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"system:\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"tmpsys:\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ],\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"ansible_net_hostname\": \"nealab19\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"ansible_net_image\": \"flash:\/c3750e-universalk9-mz.150-2.SE6\/c3750e-universalk9-mz.150-2.SE6.bin\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"ansible_net_interfaces\": {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"FastEthernet0\": {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"bandwidth\": 100000,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"description\": null,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"duplex\": null,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"ipv4\": null,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"lineprotocol\": \"down \",\n ... \n\n<\/pre>\n<h1>snmp_facts<\/h1>\n<p><a href=\"http:\/\/docs.ansible.com\/ansible\/snmp_facts_module.html\">snmp_facts<\/a> are very similar to ios_facts, but as the name suggests, obtained by walking various SNMP MIBs. There is generally a bit less information, but with the upside that this module will work for non-Cisco stuff and devices without SSH access.<\/p>\n<p>The sample playbook looks very similar, but of course we need to supply the appropriate SNMP v2 or v3 parameters:<\/p>\n<pre>\u00a0$ cat fetch_snmpfacts.yml\n- hosts: ios\n\u00a0 connection: local\n\u00a0 vars:\n\u00a0 tasks:\n\u00a0\u00a0\u00a0 - snmp_facts:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 host: \"{{ credentials.host }}\"\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 version: \"{{ credentials.snmpversion }}\"\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 community: \"{{ credentials.snmpcommunity }}\"\n\u00a0\u00a0\u00a0\u00a0\u00a0 register: snmpfacts_out\n\u00a0\u00a0\u00a0 - copy: content=\"{{ snmpfacts_out | to_nice_json }}\" dest=\"out\/{{inventory_hostname}}_snmpfacts.json\"<\/pre>\n<p>The output is comparable as well. You get some additional information from\u00a0 the MIB-2 System MIB, at the cost of having the interfaces indexed by OID instead of their name.<\/p>\n<pre>{\n\u00a0\u00a0\u00a0 \"ansible_facts\": {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"ansible_all_ipv4_addresses\": [\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"192.168.43.19\"\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ],\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"ansible_interfaces\": {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"14502\": {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"adminstatus\": \"up\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"description\": \"\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"ifindex\": \"14502\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"mac\": \"f0f742abee40\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"mtu\": \"1500\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"name\": \"FastEthernet0\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"operstatus\": \"down\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"speed\": \"1500\"\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 },\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ...\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 },\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"ansible_sysdescr\": \"Cisco IOS Software, C3750E Software...\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"ansible_syslocation\": \"\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"ansible_sysname\": \"nealab19.netnea.com\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"ansible_sysobjectid\": \"1.3.6.1.4.1.9.1.516\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"ansible_sysuptime\": \"208066918\"\n\u00a0\u00a0\u00a0 }...<\/pre>\n<h1>ios_command<\/h1>\n<p>A big shortcoming of the previous modules is that the list of discovered attributes is not extendable. To collect custom data, you can resort to the <a href=\"https:\/\/docs.ansible.com\/ansible\/ios_command_module.html\">ios_command<\/a> module. However to get nicely formatted values in your JSON, some extraction work on the command output is required. In this sample playbook, we extract all SNMP trap destinations and format them nicely as array:<\/p>\n<pre>\u00a0$ cat fetch_command.yml\n- hosts: ios\n\u00a0 connection: local\n\u00a0 vars:\n\u00a0\u00a0\u00a0 trapdests: []\n\u00a0 tasks:\n\u00a0\u00a0\u00a0 - name: show snmp hosts\n\u00a0\u00a0\u00a0\u00a0\u00a0 register: command_out\n\u00a0\u00a0\u00a0\u00a0\u00a0 ios_command:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 commands: \"show snmp host\u00a0 | include Notification host\"\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 provider: \"{{ credentials }}\"\n\n\u00a0\u00a0\u00a0 - name: extract values\n\u00a0\u00a0\u00a0\u00a0\u00a0 set_fact:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 trapdests: \"{{trapdests + [item.split()[2]]}}\"\n\u00a0\u00a0\u00a0\u00a0\u00a0 with_items: \"{{command_out.stdout_lines}}\"\n\u00a0\u00a0\u00a0 - copy: content=\"{{ trapdests | to_nice_json }}\" dest=\"out\/{{inventory_hostname}}_trapdests.json\"\n\n<\/pre>\n<p>The set_fact block loops over all output lines, then extracts only the destination IP and appends it to the trapdests array. So from the raw command output<\/p>\n<pre>nealab19#show snmp host\u00a0 | include Notification host\nNotification host: 192.168.25.8\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0udp-port: 162 \u00a0\u00a0\u00a0 \u00a0type: trap\nNotification host: 192.168.25.9\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0udp-port: 162 \u00a0\u00a0\u00a0 \u00a0type: trap<\/pre>\n<p>we arrive at this JSON array:<\/p>\n<pre>[\n\u00a0\u00a0\u00a0 \"192.168.25.8\",\n\u00a0\u00a0\u00a0 \"192.168.25.9\"\n]<\/pre>\n<h1>Running the sample playbooks<\/h1>\n<p>To run these samples yourself, you&#8217;ll need a few additional files the weren&#8217;t mentioned yet. First, we need an inventory defining the ios group and all devices we&#8217;d like to collect data from:<\/p>\n<pre>\u00a0$ cat inventory\n[ios]\nnealab19\nnealab23<\/pre>\n<p>Also we have used the credentials structure all over the place, which is centrally defined in our group vars:<\/p>\n<pre>\u00a0$ cat group_vars\/ios\nansible_python_interpreter: \/opt\/ansible\/pyenv\/bin\/python\n\ncredentials:\n\u00a0 host: \"{{ inventory_hostname }}\"\n\u00a0 username: \"demo\"\n\u00a0 password: \"demo\"\n\u00a0 snmpversion: v2c\n\u00a0 snmpcommunity: demo\n\n<\/pre>\n<p>Of course storing passwords and communities in plain text is generally a bad idea. For production usage, we recommend using the <a href=\"http:\/\/docs.ansible.com\/ansible\/playbooks_vault.html\">vault<\/a>. In case you&#8217;re using another python than \/usr\/bin\/python to execute Ansible modules, you&#8217;ll need to set the ansible_python_interpreter as well.<br \/>\nOnce all of this is in place, you should be able to run the playbooks like e.g.<\/p>\n<pre>$ ansible-playbook -i inventory fetch_command.yml<\/pre>\n<p>Please note that you need at least Ansible 2.2 to have all of the modules.<\/p>\n<h1>IOS-XR, NX-OS and others<\/h1>\n<p>For these IOS variants, you can find specialized versions of the ios_-modules like <a href=\"https:\/\/docs.ansible.com\/ansible\/iosxr_facts_module.html\">iosxr_facts<\/a>, <a href=\"https:\/\/docs.ansible.com\/ansible\/nxos_command_module.html\">nxos_command<\/a> and many more. For a full list of Ansible networking-related functionality, check out <a href=\"https:\/\/docs.ansible.com\/ansible\/list_of_network_modules.html\">this page<\/a>. Happy hacking!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this article, we&#8217;ll look at various Ansible modules that can be used to fetch information from Cisco IOS devices: ios_facts, snmp_facts and ios_command. Regardless of the used module, we&#8217;ll store the output in a JSON file that can easily be used in other tools. ios_facts ios_facts is the obvious choice. It connects to the [&hellip;]<\/p>\n","protected":false},"author":4,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":{"0":"post-987","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-nms","7":"czr-hentry"},"_links":{"self":[{"href":"https:\/\/www.netnea.com\/cms\/wp-json\/wp\/v2\/posts\/987","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.netnea.com\/cms\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.netnea.com\/cms\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.netnea.com\/cms\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/www.netnea.com\/cms\/wp-json\/wp\/v2\/comments?post=987"}],"version-history":[{"count":4,"href":"https:\/\/www.netnea.com\/cms\/wp-json\/wp\/v2\/posts\/987\/revisions"}],"predecessor-version":[{"id":2001,"href":"https:\/\/www.netnea.com\/cms\/wp-json\/wp\/v2\/posts\/987\/revisions\/2001"}],"wp:attachment":[{"href":"https:\/\/www.netnea.com\/cms\/wp-json\/wp\/v2\/media?parent=987"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.netnea.com\/cms\/wp-json\/wp\/v2\/categories?post=987"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.netnea.com\/cms\/wp-json\/wp\/v2\/tags?post=987"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}