Taking regular snapshots of device configuration is something everyone hopefully does, but having them in a version control system as text files provides all the benefits of a full revision history. Depending on the front-end you might even get good looking diffs, and all that for very little effort!

For many of us git is the tool of choice these days, but as you will see below, due to the lack of any built in module that does this in ansible, you can just substitute the commands for whatever version control system you have in house.

First of all we need to pull the configuration in some way. The example in this playbook uses the nxos_facts module to pull the config and then saves it to disk using the copy module. While we could use the nxos_config module's backup option, it currently (as of 2.7) does not allow for customization of the path or the filename under which the backup is made. It saves the file with a timestamp in its name in a backup folder where the playbook is run. This is unfortunately no good for our purposes, as we need a constant filename (so git can track changes) and a configurable folder where the git repo is located.

  hosts: n9k
  tags: fetch

    - name: get nxos facts via ssh
          - config

    - name: save running-config to file
      local_action: copy content={{ ansible_net_config }} dest={{ local_git_repo_path }}/{{ ansible_net_hostname }}.txt

NOTE: Ensure that the path exists and is an actual git repo beforehand - the playbook's goal is to make backups, so it assumes the necessary repository is already in place (you could write another playbook to set things up in the beginning). In our case /tmp/git/ is the repository and it's defined as a variable in the ansible inventory.

Now that we have all the configs, we run a second play locally (only once, for localhost!), in order to get the files ready and commit them to the repository:

  • we need to remove the timestamp added at the beginning of the running-config file which causes every config pull to count as a change (don't want to pollute the repository when nothing really has changed)
  • then we just add all the files (identify them as you wish) in the n9k folder and commit them with a timestamped message (not really needed as git already has timestamps, so it's up to you)
  • if there's no changed file, the commit command will fail as there's nothing to actually commit, but that's fine (it's handled in the shell commands)
  hosts: localhost
  connection: local
  tags: git

    - name: remove commented lines with timestamps
      # Cisco/NXOS specific - avoid timestamp from always marking config as changed
      shell: |
        sed -i -e '/^!Time/d' {{ local_git_repo_path }}/*.txt
        warn: no

    - name: commit changes to git
      shell: |
        git add .
        git commit -m "Config snapshot taken $(date +"%Y-%m-%d %H:%M:%S")"
        # Needed as git commit will fail if there are no changed files
        exit 0
        chdir: "{{ local_git_repo_path }}"

The output is from running cfg_backup.yml against the lab set up in the NX-OSv 9000 Automation (3) post. After the first run, on an empty repo:

> cd /tmp/git/
> tree
└── n9k
    ├── n9k1.txt
    ├── n9k2.txt
    └── n9k3.txt

> git log
* 78d31a4 (HEAD -> master) Config snapshot taken 2019-02-15 18:31:51

Make some changes, run the playbook again.

> ansible-playbook config_backup.yml -l n9k1,localhost

PLAY [FETCH CONFIGURATION FROM N9K DEVICES] *******************************

TASK [get nxos facts via ssh] *********************************************
ok: [n9k1]

TASK [save running-config to file] ****************************************
changed: [n9k1 -> localhost]

PLAY [COMMIT CONFIGURATION CHANGES TO GIT] ********************************

TASK [remove commented lines with timestamps] *****************************
changed: [localhost]

TASK [commit changes to git] **********************************************
changed: [localhost]

PLAY RECAP ****************************************************************
localhost                  : ok=2    changed=2    unreachable=0    failed=0
n9k1                       : ok=2    changed=1    unreachable=0    failed=0

> git log

* e2aa243 (HEAD -> master) Config snapshot taken 2019-02-15 18:34:19
* 78d31a4 Config snapshot taken 2019-02-15 18:31:51

Once a few changes are in, we can diff the various revisions and see what/when changed. I'm showing the CLI git diff command here, but there are plenty of nice GUI/Web git clients out there for a better diffing experience.

> git diff 78d31a4

diff --git a/n9k/n9k1.txt b/n9k/n9k1.txt
index dda82b4..9674a47 100644
--- a/n9k/n9k1.txt
+++ b/n9k/n9k1.txt
@@ -12,6 +12,7 @@ vdc n9k1 id 1
   limit-resource m6route-mem minimum 8 maximum 8

 feature nxapi
+feature lldp

 no password strength-check

You can find all the code in my NXOS9000v Automation GitHub under Part 3.

NOTE: there's no one right way of doing this, and here's a quick example why: I've had this post in my drafts for about a year and now that I decided to finally publish it, I had two rewrite part of the playbook to adapt for changes in Ansible. Tools evolve all the time!

And, as always, thanks for reading.

Any comments? Contact me via Twitter or e-mail.

Share & Subscribe!