{"id":115340,"date":"2020-07-13T15:31:21","date_gmt":"2020-07-13T15:31:21","guid":{"rendered":"https:\/\/fedoramagazine.org\/?p=31280"},"modified":"2020-07-13T15:31:21","modified_gmt":"2020-07-13T15:31:21","slug":"automating-network-devices-with-ansible","status":"publish","type":"post","link":"https:\/\/sickgaming.net\/blog\/2020\/07\/13\/automating-network-devices-with-ansible\/","title":{"rendered":"Automating Network Devices with Ansible"},"content":{"rendered":"<p>Ansible is a great automation tool for system and network engineers, with Ansible we can automate small network to a large scale enterprise network. I have been using Ansible to automate both Aruba, and Cisco switches from my Fedora powered laptops for a couple of years. This article covers the requirements and executing a couple of playbooks.<\/p>\n<p> <span id=\"more-31280\"><\/span> <\/p>\n<h2>Configuring Ansible<\/h2>\n<p>If Ansible is not installed, it can be installed using the command below<\/p>\n<pre class=\"wp-block-preformatted\">$ sudo dnf -y install ansible<\/pre>\n<p>Once installed, create a folder in your home directory or a directory of your preference and copy the ansible configuration file. For this demonstration, I will be using the following.<\/p>\n<pre class=\"wp-block-preformatted\">$ mkdir -pv \/home\/$USER\/network_automation\n$ sudo cp -v \/etc\/ansible.cfg \/home\/$USER\/network_automation\n$ cd \/home\/$USER\/network_automation\n$ sudo chown $USER.$USER &amp;&amp; chmod 0600 ansible.cfg<\/pre>\n<p>To prevent lengthy commands from failing, edit the ansible.cfg and append the following lines. We must add the persistent connection and set the desired time in seconds for the <em>command_timeout<\/em> as demonstrated below. A use case where this is useful is when you are performing backups of a network device that has a lengthy configuration.<\/p>\n<pre class=\"wp-block-preformatted\">$ vim ansible.cfg\n[persistent_connection]\ncommand_timeout = 300\nconnection_timeout = 30<\/pre>\n<h3>Requirements<\/h3>\n<p>If SELinux is enabled, you will need to install SELinux binding, which is required when using the copy module.<\/p>\n<pre class=\"wp-block-preformatted\"># Install SELinux bindings\ndnf -y install python3-libselinux python3-libsemanage<\/pre>\n<h3>Creating the inventory<\/h3>\n<p>The inventory holds the names of the network assets, and grouping of the assets are in square brackets <em>[]<\/em>, below is a&nbsp; sample inventory.<\/p>\n<pre class=\"wp-block-preformatted\">[site_a]\nCore_A ansible_host=192.168.122.200\nDistro_A ansible_host=192.168.122.201\nDistro_B ansible_host=192.168.122.202<\/pre>\n<div class=\"wp-block-jetpack-markdown\">\n<p>Group vars can be used to address the common variables, for example, credentials, network operating system, and so on. Ansible document on <a href=\"https:\/\/docs.ansible.com\/ansible\/latest\/network\/getting_started\/first_inventory.html\">inventory<\/a> provides additional details.<\/p>\n<\/div>\n<h2>Playbook<\/h2>\n<div class=\"wp-block-jetpack-markdown\">\n<blockquote>\n<p>Playbooks are Ansible\u2019s configuration, deployment, and orchestration language. They can describe a policy you want your remote systems to enforce, or a set of steps in a general IT process.<br \/>\n<a href=\"https:\/\/docs.ansible.com\/ansible\/latest\/user_guide\/playbooks.html\">Ansible Playbook<\/a><\/p>\n<\/blockquote>\n<\/div>\n<h3>Read Operations<\/h3>\n<div class=\"wp-block-jetpack-markdown\">\n<p>Let us create a simple playbook to run a show command to read the configuration on a few switches.<\/p>\n<pre> <div class=\"codecolorer-container text default language-yaml\" style=\"overflow:auto;border:1px solid #9F9F9F;width:435px\"><div class=\"text codecolorer\" style=\"padding:5px;font:normal 12px\/1.4em Monaco, Lucida Console, monospace\">&nbsp; 1 ---<br \/>\n&nbsp; 2 - name: Basic Playbook<br \/>\n&nbsp; 3 &nbsp; hosts: site_a<br \/>\n&nbsp; 4 &nbsp; connection: local<br \/>\n&nbsp; 5 <br \/>\n&nbsp; 6 &nbsp; tasks:<br \/>\n&nbsp; 7 &nbsp; - name: Get Interface Brief<br \/>\n&nbsp; 8 &nbsp; &nbsp; ios_command:<br \/>\n&nbsp; 9 &nbsp; &nbsp; &nbsp; commands:<br \/>\n&nbsp;10 &nbsp; &nbsp; &nbsp; &nbsp; - show ip interface brief | e una<br \/>\n&nbsp;11 &nbsp; &nbsp; register: interfaces<br \/>\n&nbsp;12 <br \/>\n&nbsp;13 &nbsp; - name: Print results<br \/>\n&nbsp;14 &nbsp; &nbsp; debug:<br \/>\n&nbsp;15 &nbsp; &nbsp; &nbsp; msg: &quot;{{ interfaces.stdout[0] }}<\/div><\/div> <\/pre>\n<figure><img decoding=\"async\" src=\"https:\/\/www.sickgaming.net\/blog\/wp-content\/uploads\/2020\/07\/automating-network-devices-with-ansible.png\" alt=\"Without Debug\" \/><\/figure>\n<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/www.sickgaming.net\/blog\/wp-content\/uploads\/2020\/07\/automating-network-devices-with-ansible-1.png\" alt=\"With Debug\" \/><\/figure>\n<\/p>\n<p>The above images show the differences without and with the debug module respectively.<\/p>\n<p>Let&#8217;s break the playbook into three blocks, starting with lines 1 to 4.<\/p>\n<ul>\n<li>The three dashes\/hyphens starts the YAML document<\/li>\n<li>The hosts defines the hosts or host groups, multiple groups are comma-separated<\/li>\n<li>Connection defines the methodology to connect to the network devices. Another option is network_cli (recommended method) and will be used later in this article. See <a href=\"https:\/\/docs.ansible.com\/ansible\/latest\/network\/user_guide\/platform_ios.html\">IOS Platform Options<\/a> for more details.<\/li>\n<\/ul>\n<p>Lines 6 to 11 starts the tasks, we will be using <a href=\"https:\/\/docs.ansible.com\/ansible\/latest\/modules\/ios_command_module.html\">ios_command<\/a> and <a href=\"https:\/\/docs.ansible.com\/ansible\/latest\/modules\/ios_config_module.html\">ios_config<\/a>. This play will execute the show command <em>show ip interface brief | e una<\/em> and save the output from the command into the interfaces variable, with the register key.<\/p>\n<p>Lines 13 to 15, by default, when you execute a show command you will not see the output, though this is not used during automation. It is very useful for debugging; therefore, the debug module was used.<\/p>\n<p>The below video shows the execution of the playbook. There are a couple of ways you can execute the playbook.<\/p>\n<ul>\n<li>Passing arguments to the command line, for example, include <em>-u &lt;username&gt;<\/em> <em>-k<\/em> to prompt for the remote user credentials<\/li>\n<\/ul>\n<pre> <div class=\"codecolorer-container text default\" style=\"overflow:auto;border:1px solid #9F9F9F;width:435px\"><div class=\"text codecolorer\" style=\"padding:5px;font:normal 12px\/1.4em Monaco, Lucida Console, monospace\">ansible-playbook -i inventory show_demo.yaml -u admin -k<\/div><\/div> <\/pre>\n<ul>\n<li>Include the credentials in the host or group vars<\/li>\n<\/ul>\n<pre> <div class=\"codecolorer-container text default\" style=\"overflow:auto;border:1px solid #9F9F9F;width:435px\"><div class=\"text codecolorer\" style=\"padding:5px;font:normal 12px\/1.4em Monaco, Lucida Console, monospace\">ansible-playbook -i inventory show_demo.yaml<\/div><\/div> <\/pre>\n<\/div>\n<div class=\"wp-block-jetpack-markdown\">\n<blockquote>\n<p>Never store passwords in plain text. We recommend using SSH keys to authenticate SSH connections. Ansible supports ssh-agent to manage your SSH keys. If you must use passwords to authenticate SSH connections, we recommend encrypting them with<br \/>\n<a href=\"https:\/\/docs.ansible.com\/ansible\/latest\/user_guide\/playbooks_vault.html#playbooks-vault\">Using Vault in Playbooks<\/a><\/p>\n<\/blockquote>\n<\/div>\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/fedoramagazine.org\/wp-content\/uploads\/2020\/06\/Screencast-from-25-06-20-100214.webm\"><\/video><figcaption>Passing arguments to the command line<\/figcaption><\/figure>\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/fedoramagazine.org\/wp-content\/uploads\/2020\/06\/Screencast-from-25-06-20-100811.webm\"><\/video><figcaption>Credentials in the inventory<\/figcaption><\/figure>\n<p>If we want to save the output to a file, we will use the copy module as shown in the playbook below. In addition to using the copy module, we will include the <em>backup_dir<\/em> variable to specify the directory path.<\/p>\n<div class=\"wp-block-jetpack-markdown\">\n<pre> <div class=\"codecolorer-container text default\" style=\"overflow:auto;border:1px solid #9F9F9F;width:435px\"><div class=\"text codecolorer\" style=\"padding:5px;font:normal 12px\/1.4em Monaco, Lucida Console, monospace\">---<br \/>\n- name: Get System Infomation<br \/>\n&nbsp; hosts: site_a<br \/>\n&nbsp; connection: network_cli<br \/>\n&nbsp; gather_facts: no<br \/>\n&nbsp; <br \/>\n&nbsp; vars:<br \/>\n&nbsp; &nbsp; backup_dir: \/home\/eramirez\/dev\/ansible\/fedora_magazine<br \/>\n&nbsp; <br \/>\n&nbsp; tasks:<br \/>\n&nbsp; - name: get system interfaces<br \/>\n&nbsp; &nbsp; ios_command:<br \/>\n&nbsp; &nbsp; &nbsp; commands:<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; - show ip int br | e una<br \/>\n&nbsp; &nbsp; register: interface<br \/>\n&nbsp; &nbsp; <br \/>\n&nbsp; - name: Save result to disk<br \/>\n&nbsp; &nbsp; copy:<br \/>\n&nbsp; &nbsp; &nbsp; content: &quot;{{ interface.stdout[0] }}&quot;<br \/>\n&nbsp; &nbsp; &nbsp; dest: &quot;{{ backup_dir }}\/{{ inventory_hostname }}.txt&quot;<\/div><\/div> <\/pre>\n<p>To demonstrate the use of variables in the inventory, we will use plain text. This method <strong>Must<\/strong> not be used in production.<\/p>\n<pre> <div class=\"codecolorer-container text default language-yaml\" style=\"overflow:auto;border:1px solid #9F9F9F;width:435px\"><div class=\"text codecolorer\" style=\"padding:5px;font:normal 12px\/1.4em Monaco, Lucida Console, monospace\">[site_a]<br \/>\nCore_A ansible_host=192.168.122.200<br \/>\nDistro_A ansible_host=192.168.122.201<br \/>\nDistro_B ansible_host=192.168.122.202<br \/>\n[all:vars]<br \/>\nansible_connection=network_cli<br \/>\nansible_network_os=ios<br \/>\nansible_user=admin<br \/>\nansible_password=fedora<br \/>\nansible_become=yes<br \/>\nansible_become_password=yes<br \/>\nansible_become_method=enable<\/div><\/div> <\/pre>\n<\/div>\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/fedoramagazine.org\/wp-content\/uploads\/2020\/06\/Screencast-from-24-06-20-234555.webm\"><\/video><\/figure>\n<h3>Write Operations<\/h3>\n<div class=\"wp-block-jetpack-markdown\">\n<p>In the previous section, we saw that we could get information from the network devices; in this section, we will write (add\/modify) the configuration on these network devices. To make changes to the network device, we will be using the <a href=\"https:\/\/docs.ansible.com\/ansible\/latest\/modules\/ios_config_module.html\">ios config<\/a> module.<\/p>\n<\/div>\n<div class=\"wp-block-jetpack-markdown\">\n<p>Let us create a playbook to configure a couple of interfaces in all of the network devices in site_a. We will first take a backup of the current configuration of all devices in site_a. Lastly, we will save the configuration.<\/p>\n<pre> <div class=\"codecolorer-container text default language-yaml\" style=\"overflow:auto;border:1px solid #9F9F9F;width:435px;height:300px\"><div class=\"text codecolorer\" style=\"padding:5px;font:normal 12px\/1.4em Monaco, Lucida Console, monospace\">---<br \/>\n- name: Get System Infomation<br \/>\n&nbsp; hosts: site_a<br \/>\n&nbsp; connection: network_cli<br \/>\n&nbsp; gather_facts: no<br \/>\n&nbsp; <br \/>\n&nbsp; vars:<br \/>\n&nbsp; &nbsp; backup_dir: \/home\/eramirez\/dev\/ansible\/fedora_magazine<br \/>\n&nbsp; <br \/>\n&nbsp; tasks:<br \/>\n&nbsp; - name: Backup configs<br \/>\n&nbsp; &nbsp; ios_config:<br \/>\n&nbsp; &nbsp; &nbsp; backup: yes<br \/>\n&nbsp; &nbsp; &nbsp; backup_options:<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; filename: &quot;{{ inventory_hostname }}_running_cfg.txt&quot;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; dir_path: &quot;{{ backup_dir }}&quot;<br \/>\n&nbsp; &nbsp; <br \/>\n&nbsp; - name: get system interfaces<br \/>\n&nbsp; &nbsp; ios_config:<br \/>\n&nbsp; &nbsp; &nbsp; lines:<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; - description Raspberry Pi<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; - switchport mode access<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; - switchport access vlan 100<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; - spanning-tree portfast<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; - logging event link-status<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; - no shutdown<br \/>\n&nbsp; &nbsp; &nbsp; parents: &quot;{{ item }}&quot;<br \/>\n&nbsp; &nbsp; with_items:<br \/>\n&nbsp; &nbsp; &nbsp; - interface FastEthernet1\/12<br \/>\n&nbsp; &nbsp; &nbsp; - interface FastEthernet1\/13<br \/>\n&nbsp; &nbsp; &nbsp; <br \/>\n&nbsp; - name: Save switch configuration<br \/>\n&nbsp; &nbsp; ios_config:<br \/>\n&nbsp; &nbsp; &nbsp; save_when: modified<\/div><\/div> <\/pre>\n<\/div>\n<p>Before we execute the playbook, we will first validate the interface configuration. We will then run the playbook and confirm the changes as illustrated below.<\/p>\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/fedoramagazine.org\/wp-content\/uploads\/2020\/06\/Screencast-from-25-06-20-113943.webm\"><\/video><\/figure>\n<h2>Conclusion<\/h2>\n<p>This article is a basic introduction to whet your appetite that demonstrates how Ansible is used to manage network devices. Ansible is capable of automating a vast network, which includes MPLS routing and performing validation before executing the next task.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ansible is a great automation tool for system and network engineers, with Ansible we can automate small network to a large scale enterprise network. I have been using Ansible to automate both Aruba, and Cisco switches from my Fedora powered laptops for a couple of years. This article covers the requirements and executing a couple [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":115341,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[48],"tags":[706,619,45,61,46,773,47],"class_list":["post-115340","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-fedora-os","tag-ansible","tag-automation","tag-fedora","tag-fedora-project-community","tag-magazine","tag-networking","tag-news"],"_links":{"self":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/115340","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/comments?post=115340"}],"version-history":[{"count":0,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/115340\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/media\/115341"}],"wp:attachment":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/media?parent=115340"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/categories?post=115340"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/tags?post=115340"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}