Giter VIP home page Giter VIP logo

anit's Introduction

Ansible Network Infrastructure Testing (ANIT)

Introduction

ANIT is a framework to show how traditional unittesting concepts can be applied to the process of generating Cisco network configuration files when using Ansible. All examples provided focus on having a robust templating framework for Cisco device management.

Not only will this testing approach allow a user to verify that different data files (YAML) render the proper expected CLI network configurations using the same or different Jinja templates, it will do so across different versions of both Python and Ansible.

In other words, it'll verify your network YAML data (the YAML files), Jinja template(s), Python version, and Ansible version won't break the configuration being built and deployed to network infrastructure. This comes in to be super handy to test various YAML data structures to ensure your Jinja logic is sound and accounts for both required and optional variables in the data.

The project uses nox, a Python testing framework. It's similar to tox, but uses a Python-based config file allowing for maximum flexibility. You would trigger nox via Jenkins or Travis if you choose to use this framework.

Using ANIT

  1. Install nox in your Python 3.6+ environment.
  2. Determine a feature you're testing, e.g BGP, VLANs, interfaces, OSPF
  3. Create a sub-directory with the feature name inside the tests directory
  4. Create test cases: create as many sub-directories inside the feature directory equal to the number of tests for that feature, e.g. the number of data files and/or templates needed to test. The names of these sub-directories could be a descriptive name or something like test_01, test_02 as shown in the repository.
  5. Create a Jinja template and at a minimum, place it in the templates directory named {{ feature }}.j2, e.g. vlans.j2. More on the template directory structure below.
  6. In each test sub-directory (test01 as an example), create data.yml and expected_config.cfg. data.yml is a YAML file of the data used in your Jinja template for that feature. It must also include a meta key that includes os and vendor attributes. The expected_config.cfg is the CLI commands that should get generated from the data and Jinja2 template. All data files will be rendered with the template in the previous step. This is based on N data files and 1 Jinja template. Optionally, you can add a Jinja template per test case in this directory, also called {{ feature }}.j2. This template will take priority over one with the same in the templates directory.
  7. Edit noxfile.py with the versions of Python and Ansible you want to test against.
  8. Execute your tests by

(a) Running nox (to test all environments)

(b) Running ansible-playbook -i localhost pb_test_configs.yml to test in your working environment.

If you run the playbook locally, you can just view the job-summary.txt generated. However, since nox uses Python venv's, we also write all job summaries to /tmp/ntc. You'll see files like this get generated: 2019-05-10-16-18-24-ansible2.6.4-python-job-summary.txt. It will be a file per test permutation. So, if you're testing 3 versions of Python and 3 versions of Ansible, you'll have 9 tests executed and 9 test reports generated.

Note: nox requires Python 3.6+ while it can still test Python 2 virtual environments.

For each playbook that runs, it generates a job-summary.txt that looks like this:

(noxy) ntc@ntc:ansible-build-test (master)$ cat job-summary.txt 
Configuration Build Testing Job Summary
   -> Ansible Version: 2.7.10
   -> Python Version: python3.6
-------------------------------------------------------------

**INFO: FEATURE bgp        TEST: test_01    ---------> PASSED    
**INFO: FEATURE bgp        TEST: test_02    ---------> PASSED    
**INFO: FEATURE vlans      TEST: test_01    ---------> PASSED    
**INFO: FEATURE vlans      TEST: test_02    ---------> FAILED    
--- tests/vlans/test_02/expected_config.cfg
+++ outputs/vlans/test_02/generated_config.cfg
@@ -2,5 +2,5 @@
   name web
 vlan 20
   name app
-vlan 30
+vlan 300
   name db
**INFO: FEATURE vlans      TEST: test_03    ---------> FAILED    
AnsibleUndefinedVariable: 'dict object' has no attribute 'name'

Summary: 5 data files tested

This tells us that the VLANs test_02 and test_03 failed.

If we show that actual data (also in the repository), you'd see this:

(noxy) ntc@ntc:ansible-build-test$ tree tests/vlans/test_02/
tests/vlans/test_02/
├── data.yml
└── expected_config.cfg

0 directories, 2 files
(noxy) ntc@ntc:ansible-build-test$

The bad data:

(noxy) ntc@ntc:ansible-build-test$ cat tests/vlans/test_02/data.yml      
---

meta:
  os: ios
  vendor: cisco

vlans:
  - id: 10
    name: web
  - id: 20
    name: app
  - id: 300
    name: db
(noxy) ntc@ntc:ansible-build-test$

The expected config:

(noxy) ntc@ntc:ansible-build-test$ cat tests/vlans/test_02/expected_config.cfg 
vlan 10
  name web
vlan 20
  name app
vlan 30
  name db
(noxy) ntc@ntc:ansible-build-test$ 

The results from test_02, which is shown in the job summary:

(noxy) ntc@ntc:ansible-build-test $ cat outputs/vlans/test_02/test_results.cfg  
--- tests/vlans/test_02/expected_config.cfg
+++ outputs/vlans/test_02/generated_config.cfg
@@ -2,5 +2,5 @@
   name web
 vlan 20
   name app
-vlan 30
+vlan 300
   name db

The template being used to generate the config and compared against the expected config:

(noxy) ntc@ntc:ansible-build-test$ cat templates/vlans.j2 
{% for vlan in vlans %}
vlan {{ vlan['id'] }}
  name {{ vlan['name'] }}
{% endfor %}
(noxy) ntc@ntc:ansible-build-test$ 

test02 is showing bad data while test03 is showing the output when there is a bad template.

Creating Templates

In Step 6 above, it stated you must at a minimum store a feature template in templates. However, this test framework is much more robust because in production, you definitely will not have a single templates directory.

Here is an example tree output from the directory structure:

(noxy) ntc@ntc:ansible-build-test (master)$ tree templates/
templates/
├── cisco
│   ├── defaults
│   │   ├── bgp.j2
│   │   └── vlans.j2
│   ├── ios
│   │   ├── catalyst
│   │   │   └── 6500
│   │   │       ├── 6509
│   │   │       └── defaults
│   │   └── defaults
│   └── nxos
│       └── nexus
│           ├── 7000
│           │   └── defaults
│           │       └── vdc.j2
│           ├── 9000
│           │   ├── 9396
│           │   └── defaults
│           └── defaults
└── report.j2

16 directories, 4 files

Given Cisco has many OS types, product families, and hardware/software models, you wouldn't want to have duplicate templates and ideally have complex templates. One approach as shown here is to have a well-designed template directory structure that offers as much flexibility as possible.

This structure and project will search for templates (in priority order):

  1. Template Specific to the test case
  2. Model Templates
  3. Family Templates
  4. Platform Templates
  5. OS Templates
  6. Cisco (or Vendor) Templates
  7. Generic template found in the templates directory

This can be seen more clearly with the specific task in the tasks file:

  - name: "{{ feature | upper }}: {{ test_name | upper }}-> GENERATE {{ feature | upper }} CONFIG"
    template:
      src: "{{ template }}"
      dest: ./{{ test_path }}/generated_config.cfg
    with_first_found:
      - "{{ test_dir }}/{{ feature }}/{{ test_name }}/{{ feature }}.j2"
      - "templates/{{ meta['vendor'] }}/{{ meta['os'] }}/{{ platform }}/{{ family }}/{{ model }}/{{ feature }}.j2"
      - "templates/{{ meta['vendor'] }}/{{ meta['os'] }}/{{ platform }}/{{ family }}/defaults/{{ feature }}.j2"
      - "templates/{{ meta['vendor'] }}/{{ meta['os'] }}/{{ platform }}/defaults/{{ feature }}.j2"
      - "templates/{{ meta['vendor'] }}/{{ meta['os'] }}/defaults/{{ feature }}.j2"
      - "templates/{{ meta['vendor'] }}/defaults/{{ feature }}.j2"
      - "{{ feature }}.j2"
    loop_control:
      loop_var: template
    ignore_errors: true
    register: template_status

TODO

  • Explore the use of testinfra and pytest-ansible.

anit's People

Contributors

eckelcu avatar jathanism avatar jedelman8 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

anit's Issues

Job Summary: Show results for all Ansible/Python versions

It appears the job-summary.txt only shows the last run rather than results from each version tested. I think it would be valuable to have it include all the results from the different versions tested. Currently, those individual runs are stored in /tmp/ntc

I can submit a PR if this would be accepted.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.