Backing and Restoring router configuration

1. Théorie

Backing up router configuration

---
- name: BACKUP ROUTER CONFIGURATIONS
  hosts: cisco
  connection: network_cli
  gather_facts: no

  tasks:
    - name: BACKUP THE CONFIG
      ios_config:
        backup: yes
      register: config_output

The backup parameter of the ios_config module triggers the backup and automatically stores device configuration backups within a backups directory

Cleaning up the backed up configuration

The backed up configuration has 2 lines that should be removed:

Building configuration...

Current configuration with default configurations exposed : 393416 bytes

The lineinfile module is a general purpose module that is used for manipulating file contents.

Cleaning up an exact line match

    - name: REMOVE NON CONFIG LINES
      lineinfile:
        path: "./backup/{{inventory_hostname}}.config"
        line: "Building configuration..."
        state: absent

Matching using a regular expression

    - name: REMOVE NON CONFIG LINES - REGEXP
      lineinfile:
        path: "./backup/{{inventory_hostname}}.config"
        regexp: 'Current configuration.*'
        state: absent

Restoring the configuration

If any out of band changes were made to the device and it needs to be restored to the last known good configuration, we could take the following approach:

  • Copy over the cleaned up configuration to the devices
  • Use vendor provided commands to restore the device configuration

In our example we use the Cisco IOS command config replace. This allows for applying only the differences between running and the copied configuration

---
- name: RESTORE CONFIGURATION
  hosts: cisco
  connection: network_cli
  gather_facts: no

  tasks:
    - name: COPY RUNNING CONFIG TO ROUTER
      command: scp ./backup/{{inventory_hostname}}.config {{inventory_hostname}}:/{{inventory_hostname}}.config

    - name: CONFIG REPLACE
      ios_command:
        commands:
          - config replace flash:{{inventory_hostname}}.config force

Note the use of inventory_hostname to effect host specific changes.

Lab a - Backing up the router configuration

In this realistic scenario, you will create a playbook to back-up Cisco router configurations. In subsequent labs we will use this backed up configuration, to restore devices to their known good state.

Note: Since this is a common day 2 operation for most network teams, you can pretty much re-use most of this content for your environment with minimum changes.

Step 1

Create a new file called backup.yml using your favorite text editor and add the following play definition:

---
- name: BACKUP ROUTER CONFIGURATIONS
  hosts: cisco
  connection: network_cli
  gather_facts: no

Step 2

Use the ios_config Ansible module to write a new task. This task should back up the configuration of all devices defined in cisco group.

The backup parameter automatically creates a directory called backup within the playbook root and saves a time-stamped backup of the running configuration.

Note: Use ansible-doc ios_config or check out docs.ansible.com for help on the module usage.

---
- name: BACKUP ROUTER CONFIGURATIONS
  hosts: cisco
  connection: network_cli
  gather_facts: no

  tasks:
    - name: BACKUP THE CONFIG
      ios_config:
        backup: yes
      register: config_output

Why are we capturing the output of this task into a variable called config_output? Step 5 will reveal this.

Step 3

Go ahead and run the playbook:

ansible-playbook backup.yml

PLAY [BACKUP ROUTER CONFIGURATIONS] *********************************************************************************************************************************************************

TASK [BACKUP THE CONFIG] ********************************************************************************************************************************************************************
ok: [rtr1]
ok: [rtr3]
ok: [rtr4]
ok: [rtr2]

PLAY RECAP **********************************************************************************************************************************************************************************
rtr1                       : ok=1    changed=0    unreachable=0    failed=0   
rtr2                       : ok=1    changed=0    unreachable=0    failed=0   
rtr3                       : ok=1    changed=0    unreachable=0    failed=0   
rtr4                       : ok=1    changed=0    unreachable=0    failed=0   

Step 4

The playbook should now have created a directory called backup. Now, list the contents of this directory:

ls -l backup
total 1544
-rw-rw-r--. 1 student1 student1 393514 Jun 19 12:45 rtr1_config.2018-06-19@12:45:36
-rw-rw-r--. 1 student1 student1 393513 Jun 19 12:45 rtr2_config.2018-06-19@12:45:38
-rw-rw-r--. 1 student1 student1 390584 Jun 19 12:45 rtr3_config.2018-06-19@12:45:37
-rw-rw-r--. 1 student1 student1 390586 Jun 19 12:45 rtr4_config.2018-06-19@12:45:37

Feel free to open up these files using a text editor (vim & nano work as well) to validate their content.

Step 5

Since we will be using the backed up configurations as a source to restore the configuration. Let’s rename them to reflect the device name.

