Skip to content

Automation Pipelines with Branch as Code

This guide demonstrates how to implement a working CI/CD pipeline for your Branch as Code project using GitLab. Building on the concepts from Understanding Pipelines, we’ll transform your existing workspace into a production-ready, version-controlled project with automated validation, deployment, and testing capabilities.

Why Implement CI/CD for Network Operations?

Section titled “Why Implement CI/CD for Network Operations?”

In the previous section, you learned about the theoretical benefits of automation pipelines for network operations. Now we’ll put those concepts into practice. By the end of this section, you’ll have:

  • Automated Validation: Every configuration change will be automatically validated against schema and business rules
  • Controlled Deployment: Changes will only deploy after passing all validation checks and manual approval
  • Comprehensive Testing: Post-deployment testing will verify that your intended configuration matches the actual network state
  • Complete Auditability: Every change, test result, and deployment will be tracked and documented

This practical implementation bridges the gap between traditional network change management and modern Infrastructure as Code practices.

In the Code Server environment, you already have your working Branch-as-Code configuration. The next step is to prepare it for version control and CI/CD.

If you’re following along using the dCloud lab, a GitLab instance is already provided. Otherwise, you can use your own GitLab—or any other CI/CD platform—though you will need to adjust the provided CI/CD configuration accordingly.

Your workspace already contains a .gitlab-ci.yml file that implements the four-stage pipeline we discussed:

  1. Prepare Stage: Renders the network templates and all variables
  2. Validate Stage: Verifies the data model correctness
  3. Plan Stage: Performs the planning of resources to be deployed
  4. Deploy Stage: Apply configuration to network devices via Meraki Dashboard
  5. Test Stage: Uses templates in tests/ to verify deployment success

This practical implementation brings the theoretical pipeline concepts into a working automation framework.

Creating a GitLab Project and Preparing Your Workspace

Section titled “Creating a GitLab Project and Preparing Your Workspace”

Understanding Git and GitLab in Network Operations Context

Section titled “Understanding Git and GitLab in Network Operations Context”

Before diving into the setup, it’s important to understand why we’re using Git and GitLab for network configuration management:

Git provides version control - the ability to track every change to your network configuration over time. This means you can:

  • See exactly what changed between any two versions of your network state
  • Rollback to previous configurations if needed
  • Collaborate with team members without conflicts
  • Maintain a complete audit trail of all network changes

GitLab provides the CI/CD platform that automates our pipeline processes:

  • Automatically validates configuration changes before they’re applied
  • Provides controlled deployment workflows with approval gates
  • Runs comprehensive testing after deployments
  • Maintains artifacts and reports for compliance and troubleshooting

This combination transforms network operations from manual, error-prone processes to automated, reliable workflows.

Before you can use version control and create CI/CD pipelines, you need a remote repository to store your code and manage collaboration. So we are going to create a GitLab project. This provides:

  • A central place to store and back up your code
  • Collaboration features for teams
  • Integration with GitLab CI/CD to automate configuration validation, deployment, and testing
  • Visibility and history of all changes made to your project

After you have logged into GitLab you will create a new project.

  • Click Create a project to start a new project

Create Project

  • Choose Create blank project to start with an empty repository. This is ideal for our use case where we will push existing code from the code server.

  • Enter the project name (e.g., branch-as-code)

  • Set visibility to Private (to restrict access to your project to only you and authorized users)

  • Uncheck the Initialize repository with a README option (since you will push your existing code)

  • Click Create project to finalize the project creation.

Create Blank Project

You should see an empty project page with instructions to push existing code. This is where you will connect your code server workspace to this new GitLab project.

Create Project

Step 3: Check if GIT is already initialized

Section titled “Step 3: Check if GIT is already initialized”

When you set up your workspace in the Branch as Code Setup section, you cloned the NetAsCode example repository. This gave you the working code, but it also connected your workspace to the original NetAsCode repository on GitHub.

In the steps, we did disconnect from that repository and connect to your new GitLab project instead. In the previous steps we deleted the .git directory. While there are advanced Git commands to change the repository URL, for better understanding in simple terms we will just initialize a new repository.

First, let’s see what repository is currently connected:

Open the Code Server and navigate to your workspace directory:

Terminal window
cd ~/network-as-code/branch-as-code

Check the current Git remote connection (this shows the repository from the previous setup section):

Terminal window
git remote -v

If you see the following output, you missed the step to remove the .git directory in the previous section:

Terminal window
origin https://github.com/netascode/nac-branch-example (fetch)
origin https://github.com/netascode/nac-branch-example (push)

