{"id":53,"date":"2019-09-06T15:12:35","date_gmt":"2019-09-06T05:12:35","guid":{"rendered":"https:\/\/mitchbradford.me\/wp\/?p=53"},"modified":"2019-09-06T15:12:36","modified_gmt":"2019-09-06T05:12:36","slug":"current-state-device-config-audit","status":"publish","type":"post","link":"https:\/\/mitchbradford.me\/wp\/2019\/09\/06\/current-state-device-config-audit\/","title":{"rendered":"Current State Device Config Audit"},"content":{"rendered":"\n<p>Welcome to my first post which happens to be on network automation.  I&#8217;ve got a large number of network hardware replacements coming up so I&#8217;ve created a (fairly basic) script that uses Netmiko to do the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Import a list of IP addresses from an external file (routers.txt)<\/li><li>SSH to each IP address (with error handling)<\/li><li>Run a list of commands specified from an external file (commands.txt)<\/li><li>Output the result of the commands in an individual text file named with each devices hostname and IP address<\/li><li>Output the IP addresses of devices it was unable to connect to into a file which is named based on the error. Examples are:<ul><li>Connection Timeouts.txt<\/li><li>Auth Failures.txt<\/li><li>SSH Failures.txt<\/li><li>EOF Errors.txt<\/li><li>UnknownError.txt<\/li><\/ul><\/li><\/ul>\n\n\n\n<p>At the moment the script is only working for Cisco equipment as that&#8217;s the current use-case I have for it, however, it should be pretty easy to call the Aruba or other vendor Netmiko library instead.<\/p>\n\n\n\n<p>I&#8217;ve attached the initial release of the code below, however, the most current version will always be located on my <a href=\"https:\/\/github.com\/mitchbradford\">GitHub<\/a>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/usr\/bin\/env python\n# Script by Mitch Bradford\n# Dependencies - Netmiko, Python 3\n# Instructions - List IP addresses in routers.txt and commands to run in commands.txt\n# === Formatting ===\n# routers.txt:\n# [ip address]\n# [ip address]\n#\n# commands.txt:\n# exit\n# [enable priv command]\n# [enable priv command]\n\nfrom netmiko import ConnectHandler\nfrom netmiko.ssh_exception import  NetMikoTimeoutException\nfrom paramiko.ssh_exception import SSHException \nfrom netmiko.ssh_exception import  AuthenticationException\nfrom getpass import getpass\nfrom pprint import pprint\n\nwith open('commands.txt') as f:\n\tcommands_list = f.read().splitlines()\n\nwith open('routers.txt') as f:\n\trouter_list = f.read().splitlines()\n\nusername=input('Enter your username:')\npassword=getpass()\n\nfor routers in router_list:\n\tprint ('Connecting to device ' + routers)\n\tip_address_of_device = routers\n\tios_device = {\n\t'device_type': 'cisco_ios',\n\t'ip': ip_address_of_device,\n\t'username': username,\n\t'password': password\n\t}\n\n\t#Define the error handling files to reference if\/when something fails\n\tTimeouts=open(\"Connection time outs.txt\", \"a\")\n\tAuthfailure=open(\"Auth failures.txt\", \"a\")\n\tSSHException=(\"SSH Failure.txt\", 'a')\n\tEOFError=(\"EOFerrors.txt\",'a')\n\tUnknownError=(\"UnknownError.txt\",'a')\n\n\ttry:\n\t\t# Actually connect to the device\n\t\tnet_connect = ConnectHandler(**ios_device)  \n\t\t\n\t\t# Grab the hostname of the device, so it can be used as a filename\n\t\thostname = net_connect.send_command(\"show run | i hostname\")\n\t\thostname = hostname[9:]\n\t\t\n\t\t#open file to write command output\n\t\tfile = open('1 - ' + hostname + \" - \" + ip_address_of_device + \" \" + '.txt', 'w')\n\t\t# Print output to console screen\n\t\tprint('-------------- Running script on ' + ip_address_of_device + ' - ' + hostname + ' ------------------')\n\n\t\tfile.write('======== ' + ip_address_of_device + ' @ ' + hostname + ' ========')\n\t\tfile.write(\"\\n\")\n\t\t\n\t\toutput=net_connect.send_config_set(commands_list)\n\t\t#print(output)\n\t\tfile.write(output)\n\t\t\n\t\t# Close the file\t\n\t\tfile.close()\n\t\t\n\t\t# Cleanly disconnect SSH session\t\n\t\tnet_connect.disconnect()\n\texcept (AuthenticationException):\n\t\tprint ('Authentication Failure: ' + ip_address_of_device)\n\t\tAuthfailure.write('\\n' + ip_address_of_device)\n\t\tcontinue \n\texcept (NetMikoTimeoutException):\n\t\tprint ('\\n' + 'Timeout to device: ' + ip_address_of_device)\n\t\tTimeouts.write('\\n' + ip_address_of_device)\n\t\tcontinue\n\texcept (SSHException):\n\t\tprint ('SSH might not be enabled: ' + ip_address_of_device)\n\t\tSSHException.write('\\n' + ip_address_of_device)\n\t\tcontinue \n\texcept (EOFError):\n\t\tprint ('\\n' + 'End of attempting device: ' + ip_address_of_device)\n\t\tEOFError.write('\\n' + ip_address_of_device)\n\t\tcontinue\n\texcept unknown_error:\n\t\tprint ('Some other error: ' + str(unknown_error))\n\t\tcontinue<\/code><\/pre>\n\n\n\n<p style=\"text-align:left\">The routers.txt file should be formatted as such:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>IP Address 1\nIP Address 2<\/code><\/pre>\n\n\n\n<p>The commands.txt file should be formatted as such:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Config Level Command 1\nConfig Level Command 2\nexit\nEnable Mode Command 1\nEnable Mode Command 2\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Welcome to my first post which happens to be on network automation. I&#8217;ve got a large number of network hardware replacements coming up so I&#8217;ve <a href=\"https:\/\/mitchbradford.me\/wp\/2019\/09\/06\/current-state-device-config-audit\/\" class=\"btn btn-link continue-link\">Continue Reading<\/a><\/p>\n","protected":false},"author":1,"featured_media":57,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9,10],"tags":[11,13,15,14,12],"class_list":["post-53","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-automation","category-python","tag-automation","tag-cisco","tag-netmiko","tag-networking","tag-python"],"_links":{"self":[{"href":"https:\/\/mitchbradford.me\/wp\/wp-json\/wp\/v2\/posts\/53","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mitchbradford.me\/wp\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mitchbradford.me\/wp\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mitchbradford.me\/wp\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mitchbradford.me\/wp\/wp-json\/wp\/v2\/comments?post=53"}],"version-history":[{"count":4,"href":"https:\/\/mitchbradford.me\/wp\/wp-json\/wp\/v2\/posts\/53\/revisions"}],"predecessor-version":[{"id":58,"href":"https:\/\/mitchbradford.me\/wp\/wp-json\/wp\/v2\/posts\/53\/revisions\/58"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/mitchbradford.me\/wp\/wp-json\/wp\/v2\/media\/57"}],"wp:attachment":[{"href":"https:\/\/mitchbradford.me\/wp\/wp-json\/wp\/v2\/media?parent=53"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mitchbradford.me\/wp\/wp-json\/wp\/v2\/categories?post=53"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mitchbradford.me\/wp\/wp-json\/wp\/v2\/tags?post=53"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}