In Step 2 you captured the output of the task into a variable called config_output. This variable contains the name of the backup file. Use the copy Ansible module to make a copy of this file.

---
- name: BACKUP ROUTER CONFIGURATIONS
  hosts: cisco
  connection: network_cli
  gather_facts: no

  tasks:
    - name: BACKUP THE CONFIG
      ios_config:
        backup: yes
      register: config_output

    - name: RENAME BACKUP
      copy:
        src: "{{config_output.backup_path}}"
        dest: "./backup/{{inventory_hostname}}.config"

Step 6

Re-run the playbook.

ansible-playbook backup.yml

PLAY [BACKUP ROUTER CONFIGURATIONS] *********************************************************************************************************************************************************

TASK [BACKUP THE CONFIG] ********************************************************************************************************************************************************************
ok: [rtr3]
ok: [rtr4]
ok: [rtr2]
ok: [rtr1]

TASK [RENAME BACKUP] ************************************************************************************************************************************************************************
changed: [rtr1]
changed: [rtr4]
changed: [rtr2]
changed: [rtr3]

PLAY RECAP **********************************************************************************************************************************************************************************
rtr1                       : ok=2    changed=1    unreachable=0    failed=0   
rtr2                       : ok=2    changed=1    unreachable=0    failed=0   
rtr3                       : ok=2    changed=1    unreachable=0    failed=0   
rtr4                       : ok=2    changed=1    unreachable=0    failed=0   

Step 7

Once again list the contents of the backup directory:

ls -l backup
total 3088
-rw-rw-r--. 1 student1 student1 393514 Jun 19 13:35 rtr1.config
-rw-rw-r--. 1 student1 student1 393514 Jun 19 13:35 rtr1_config.2018-06-19@13:35:14
-rw-rw-r--. 1 student1 student1 393513 Jun 19 13:35 rtr2.config
-rw-rw-r--. 1 student1 student1 393513 Jun 19 13:35 rtr2_config.2018-06-19@13:35:13
-rw-rw-r--. 1 student1 student1 390584 Jun 19 13:35 rtr3.config
-rw-rw-r--. 1 student1 student1 390584 Jun 19 13:35 rtr3_config.2018-06-19@13:35:12
-rw-rw-r--. 1 student1 student1 390586 Jun 19 13:35 rtr4.config
-rw-rw-r--. 1 student1 student1 390586 Jun 19 13:35 rtr4_config.2018-06-19@13:35:13

Notice that the directory now has another backed-up configuration but one that reflects the device’s name.

Step 8

If we were to try and manually restore the contents of this file to the respective device there are two lines in the configuration that will raise errors:

Building configuration...

Current configuration with default configurations exposed : 393416 bytes

These lines have to be “cleaned up” to have a restorable configuration.

Write a new task using Ansible’s lineinfile module to remove the first line.

---
- name: BACKUP ROUTER CONFIGURATIONS
  hosts: cisco
  connection: network_cli
  gather_facts: no

  tasks:
    - name: BACKUP THE CONFIG
      ios_config:
        backup: yes
      register: config_output

    - name: RENAME BACKUP
      copy:
        src: "{{config_output.backup_path}}"
        dest: "./backup/{{inventory_hostname}}.config"

    - name: REMOVE NON CONFIG LINES
      lineinfile:
        path: "./backup/{{inventory_hostname}}.config"
        line: "Building configuration..."
        state: absent

Note: The module parameter line is matching an exact line in the configuration file “Building configuration…”

Step 9

Before we run the playbook, we need to add one more task to remove the second line “Current configuration …etc”. Since this line has a variable entity (the number of bytes), we cannot use the line parameter of the lineinfile module. Instead, we’ll use the regexp parameter to match on regular expressions and remove the line in the file:

---
- name: BACKUP ROUTER CONFIGURATIONS
  hosts: cisco
  connection: network_cli
  gather_facts: no

  tasks:
    - name: BACKUP THE CONFIG
      ios_config:
        backup: yes
      register: config_output

    - name: RENAME BACKUP
      copy:
        src: "{{config_output.backup_path}}"
        dest: "./backup/{{inventory_hostname}}.config"

    - name: REMOVE NON CONFIG LINES
      lineinfile:
        path: "./backup/{{inventory_hostname}}.config"
        line: "Building configuration..."
        state: absent

    - name: REMOVE NON CONFIG LINES - REGEXP
      lineinfile:
        path: "./backup/{{inventory_hostname}}.config"
        regexp: 'Current configuration.*'
        state: absent

Step 10

Now run the playbook.

ansible-playbook backup.yml

PLAY [BACKUP ROUTER CONFIGURATIONS] *********************************************************************************************************************************************************