Delete the GIT directory:

Open the Code Server and navigate to your workspace directory:

Terminal window
cd ~/network-as-code/branch-as-code

Remove the existing Git tracking (this removes the connection to the original NetAsCode repository):

Terminal window
rm -rf .git

Why do this? The .git directory contains all the version control history and remote connections. By removing it, we start with a clean slate for your own project.

Initialize a new Git repository with main as the default branch:

Terminal window
cd ~/network-as-code/branch-as-code
git init --initial-branch=main

What this does: Creates a new Git repository in your current directory. The --initial-branch=main option sets the default branch name to “main” (rather than the older default “master”). This command creates the .git directory and sets up the basic Git structure needed to track changes to your files.

Configure your Git user identity:

Terminal window
git config --global user.name "labuser"
git config --global user.email "labuser@example.com"

What this does: Sets your identity for Git commits. Every commit in Git is associated with an author, and these commands tell Git who you are. The --global flag means this configuration applies to all Git repositories on this system, not just the current one. When you make commits, they’ll be attributed to “labuser” with the email “labuser@example.com”. This information appears in the Git history and is important for collaboration and audit trails.

When working with a GIT repository, it is important to exclude certain files and directories from being tracked in the repository. These are files that could be generated during automation execution, files that are not relevant to be stored that are part of execution, temporary files, or files that contain sensitive information. If you look the repository already contains a .gitignore file, but it is missing some exclusions that we want to show you. Also this step introducues you to the concept of .gitignore files.

evaluate the .gitignore file to exclude test results and temporary files:

Terminal window
*.log
.terraform
.terraform.lock.hcl
terraform.tfstate
terraform.tfstate.backup
workspaces/.terraform
workspaces/.terraform.lock.hcl
workspaces/terraform.tfstate
workspaces/terraform.tfstate.backup
workspaces/merged_configuration.nac.yaml
.env
tflint.hcl
tests/results

If needed, you can add any other files to be excluded. We already provided configuration to exclude all Terraform state and log files, logs, environmental variables, parsed config, test results…

Step 7: Configure remote GIT repository server in GitLab

Section titled “Step 7: Configure remote GIT repository server in GitLab”

