In part one we learned how to use Ansible and a data model to represent infrastructure as code. Now it’s time to introduce Git as the central network automation tool to use the advantages that result from working with text files.
I cannot emphasize enough how important this step is to long-term success with an automation initiative. Unversioned files with funny names in a random directory are not the solution.
Git is a software to realize a distributed version control system and needs to be installed on the Ansible control node.
$ sudo yum install git
It is best practice to set up personal information that will be used when changes are committed to the repository.
$ git config --global user.name "nwmichl" $ git config --global user.email "firstname.lastname@example.org"
Version Control With Git
Now back to the syslog configuration example. A new directory named
iac for this little InfrastructureAsCode demo includes the two files we developed in the previous blog post.
[nwmichl@localhost ~]$ tree iac/
As I mentioned before, versioning via file name, like syslog_v1a.yml, is not the right approach. To use git for this task we just need to put our directory under version control,
$ cd ~/iac $ git init Initialized empty Git repository in /home/nwmichl/iac/.git/
tell git about all the file we would like to be tracked,
$ git add . $ git status # On branch master # # Initial commit # # Changes to be commited: # new file: group_vars.yml # new file: syslog.yml
and commit the actual state of those files to the central master branch of the repository. Branches enable further development independant of production code (in the master branch), but we don’t need them at first.
$ git commit -m "Initial commit" [master (root-commit) 668a138] Initial commit 2 files changed, 45 insertions(+) create mode 100644 group_vars.yml create mode 100644 syslog.yml $ git status # On branch master nothing to commit, working directory clean
Wow, I know, that all looks weird the first time and if you search the web for Git tutorials you might be overwhelmed by the possibilities. But believe me, for the purpose of InfraAsCode we only need a very small subset of functions and you will definitely get used to it.
So to recap: With the first three commands
git add . and
git commit we put the directory
iac under version control and Git now takes care about changes using the new special folder
Let’s assume I want to change the syslog.yml playbook, maybe a comment needs improvement. I’d
vi syslog.yml and store the new version via
:wq. The filename didn’t change, of cause, but Git knows that something happend:
[nwmichl@localhost iac]$ git status # On branch master # Changes not staged for commit: # (use "git add ..." to update what will be committed) # (use "git checkout -- ..." to discard changes in working directory) # # modified: syslog.yml # no changes added to commit (use "git add" and/or "git commit -a")
You can also compare all the changes made since the last commit to the repository line by line, where
- indicates a deletion and
+ the new substitute.
$ git diff diff --git a/syslog.yml b/syslog.yml index 45b432e..4a4e529 100644 --- a/syslog.yml +++ b/syslog.yml @@ -1,4 +1,4 @@ -# Playbook realizing declarative syslog configuration +# Playbook realizing declarative syslog configuration with Cisco IOS devices
Because I like what I did there, I commit to a new version of this repo.
$ git add . $ git commit -m "Changed syslog.yml comment" [master 48c60ab] Changed syslog.yml comment 1 file changed, 1 insertion(+), 1 deletion(-)
Git assigns a unique hash value to each version,
48c60ab in this case, to differentiate between them and curates a list of all commits since the initialisation of the repository. Visit
git log to get verbose information of the whole git history.
$ git log --oneline 48c60ab Changed syslog.yml comment 668a138 Initial commit
BTW: Please do yourself and everyone working with your repositories a favour and always use meaningful commit messages! 😉
If you now would like to compare two commits and see all the differences, just use the
git diff command again, this time specifying the two hashes.
$ git diff 48c60ab 668a138 diff --git a/syslog.yml b/syslog.yml index 4a4e529..45b432e 100644 --- a/syslog.yml +++ b/syslog.yml @@ -1,4 +1,4 @@ -# Playbook realizing declarative syslog configuration with Cisco IOS devices +# Playbook realizing declarative syslog configuration
That’s enough to grasp the relevant concept behind git, but it certainly doesn’t hurt to dig a little deeper at times.
GitLab as a Central Repository
Let’s consider the challenge of versioning as solved for now.
The other problem is, that we are only working with a repository local to the Ansible control node and even worse just in the home directory of one user (nwmichl). As most of us are part of a team, we need a way to centrally store all repositories of our automation stack and work collaboratively. This is where hosting platforms like GitHub or GitLab come to the party.
Both solutions provide (free) private projects (GitLab) / repositories (GitHub) or even on-prem installation which is great, because most of us would feel uncomfortable with public hosting of their automation environment, right? For the sake of this blog it will be GitLab, and I use an account for the user NWMichl.
There is no need to create the new private GitLab project using the Web-UI, just push the local repository like this:
$ git push --set-upstream https://gitlab.com/NWMichl/iac.git master Username for 'https://gitlab.com': nwmichl Password for 'https://email@example.com': Counting objects: 7, done. Compressing objects: 100% (7/7), done. Writing objects: 100% (7/7), 1014 bytes | 0 bytes/s, done. Total 7 (delta 1), reused 0 (delta 0) remote: remote: The private project NWMichl/iac was successfully created. remote: remote: To configure the remote, run: remote: git remote add origin https://gitlab.com/NWMichl/iac.git remote: remote: To view the project, visit: remote: https://gitlab.com/NWMichl/iac remote: To https://gitlab.com/NWMichl/iac.git * [new branch] master -> master Branch master set up to track remote branch master from https://gitlab.com/NWMichl/iac.git.
Et voila, a new private project named iac will automagically appear at GitLab. All files are there and, even more important, the complete change history (2 commits).
(Very) Basic Change Workflow
The following example demonstrates how developers usually work together in a collaborative fashion using hosting platforms like GitLab.
Imagine John Ops from the operations department needs to add another syslog receiver because IT security decided it’s time to use a full blown SIEM. He recently followed some cool NetDevOps advocates on Twitter and thus decides to skip the ITIL based service request workflow via ticket and opens an GitLab issue instead, wicked! Because the
iac project is private, he needs access with at least guest permissions, configured under the members section by a project maintainer.
A guest has no access to the repository itself, but can open new issues.
A short time later a notification about a the new issue pops up in the networking teams slack (yes, that’s possible!) and the project owner himself takes care of this task. As he wiped the whole project from his home directory since it is hosted at the central GitLab repository, he first has to download a copy.
$ git clone https://gitlab.com/nwmichl/iac.git Cloning into 'iac'… Username for 'https://gitlab.com': nwmichl Password for 'https://firstname.lastname@example.org': remote: Enumerating objects: 7, done. remote: Counting objects: 100% (7/7), done. remote: Compressing objects: 100% (7/7), done. remote: Total 7 (delta 1), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (7/7), done. $ cd iac/
Now the new syslog receiver according to the GitLab issue has to be added to the
group_vars.yml file, via vim for instance.
syslog_server: 192.168.10.12 10.10.10.10 220.127.116.11
Next, he executes the
syslog.yml playbook once again to configure the new syslog server on all switches.
The play recap looks great, so the GitLab issue can be closed.
But wait, the GitLab repository doesn’t reflect the changes made, the group_vars.yml still misses the new 18.104.22.168 server:
Sure, we’ve forgotten we’re only working with a local copy. So the change has to be committed to the local repository at the Ansible control node to create a new version and pushed to the GitLab repository.
$ git add . $ git commit -m "Add new syslog receiver 22.214.171.124" [master 65f19ca] Add new syslog receiver 126.96.36.199 2 files changed, 1 insertion(+), 3 deletions(-) $ git push origin master Username for 'https://gitlab.com': nwmichl Password for 'https://email@example.com': Counting objects: 7, done. Compressing objects: 100% (4/4), done. Writing objects: 100% (4/4), 373 bytes | 0 bytes/s, done. Total 4 (delta 1), reused 0 (delta 0) To https://gitlab.com/nwmichl/iac.git 48c60ab..65f19ca master -> master
That looks better now and the change workflow has finished.
We learned how to use Git as a version control system and a central repository like GitLab, including a first little glimpse of the collaborative possibilities.
Do you think the configuration part included way too many manual interactions for a network automation solution? Right, that was only for didactic reasons! But relax, in the next blog post I’ll close the loop and show how to fully automate the process, including some testing.
One thought on “Network Infrastructure As Code With Ansible & Git – Part 2”
Very simple and informative description for beginners and those who looks for how to replace legacy workflow with a modern one.