TASK [BACKUP THE CONFIG] ********************************************************************************************************************************************************************
ok: [rtr2]
ok: [rtr4]
ok: [rtr1]
ok: [rtr3]

TASK [RENAME BACKUP] ************************************************************************************************************************************************************************
changed: [rtr2]
changed: [rtr4]
changed: [rtr3]
changed: [rtr1]

TASK [REMOVE NON CONFIG LINES] **************************************************************************************************************************************************************
changed: [rtr4]
changed: [rtr1]
changed: [rtr2]
changed: [rtr3]

TASK [REMOVE NON CONFIG LINES - REGEXP] *****************************************************************************************************************************************************
changed: [rtr1]
changed: [rtr3]
changed: [rtr2]
changed: [rtr4]

PLAY RECAP **********************************************************************************************************************************************************************************
rtr1                       : ok=4    changed=3    unreachable=0    failed=0   
rtr2                       : ok=4    changed=3    unreachable=0    failed=0   
rtr3                       : ok=4    changed=3    unreachable=0    failed=0   
rtr4                       : ok=4    changed=3    unreachable=0    failed=0   

Step 11

Use an editor to view the cleaned up files. The first 2 lines that we cleaned up in the earlier tasks should be absent:

head -n 10 backup/rtr1.config

!
! Last configuration change at 14:25:42 UTC Tue Jun 19 2018 by ec2-user
!
version 16.8
downward-compatible-config 16.8
no service log backtrace
no service config
no service exec-callback
no service nagle

Note: The head unix command will display the first N lines specified as an argument.

Lab b - Using Ansible to restore the backed up configuration

In the previous lab you learned how to backup the configuration of the 4 cisco routers. In this lab you will learn how to restore the configuration. The backups had been saved into a local directory called backup.

backup
├── rtr1.config
├── rtr1_config.2018-06-07@20:36:05
├── rtr2.config
├── rtr2_config.2018-06-07@20:36:07
├── rtr3.config
├── rtr3_config.2018-06-07@20:36:04
├── rtr4.config
└── rtr4_config.2018-06-07@20:36:06

Our objective is to apply this “last known good configuraion backup” to the routers.

Step 1

On one of the routers (rtr1) manually make a change. For instance add a new loopback interface.

Log into rtr1 using the ssh rtr1 command and add the following:

rtr1#config terminal
Enter configuration commands, one per line.  End with CNTL/Z.
rtr1(config)#interface loopback 101
rtr1(config-if)#ip address 169.1.1.1 255.255.255.255
rtr1(config-if)#end
rtr1#

Now verify the newly created Loopback Interface

rtr1#sh run interface loopback 101
Building configuration...

Current configuration : 67 bytes
!
interface Loopback101
 ip address 169.1.1.1 255.255.255.255
end

rtr1#

Step 2

Step 1 simulates our “Out of process/band” changes on the network. This change needs to be reverted. So let’s write a new playbook to apply the backup we collected from our previous lab to achieve this.

Create a file called restore_config.yml using your favorite text editor and add the following play definition:

---
- name: RESTORE CONFIGURATION
  hosts: cisco
  connection: network_cli
  gather_facts: no

Step 3

Write the task to copy over the previously backed up configuration file to the routers.

---
- name: RESTORE CONFIGURATION
  hosts: cisco
  connection: network_cli
  gather_facts: no

  tasks:
    - name: COPY RUNNING CONFIG TO ROUTER
      command: scp ./backup/{{inventory_hostname}}.config  {{inventory_hostname}}:/{{inventory_hostname}}.config

Note the use of the inventory_hostname variable. For each device in the inventory file under the cisco group, this task will secure copy (scp) over the file that corresponds to the device name onto the bootflash: of the CSR devices.

Step 4

Go ahead and run the playbook.

ansible-playbook restore_config.yml

PLAY [RESTORE CONFIGURATION] *********************************************************

TASK [COPY RUNNING CONFIG TO ROUTER] *************************************************
changed: [rtr1]
changed: [rtr2]
changed: [rtr3]
changed: [rtr4]

PLAY RECAP ***************************************************************************
rtr1                       : ok=1    changed=1    unreachable=0    failed=0   
rtr2                       : ok=1    changed=1    unreachable=0    failed=0   
rtr3                       : ok=1    changed=1    unreachable=0    failed=0   
rtr4                       : ok=1    changed=1    unreachable=0    failed=0   

Step 5

Log into the routers to check that the file has been copied over

Note rtr1.config at the bottom of the bootflash:/ directory

ssh rtr1


