Now we need to setup the pipline stages in the .gitlab-ci.yml
file. This file acts
as the control file for defining all CI/CD jobs.
We also need to define the test cases that will be used to validate changes to the staging and production environments.
When managing your network with NaC/IaC, adding good test cases is critical. Your test code should be equal to or better than the production code. The main objective for is to validate the code and configuration on a staging environment before deploying it to the production environment. This validation can reduce the chance of an outage dramatically.
In this lab, we will use Ansible validation playbooks for the following:
The validation we do as part of this lab is just a simple example. The validation needed in a real staging and production environment should include as many tests as required in order to ensure that what you are deploying to the production environment will not break your system.
touch ~/workspace/ndfclab/ansible/verify_fabric.yml
cat << EOF > ~/workspace/ndfclab/ansible/verify_fabric.yml
---
- name: Verify Fabric on NDFC
hosts: ndfc
gather_facts: false
tasks:
- name: verify | check if all VRFs are deployed
block:
- name: verify | query all VRFs from {{ fabric_settings.FABRIC_NAME }}
cisco.dcnm.dcnm_rest:
path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{{ fabric_settings.FABRIC_NAME }}/vrfs"
method: GET
register: result
- name: verify | check if status is DEPLOYED
assert:
that:
- item.vrfStatus != "OUT-OF-SYNC"
quiet: true
loop: "{{ result.response.DATA }}"
- name: verify | check if all Networks are deployed
block:
- name: verify | query all Networks from {{ fabric_settings.FABRIC_NAME }}
cisco.dcnm.dcnm_rest:
path: "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{{ fabric_settings.FABRIC_NAME }}/networks"
method: GET
register: result
- name: verify | check if status is DEPLOYED
assert:
that:
- item.networkStatus != "OUT-OF-SYNC"
quiet: true
loop: "{{ result.response.DATA }}"
EOF
We are using the cisco.dcnm.dcnm_rest
module from the collection to query the VRF's and Networks on
NDFC and then using Ansible ansible.builtin.assert
to make sure they are deployed properly and fail if not.
touch ~/workspace/ndfclab/ansible/leaf_devices.stage.yml
cat << EOF > ~/workspace/ndfclab/ansible/leaf_devices.stage.yml
---
# Connection Information For Staging Fabric
#
# This file defines how Ansible will connect to the leaf1
nxos:
children:
stage:
hosts:
10.15.1.12:
ansible_connection: ansible.netcommon.network_cli
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
ansible_python_interpreter: auto_silent
ansible_network_os: cisco.nxos.nxos
ansible_user: admin
ansible_password: cisco.123
EOF
touch ~/workspace/ndfclab/ansible/leaf_devices.prod.yml
cat << EOF > ~/workspace/ndfclab/ansible/leaf_devices.prod.yml
---
# Connection Information For Production Fabric
#
# This file defines how Ansible will connect to the leaf1
nxos:
children:
prod:
hosts:
10.15.1.19:
ansible_connection: ansible.netcommon.network_cli
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
ansible_python_interpreter: auto_silent
ansible_network_os: cisco.nxos.nxos
ansible_user: admin
ansible_password: cisco.123
EOF
.gitlab-ci.yml
in the project root folder.
touch ~/workspace/ndfclab/ansible/.gitlab-ci.yml
code-server -r ~/workspace/ndfclab/ansible/.gitlab-ci.yml
---
variables:
environ: "staging"
stages:
- lint
- deploy
- verify
ansible lint:
stage: lint
image:
name: "cytopia/ansible-lint:5"
entrypoint: [""]
rules:
- if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "stage"'
before_script:
- export ANSIBLE_PERSISTENT_COMMAND_TIMEOUT=1000
- export ANSIBLE_PERSISTENT_CONNECT_TIMEOUT=1000
- export no_proxy="localhost,127.0.0.1,172.25.74.47"
- python3 -m pip install requests
script:
- ansible-galaxy -vvv collection install cisco.dcnm
- ansible-lint -p roles/create_fabric
- ansible-lint -p group_vars/all/overlay.yml
deploy_on_stage:
stage: deploy
image:
name: "cytopia/ansible"
entrypoint: [""]
rules:
- if: $CI_PIPELINE_SOURCE == 'merge_request_event' && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "main"
before_script:
- export ANSIBLE_PERSISTENT_COMMAND_TIMEOUT=1000
- export ANSIBLE_PERSISTENT_CONNECT_TIMEOUT=1000
- python3 -m pip install requests
- python3 -m pip install jmespath
script:
- ansible-playbook --version
- ansible-galaxy -vvv collection install cisco.dcnm
- ansible-playbook -i hosts.stage.yml build_fabric.yml
verify_on_stage:
stage: verify
image:
name: "cytopia/ansible"
entrypoint: [""]
rules:
- if: $CI_PIPELINE_SOURCE == 'merge_request_event' && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "main"
before_script:
- export ANSIBLE_HOST_KEY_CHECKING=False
- python3 -m pip install requests
- python3 -m pip install paramiko
script:
- sleep 10
- ansible-playbook --version
- ansible-galaxy -vvv collection install cisco.dcnm
- ansible-playbook -i hosts.stage.yml verify_fabric.yml
deploy_on_prod:
stage: deploy
image:
name: "cytopia/ansible"
entrypoint: [""]
rules:
- if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "main"'
before_script:
- export ANSIBLE_PERSISTENT_COMMAND_TIMEOUT=1000
- export ANSIBLE_PERSISTENT_CONNECT_TIMEOUT=1000
- python3 -m pip install requests
- python3 -m pip install jmespath
script:
- ansible-playbook --version
- ansible-galaxy -vvv collection install cisco.dcnm
- ansible-playbook -i hosts.prod.yml build_fabric.yml
verify_on_prod:
stage: verify
image:
name: "cytopia/ansible"
entrypoint: [""]
rules:
- if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "main"'
before_script:
- export ANSIBLE_HOST_KEY_CHECKING=False
- python3 -m pip install requests
- python3 -m pip install paramiko
script:
- sleep 10
- ansible-playbook --version
- ansible-galaxy -vvv collection install cisco.dcnm
- ansible-playbook -i hosts.prod.yml verify_fabric.yml
After successfully populating the file above, save the file using Ctrl+s on the Windows keyboard or by clicking File then Save.
Be sure to save your file! Not saving will result in your code not executing.
All of these stages run in a docker container that are built with the ansible-lint, ansible-playbook and ansible-galaxy binaries.
We will tigger the various pipeline stages in the next section.