This post will be a crash course on using Git.
As a reminder from Part 1, Git is being used to fulfill many of the requirements of a sandbox. It provides documentation, mobility, change management, automation, and consistency. It is an integral part of this guide.
There are plenty of different ways to use Git. You can host your own Git server or you can use one of the many services available. For this example, I’ll be creating a private repository and I’ll be using the Bitbucket service since they offer them for free.
Create a new repository
Go to https://bitbucket.org/ to sign up for a new account. Once your account is created, the first thing you need to do is create a new repository.
Give it whatever name you want. I’ll be using ‘ansible-sandbox’.
Now we need to get the link to the repository. Basically we are going to clone an empty repository to our local system. Click the three dots to the left and click on ‘clone’
Just to avoid any complications with SSH keys, I’m going to use HTTPS for communication. Feel free to use SSH if you want. Copy the displayed URL
First, decide where you want to store all of this. Your VMs will eventually be stored in this same directory. They will be tiny VMs, but still just something to consider when choosing your directory for the project. I’ll be putting everything in ‘C:\Users\me\projects’. Once you are in the directory which you want to put the files, you will use the ‘git clone’ command with that URL you copied earlier.
git clone https://firstname.lastname@example.org/matthew-hickok/ansible-sandbox.git
Ignore the warning. It thinks you are being weird for cloning a repository with no files in it. But the process of cloning a repository does actually do something.
Notice that cloning the repository automatically creates a folder with the name of the repository. Inside that newly created folder is a hidden folder. The hidden folder is named ‘.git’ and contains all of the information related to Git — aside from the actual files you will be working with. Think of it as the configuration files and metadata.
Now let’s run the command ‘git status’ to see what the status of the repository is. You will see that Git is pretty bored. You have no new files to be tracked, no modified files, etc…
Now we’ll add a bogus file just to see how this all works. Type
echo "this is a test file" > my_test_file
And now ‘git status’ again
It detected a new file that is untracked — meaning the file is not in source control and any changes to the file will not be detected or tracked. So let’s add it to source control.
git add .\my_test_file
Now check status again and we’ll see that the file is going to be added to the repository and tracked going forward
Now we want to commit our changes with the following
git commit .\my_test_file
This will bring up a vi like environment where we can add our commit message. The commit message is very important as it allows you to easily see which code commits were responsible for what changes without having to dig through your code.
Hit the ‘i’ key to enter into insert mode, type your message (there is a default character limit of 50 characters I think), hit the escape key, ‘:wq’, and then enter. So enter insert mode->write message->esc->:wq->enter
It will display a small summary of the commit. The file is now being tracked in source control in the local repository, but it still does not exist on the remote server (Bitbucket in this case).
We are going to use the push method to push it to the remote repository with ‘git push’
Now if you look at the source files in the repository, you will now see the file that we added.
If you run ‘git status’, you will see that there are no new files or modifications, and no pending commits.
Now we are going to modify the file and see how what happens. I’m going to use VS Code as my editor, so I’ll just add another line
Now if I type ‘git status’ I’ll see that there are pending changes that need to be committed
Now I’ll commit it slightly differently
git commit * -m "added an additional line"
There are two changes with the way I ran the command. The first is that I did not specify the file to which I want to commit changes, but rather said commit all changes. If multiple files had been modified, this would commit all of those changes.
Secondly is the -m, this allows me do just write my commit message inline rather than entering the text editor. This is much quicker.
We don’t have to push the file since it’s just a dummy file. In fact, let’s remove it by typing ‘git .\rm my_test_file’. Then a git status to see the change, then go ahead and commit and push.
The file is now out of source control.
Adding the Sample Vagrantfile and .gitignore File
Now than we know how to use Git, we can use it to track the Vagrantfile which will be used to provision our nodes.
I rarely use GitHub (as I keep most repos private), but I’m going to create an ‘ansible’sandbox’ public repository to host some of the samples for this guide. We are going to start by just downloading two sample files.
First, we have the Vagrantfile itself. This is the description of the nodes which you would like to be provisioned. The sample provided will provision the nodes mentioned in part 1.
The second file is the .gitignore file. Remember when I used the ‘git commit *’ command. Imagine doing that with ‘git add’. It would add all of the files in the current directory and in subdirectories. There will be a lot of files that you do not want to add to source control. This includes things such as log files, error files, executables, and potentially many others. The .gitignore file is a list of exlusions.
For example, having *.log in your .gitignore file will exclude any .log file when you to ‘git add *’. You can put it in the root of your repository and in any of your subfolders. There are rules of precedence which you can read about here. For this guide though, you can just grab the sample from my my respo and place it in the root of this repository.
You can check out the two sample files before downloading them here.
Go ahead and download the two files now, placing each of them in the root directory of your repository. I’ll use PowerShell to do it
Start-BitsTransfer -Source https://raw.githubusercontent.com/matthew-hickok/ansible-sandbox/master/Vagrantfile Start-BitsTransfer -Source https://raw.githubusercontent.com/matthew-hickok/ansible-sandbox/master/.gitignore
Now use what you just learned to add both of those to your repository
git add * git commit * -m "added vagrantfile and gitignore" git push
Now check the repo on Bitbucket and you should see those two files.
Click on any of them to see contents
It looks a whole lot better in a code editor though. If the editor does not automatically pick up the syntax, it’s Ruby.
So you are probably thinking ‘so what?’ at this point. It tracks changes. Big deal.
But it is a very big deal and this will become more apparent as we go on. Imagine perfecting this Vagrantfile, and in the future, writing a ton of super cool Ansible playbooks. You put them all in your Git repository.
Well now you have reliable documentation (commit messages and code diffs), change management (revert to any point in time since it was added to source control), and you could have an entire team of people working on this project with you (I won’t be covering repo permissions, but it’s super easy).
Alright, now pretend that all of this is setup on your desktop, but you are travelling and want to keep working on this from your laptop. No problem. Install git, clone the repository, and everything is there. Your Vagrantfile, your ansible playbooks — everything.
We won’t be going over CI in this guide, but there is additional automation to be found so that every time you do something like commit or push code, it will kickoff a task. As an example, this could be running the playbooks against a group of test servers every time you commit a change to the playbook.
The rabbit hole goes much deeper than I’ll get into in this guide, but just know that the possibilities here are endless and that Git will end up being a core part of your workflow throughout.
Coming in Part 3: Vagrant
Originally I planned on doing both the Git and Vagrant parts in one post — but I really didn’t want to rush the Git part of it and combining them would get too long (this post is already too long).
Instead Part 3 will be solely focused on Vagrant, and Part 4 will be on Ansible.
In Part 3 we’ll look in detail at the Vagrantfile and then we’ll actually provision all of the nodes using that file and by issuing a single command: ‘vagrant up’
And to finish it off, we’ll SSH into each node to verify things are working as they should.