rtr1#dir
Directory of bootflash:/

   11  drwx            16384  May 11 2018 21:30:28 +00:00  lost+found
   12  -rw-        380928984  May 11 2018 21:32:05 +00:00  csr1000v-mono-universalk9.16.08.01a.SPA.pkg
   13  -rw-         38305434  May 11 2018 21:32:06 +00:00  csr1000v-rpboot.16.08.01a.SPA.pkg
   14  -rw-             1967  May 11 2018 21:32:06 +00:00  packages.conf
235713  drwx             4096   Jun 4 2018 18:08:56 +00:00  .installer
186945  drwx             4096   Jun 4 2018 18:08:44 +00:00  core
   15  -rw-               58   Jun 4 2018 18:08:30 +00:00  iid_check.log
113793  drwx             4096   Jun 4 2018 18:08:32 +00:00  .prst_sync
73153  drwx             4096   Jun 4 2018 18:08:44 +00:00  .rollback_timer
81281  drwx             4096   Jun 7 2018 22:03:48 +00:00  tracelogs
227585  drwx             4096   Jun 4 2018 18:16:10 +00:00  .dbpersist
130049  drwx             4096   Jun 4 2018 18:09:41 +00:00  virtual-instance
   16  -rw-               30   Jun 4 2018 18:11:05 +00:00  throughput_monitor_params
   17  -rw-            10742   Jun 4 2018 18:16:08 +00:00  cvac.log
   18  -rw-               16   Jun 4 2018 18:11:14 +00:00  ovf-env.xml.md5
   19  -rw-               16   Jun 4 2018 18:11:14 +00:00  .cvac_skip_once
   20  -rw-              209   Jun 4 2018 18:11:15 +00:00  csrlxc-cfg.log
170689  drwx             4096   Jun 4 2018 18:11:16 +00:00  onep
373889  drwx             4096   Jun 8 2018 00:41:04 +00:00  syslog
   21  -rw-               34   Jun 4 2018 18:16:15 +00:00  pnp-tech-time
   22  -rw-            50509   Jun 4 2018 18:16:16 +00:00  pnp-tech-discovery-summary
341377  drwx             4096   Jun 4 2018 18:16:21 +00:00  iox
   23  -rw-           394307   Jun 8 2018 01:26:51 +00:00  rtr1.config

7897378816 bytes total (7073292288 bytes free)
rtr1#

Step 6

Now that the known good configuration is on the destination devices, add a new task to the playbook to replace the running configuration with the one we copied over.

!!! A tester en IOSv !!!

---
- name: RESTORE CONFIGURATION
  hosts: cisco
  connection: network_cli
  gather_facts: no

  tasks:
    - name: COPY RUNNING CONFIG TO ROUTER
      command: scp ./backup/{{inventory_hostname}}.config {{inventory_hostname}}:/{{inventory_hostname}}.config

    - name: CONFIG REPLACE
      ios_command:
        commands:
          - config replace flash:{{inventory_hostname}}.config force

Note: Here we take advantage of Cisco’s archive feature. The config replace will only update the differences to the router and not really a full config replace.

Step 7

Let’s run the updated playbook:

ansible-playbook restore_config.yml

PLAY [RESTORE CONFIGURATION] *********************************************************

TASK [COPY RUNNING CONFIG TO ROUTER] *************************************************
changed: [rtr1]
changed: [rtr3]
changed: [rtr2]
changed: [rtr4]

TASK [CONFIG REPLACE] ****************************************************************
ok: [rtr1]
ok: [rtr2]
ok: [rtr4]
ok: [rtr3]

PLAY RECAP ***************************************************************************
rtr1                       : ok=2    changed=1    unreachable=0    failed=0   
rtr2                       : ok=2    changed=1    unreachable=0    failed=0   
rtr3                       : ok=2    changed=1    unreachable=0    failed=0   
rtr4                       : ok=2    changed=1    unreachable=0    failed=0   

Step 8

Validate that the new loopback interface we added in Step 1 is no longer on the device.

ssh rtr1



rtr1#sh ip int br
Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet1       172.16.165.205  YES DHCP   up                    up      
Loopback0              192.168.1.101   YES manual up                    up      
Loopback1              10.1.1.101      YES manual up                    up      
Tunnel0                10.100.100.1    YES manual up                    up      
Tunnel1                10.200.200.1    YES manual up                    up      
VirtualPortGroup0      192.168.35.101  YES TFTP   up                    up      
rtr1#sh run inter
rtr1#sh run interface Loo
rtr1#sh run interface Loopback 101
                               ^
% Invalid input detected at '^' marker.

rtr1#

You have successfully backed up and restored configurations on your Cisco routers!