Strony

Sunday, 20 May 2018

Using Ansible for generating configuration files

In this post I want to write about how Ansible and Jinja2 templates can be utilised for generating configuration files (sample configuration for network devices will be prepared).

Topics which will be covered:
- preparation of Ansible files for config generation (Jinja2 template, playbook, inventory, files with variables)
- preparation of Docker container with Ansible installed

Prerequisites:
- Docker container environment (Docker host needs to have Internet access)

1. Scenario description

Scenario for which configuration files will be generated:

Two datacenters are present:
- DatacenterA
- DatacenterB

Configuration which should be present on every device, regardless in which datacenter device is located:
- vlan 1 and vlan 2
- L2 interfaces ethernet3 and ethernet4 configured for tagged traffic ('switchport mode trunk' command)

Configuration specific to datacenter (every device in specific datacenter should have that settings applied):
- ntp server IP (10.10.10.10 for DatacenterA, 192.168.10.10 for DatacenterB)
- presence of specific vlan (vlan 10 in DatacenterA, vlan 20 in DatacenterB)

Configuration specific for each device:
- IP addresses on L3 interfaces

One device is present in each datacenter:
- DatacenterA_Device01
- DatacenterB_Device01

2. Files and folders

Directory and file structure which need to be prepared prior to building container:
[test@localhost for_docker]$ tree -f -i
.
./ansible_template
./ansible_template/Dockerfile
./ansible_template/src
./ansible_template/src/configs
./ansible_template/src/config_template.j2
./ansible_template/src/generate_config_playbook.yaml
./ansible_template/src/group_vars
./ansible_template/src/group_vars/all
./ansible_template/src/group_vars/DatacenterA
./ansible_template/src/group_vars/DatacenterA/DatacenterA
./ansible_template/src/group_vars/DatacenterB
./ansible_template/src/group_vars/DatacenterB/DatacenterB
./ansible_template/src/host_vars
./ansible_template/src/host_vars/DatacenterA_Device01
./ansible_template/src/host_vars/DatacenterB_Device01
./ansible_template/src/inventory

7 directories, 9 files
Note: empty folder "configs" needs to be created

Content of file "Dockerfile" (file used for building container):
[test@localhost ansible_template]$ cat Dockerfile
FROM centos:centos7

RUN yum -y update; yum clean all
RUN yum -y install epel-release; yum clean all
RUN yum -y install gcc python python-devel python-pip openssh-clients ; yum clean all

RUN pip install --upgrade pip
RUN pip install ansible

RUN mkdir /config_generation
COPY ./src/ /config_generation/

WORKDIR config_generation

CMD ["sleep","10000000"]


Content of file "config_template.j2" (Jinja2 template used for building configuration file):
[test@localhost src]$ cat config_template.j2
hostname {{ inventory_hostname }}

ntp server {{ ntp_server }}

{% for vlan in vlans %}
vlan {{ vlan.id }}
 name {{ vlan.name }}
{% endfor %}

{% for vlan in common_vlans %}
vlan {{ vlan.id }}
 name {{ vlan.name }}
{% endfor %}

{% for interface in L3_interfaces %}
interface {{ interface.name }}
 description L3 interface
 address {{ interface.address }}
{% endfor %}

{% for interface in L2_tagged_interfaces %}
interface {{ interface.name }}
 description L2 tagged interface, all vlans allowed
 switchport mode trunk
{% endfor %}


Content of file "generate_config_playbook.yaml" (Ansible playbook for building configuration file based on template):
[test@localhost src]$ cat generate_config_playbook.yaml
- name: Generate configuration from template
  hosts: all
  gather_facts: no
  connection: local
  tasks:
    - name: Config file generation example
      template:
        src: ./config_template.j2
        dest: ./configs/{{ inventory_hostname}}_config.txt


Content of file "inventory":
[test@localhost src]$ cat inventory
[all]
DatacenterA_Device01
DatacenterB_Device01

[DatacenterA]
DatacenterA_Device01

[DatacenterB]
DatacenterB_Device01


Content of file "all" (variables common for every device regardless of datacenter):
[test@localhost group_vars]$ cat all
common_vlans:
 - id: 1
   name: common vlan which is present in both datacenters
 - id: 2
   name: common vlan which is present in both datacenters
L2_tagged_interfaces:
 - name: ethernet3
 - name: ethernet4


Content of file "DatacenterA" (variables for devices in DatacenterA):
[test@localhost DatacenterA]$ cat DatacenterA
ntp_server: 10.10.10.10
vlans:
 - id: 10
   name: specific vlan for DatacenterA


Content of file "DatacenterB" (variables for devices in DatacenterB):
[test@localhost DatacenterB]$ cat DatacenterB
ntp_server: 192.168.10.10
vlans:
 - id: 20
   name: specific vlan for DatacenterB


Content of file "DatacenterA_Device01" (variables for specific device DatacenterA_Device01):
[test@localhost host_vars]$ cat DatacenterA_Device01
L3_interfaces:
 - name: ethernet1
   address: 10.1.1.1 255.255.255.0
 - name: ethernet2
   address: 10.1.2.1 255.255.255.0


Content of file "DatacenterB_Device01" (variables for specific device DatacenterB_Device01):
[test@localhost host_vars]$ cat DatacenterB_Device01
L3_interfaces:
 - name: ethernet1
   address: 192.168.1.1 255.255.255.0
 - name: ethernet2
   address: 192.168.2.1 255.255.255.0


3. Preparing docker container
 
Next docker image with Ansible will be build. Command need to be executed from within prepared folder "ansible_template" .
sudo docker build -f Dockerfile -t "ansible_template" .

When docker image is ready, docker container can be launched:
sudo docker run -d -t ansible_template

Command for retrieving id of launched docker container:
sudo docker ps

Command for accessing shell of launched container (value of container_id, need to be retrieved using "sudo docker ps" command):
sudo docker exec -i -t container_id /bin/bash

Command for running ansible playbook from within prepared container (command need to be run from folder /config_generation, generated configuration files will be placed in folder /config_generation/configs )
ansible-playbook generate_config_playbook.yaml -i inventory

Example output:

Configuration generation:


Generated configuration file for device DatacenterA_Device01:


Generated configuration file for device DatacenterB_Device01:


No comments:

Post a Comment