Navigate to your GitLab project page, copy the repository URL (e.g., https://gitlab.198.18.133.103.nip.io/labuser/branch-as-code.git)

Copy Repository URL

Go back to your repository on code server and add your GitLab project as the remote repository:

Terminal window
git remote add origin https://gitlab.198.18.133.103.nip.io/labuser/branch-as-code.git

What this does: Connects your local Git repository to the remote GitLab repository. “origin” is the conventional name for your primary remote repository, and this URL tells Git where to push and pull changes. Think of this as linking your local workspace to your GitLab project on the GitLab Server.

Verify the remote was added correctly:

Terminal window
git remote -v

You should see your GitLab URL:

Terminal window
origin https://gitlab.198.18.133.103.nip.io/labuser/branch-as-code.git (fetch)
origin https://gitlab.198.18.133.103.nip.io/labuser/branch-as-code.git (push)

This confirms you’ve successfully switched from the example repository to your own GitLab project!

Add all your project files to Git tracking:

Terminal window
git config http.sslVerify false
git checkout -b main
git add .
git commit -m "Initial commit"

What this does: The git add . command stages all files in your current directory for commit (the . means “everything here”). The git commit command creates a snapshot of your staged changes with a descriptive message. This creates your first commit containing all your Network as Code configuration files, making them part of your Git history.

SSL Note: If you do not have an SSL certificate configured in your environment, you can use http.sslVerify false to turn off SSL certificate verification for Git operations. This is for lab environment ONLY. Do NOT disable SSL certificate in a production environment.

Push your code and set the upstream branch:

Terminal window
git push --set-upstream origin main

What this does: Uploads your local commits to the GitLab repository. The --set-upstream origin main part establishes a tracking relationship between your local main branch and the remote main branch, so future git push and git pull commands know where to send/receive changes.

This streamlined approach ensures you have a clean start with your own GitLab project, avoiding any confusion with existing remotes or Git history.

You will be asked to authenticate. Use your credentials:

GitLab Repository After Push

Since your workspace already contains a .gitlab-ci.yml file, the pipeline should have triggered automatically when you pushed. Let’s verify the setup:

Verify the Push Success: Navigate to your GitLab project in the browser to confirm all files are present.

GitLab Repository After Push

Expected Pipeline Behavior: Since you pushed with a .gitlab-ci.yml file, GitLab will automatically start a pipeline. This first pipeline will likely fail because the CI/CD variables are not configured yet. This is normal and expected.

  • Go to Build > Pipelines in your GitLab project to see the pipeline status
  • The pipeline failure is expected at this point - we’ll fix it by configuring variables next

If you navigate to the log you will see the error that confirms that environment variables are not set.

│ Call to function "provider::utils::yaml_merge" failed: Error reading YAML
│ string: environment variable domain not set.
❌ terraform apply failed.

💡 Understanding Pipeline Triggers:

GitLab automatically triggers pipelines when you push commits that include a .gitlab-ci.yml file. Since your workspace already has this file, the pipeline will run immediately. The initial failure is normal and will be resolved once you configure the required variables.

GitLab CI/CD variables provide a secure way to store sensitive information like credentials and configuration parameters that your pipeline needs to execute. These variables are encrypted and can be masked in logs to prevent accidental exposure.

Why use CI/CD variables instead of storing credentials in code?

  • Security: Credentials are encrypted and separated from your code repository
  • Flexibility: Different environments (dev, staging, production) can use different values
  • Compliance: Sensitive data is not stored in version control history
  • Team Collaboration: Team members can access the pipeline without seeing sensitive credentials

Navigate to your GitLab project and configure the following variables:

In your GitLab project, go to Settings > CI/CD in the left sidebar

Expand the Variables section and click Add variable

Add CI/CD Variable

Understanding protected and masked variables

Section titled “Understanding protected and masked variables”

When working with variables inside of any CI/CD platform, the variables are often classified into categories. This is used to protect the variables from being exposed on execution. When working with a pipeline, the pipeline definition file contains the details of the execution.

The pipeline definition file specifies what is to execute based on branching. As an example, a operator might have permissions as a user of the source code manager ( GitLab ) to create a new branch and make changes to that branch. However, the operator may not have permissions to push changes into the primary or main branches. Those primary or main branches are what is known as protected branches.

By using protected branches, the operator can make changes to the code, but those changes will not be pushed into the main branch until they are approved by a senior operator or some other process is followed during a merge request or pull request. By protecting variables, the source code manager (SCM) doesn’t allow unprotected branches access to those credentials that are marked protected. Even if the automation would execute, it would fail since it has no way to connect to the devices or controllers.

Inside of GitLab, variables are set as:

  • Visible: Variables will be visible in job logs.
  • Masked: Prevents the variable value from being displayed in job logs. Use this for sensitive data like passwords.
  • Masked and hidden: Similar to Masked, but also hides the variable value in the UI.
  • Protected: Restricts the variable to protected branches and tags. Use this for variables that should only be available in production or secure environments.
  • Expand variable reference: $ is treated special for reference (usually always enabled).

Enter the Key and Value for each variable (see table below).

KeyValueVisibilityFlagsPurpose
secret_passwordC1sco12345!!66VisibleExpandPassword to be used
org_nameUnified Branch Learning OrgVisibleExpandYour org name
org_emailyour.email@example.comVisibleExpandEmail used for org password and dashboard access
MERAKI_API_KEYYOUR OWN MERAKI KEYMaskedExpandYour Meraki API Key

It’s best to use a different organization name than in the previous steps so you can see the CI/CD process in full action.

Use the Add variable button for each entry, the variable section should look like below:

Note: You might be asking why we don’t have the variables marked as protected. The reason is because we haven’t configured the protected branch structure for this lab. In a production environment, you would typically have a protected branch (e.g. main) where you would then set the password as protected. In some environments, we also want to mask some variables, but that can make troubleshooting more difficult.

Add CI/CD Variable

💡 Pro Tip: For production environments, consider using different variable values for different branches (development, staging, production) to maintain environment isolation.

Next Steps: Demonstrating Pipeline with Configuration Changes

Section titled “Next Steps: Demonstrating Pipeline with Configuration Changes”

Now that your variables are configured, let’s demonstrate the pipeline’s power by making practical network configuration changes. We’ll uncomment VRF and network configurations that were previously commented out in the remove section, showcasing the complete Infrastructure as Code workflow.

This exercise demonstrates several key Infrastructure as Code principles by implementing declarative configuration where you define the desired state and let automation handle implementation, leveraging version control to track exactly what changes were made and when, ensuring automated validation to verify changes are valid before deployment, providing controlled deployment that applies changes only after validation and approval, and including comprehensive verification to confirm changes were applied correctly. This practical demonstration bridges the theoretical concepts with real-world network operations management.

Step 12: Uncomment or Modify Network Configuration

Section titled “Step 12: Uncomment or Modify Network Configuration”

Let’s make a minor modification to demonstrate the pipeline workflow. You can choose to modify some of the settings in the variable file:

Uncomment or add VRF configuration:

Terminal window
code-server data/pods_variables.nac.yaml

Modify the Syslog server IP in first branch:

- name: Unified Branch 1
...
syslog_server: 3.4.5.7
...

Save the file after the change.

The first command you will run is git status to check what files have changed since your last commit. This is a command that you will run often when working with GIT. It shows you which files have been modified, added, or deleted in your working directory and also notifies you of new files that are not yet tracked by GIT. If you where to create a new file, it would show up as an untracked file. This means you would first have to add the file with git add <filename> before you can add it in the repository.

Terminal window
git status

The git diff command shows you the exact line-by-line changes you made to specific files. This is useful to review your changes before committing them. You can run git diff on the specific files you modified, such as the VRF and network configuration files.

Terminal window
git diff data/pods_variables.nac.yaml

The git commit command creates a new snapshot of your changes with a descriptive message explaining what changed and why. With the -a flag, it automatically stages all modified files for commit. The -m flag allows you to provide a commit message directly in the command. It is a good practice to write clear and concise commit messages that explain the purpose of the change. Bad commit messages can make it difficult to understand the history of your project and the reasons behind changes.

Terminal window
git commit -a -m "Deploy Unified Branch"

Finally after you have done the commit, you will push your changes to the remote GitLab repository. This uploads your new commit to GitLab, which automatically triggers the CI/CD pipeline defined in your .gitlab-ci.yml file.

Terminal window
git push origin main

You may be asked to authenticate with your CICD at this point.

Understanding the Git Workflow:

  • git status shows which files have been modified since your last commit
  • git diff displays the exact line-by-line changes you made to specific files
  • git add stages specific files for commit (you can be selective about what to include)
  • git commit creates a new snapshot with a descriptive message explaining what changed and why
  • git push uploads your new commit to GitLab, which automatically triggers the CI/CD pipeline

This workflow ensures every network change is documented, reviewable, and automatically processed through your validation and deployment pipeline.

Navigate to GitLab Pipelines:

  • Go to your GitLab project
  • Click Build > Pipelines
  • You should see a new pipeline triggered by your push

Watch the Four-Stage Process:

Terminal window
⚙️ PREPARE 🔍 VALIDATE PLAN 🚀 DEPLOY 🧪 TEST

Pipeline Stages

Monitor Pipeline Progress: Each stage will run according to the workflow described in Understanding Pipelines. Once the pipeline completes, you will see the status of each stage (success or failure).

Pipeline Progress

You can manually verify the changes in Meraki Dashboard to confirm the pipeline deployment was successful:

Meraki Dashboard Organizations

Meraki Dashboard Networks

The final stage of your CI/CD pipeline uses Robot Framework with the NaC-Test tool to verify that your deployed configuration matches the intended network state. This automated testing provides confidence that your Infrastructure as Code deployment was successful.

A network operator can view the results in two separate ways: through the GitLab pipeline interface or by downloading the test artifacts directly. nac-test provides two outputs during execution: a detailed HTML report and a JUnit-compatible XML file for integration with GitLab. The XML JUnit file is used to display the test results in the GitLab pipeline interface, that is visible if you click on the Tests tab in the pipeline details.

For the HTML report, you can download the test artifacts from the pipeline job details. This provides a comprehensive overview of the test execution, including pass/fail status, execution timeline, and detailed logs for each test case.

  1. Go to your GitLab project
  2. Click on Build > Pipelines in the left navigation menu
  3. Select the completed pipeline you want to review (click on the pipeline status or commit message)
  4. Click on the test-integration job in the test stage (the rightmost stage in your pipeline visualization)
  1. In the test-integration job details, scroll down to find the Job artifacts section on the right side
  2. Click the Download button to get the test results archive (it will download a zip file)
  3. Extract the downloaded zip file to your local machine to review the results

 Test Artifacts

  1. Open the extracted folder and look for these key files:

    • tests/results/report.html - Main test execution report with summary and pass/fail status
    • tests/results/log.html - Detailed test execution log with step-by-step information
    • tests/resultsxunit.xml - JUnit-compatible test results for GitLab integration
    • test_output.txt - Console output from the test execution

 Test Artifacts Path

  1. Open report.html in your web browser to review:
    • Overall test suite summary (passed/failed tests)
    • Individual test case results
    • Execution timeline and statistics
    • Links to detailed logs for failed tests

 Dashboard Test Logs

This report provides a comprehensive overview of how your deployed configuration performed against the expected state defined in your test templates.