Bookmark this page

Chapter 3.  Managing and Running Playbooks

Abstract

Goal

Manage automation code in version control and run Ansible Playbooks from a centrally managed automation controller.

Objectives
  • Create and manage Ansible Playbooks in a Git repository, following recommended practices.

  • Navigate and describe the automation controller web UI, and successfully launch a job using a job template, project, credential, and inventory.

  • Identify issues in Ansible Playbooks and repair them.

  • Verify that Ansible can communicate with managed network devices, and troubleshoot any problems with those connections.

Sections
  • Managing Ansible Project Materials Using Git (and Guided Exercise)

  • Running Playbooks in Automation Controller (and Guided Exercise)

  • Troubleshooting Playbooks (and Guided Exercise)

  • Troubleshooting Ansible Network Communication (and Guided Exercise)

Lab
  • Managing and Running Playbooks

Managing Ansible Project Materials Using Git

Objectives

  • Create and manage Ansible Playbooks in a Git repository, following recommended practices.

Introducing Git

Git is a distributed version control system (DVCS) that enables you to collaboratively manage changes to files.

Using Git provides many benefits:

  • You can review and restore earlier versions of files.

  • You can compare two versions of the same file to identify changes.

  • You can record a log of who made what changes, and when those changes were made.

  • Multiple users can collaboratively modify files, resolve conflicting changes, and merge the changes.

Using Git, you can start by cloning an existing shared project from a remote repository. Cloning a project creates a complete copy of the original remote repository as a local repository. This local copy has the entire history of the files in Git, and not just the latest snapshot of the project files.

You make edits to files in a working tree, which is a checkout of a single snapshot of the project. Next, you place the modified files in a staging area, ready to commit the changes to the local repository. At this point, no changes have been made to the shared remote repository.

When you are ready to share the completed changes, you commit the changes and then push the changes to the remote repository.

Likewise, when you are ready to update the local repository with the latest changes to the remote repository, you pull the changes, which fetches them from the remote repository and merges them into the local repository.

To use Git effectively, you must be aware of the three possible states of files in the working tree: modified, staged, or committed.

StateDescription
ModifiedYou edited the copy of the file in the working tree and it is different from the latest version in the repository.
StagedYou added the modified file to a list of changed files to commit as a set, but the staged files have not been committed yet.
CommittedYou committed the modified file to the local repository.

Initial Git Configuration

Because Git users often modify projects with multiple contributors, Git records the user's name and email address on each of their commits. You can define these values at a project level, but you can also set global defaults for a user. The git config command controls these settings.

Using git config with the --global option manages the default settings for all Git projects to which you contribute by saving the settings in your ~/.gitconfig file.

[user@host ~]$ git config --global user.name 'Peter Shadowman'
[user@host ~]$ git config --global user.email peter@host.example.com

Starting the Git Workflow

When you first start working on an existing project, you clone a remote repository to create a local repository in a subdirectory of the current directory.

This process creates a working tree of files ready for revisions. Because the working tree is unmodified, it is initially in a clean state. A clean state means the working tree does not contain any modified, staged, or new files.

To clone a repository from the command line, use the git clone command, followed by the URL that specifies the location of the remote repository that you want to clone.

For example, the following command clones the netconfig.git repository at git.lab.example.com by connecting using the SSH protocol and authenticating as the git user:

[user@host ~]$ git clone git@git.lab.example.com:netconfig.git

To clone a repository in VS Code, click the Source Control icon in the left navigation menu, or click ViewSource Control to display the Source Control panel. Click Clone Repository in the Source Control panel.

Figure 3.1: Cloning a repository in VS Code

As you work, you create new files and modify existing files in the working tree. This changes the working tree to a dirty state.

The git add command stages files, preparing them to be committed. Only files that are staged to the staging area are saved to the repository on the next commit.

To add all changed files in the current directory and subdirectories, use the git add . command. To add all changed files in every directory in the entire working tree, use the git add -A command.

Note

The git add . and git add -A commands can simultaneously add multiple files to the staging area.

If you are working on multiple changes at the same time, then you might want to add each file separately so that you can organize the files into different commits for better tracking of changes.

To view staged files in VS Code, click the Source Control icon in the left navigation menu.

To include a file in the next commit, click the plus (+) symbol next to the file to add the file to the Staged Changes section. Click the minus (-) symbol to remove changed files from the Staged Changes section.

Figure 3.2: Staging changes in VS Code

Note that a capital M character appears next to modified files.

To commit your staged changes, type a commit message in the upper text box and click Commit. This saves your changes to the local Git repository.

Commit messages do not have to be long, but they should be meaningful so that they are useful.

Note

Meaningful and concise commit messages are the key to maintaining a clear history for an Ansible project. Use descriptive commit messages and add references to issues, tickets, and related people where applicable.

Synchronizing Changes

From the command line, the git push command uploads commits you made in your local repository to the remote repository. One common way to coordinate work with Git is for all developers to push their work to the same, shared, remote repository.

Likewise, the git pull command downloads changes to your local repository from the remote repository. Use the git pull command to perform the following tasks:

  • Fetch commits from the remote repository.

  • Add those commits to the local directory.

  • Merge changes into the files in the working tree.

Run the git pull command often to stay current with the changes that others are making to the project in the remote repository.

To synchronize changes by using git pull and git push in VS Code, click the More Actions menu (…​) and then click Pull or Push, or choose an option in the Pull, Push submenu.

Figure 3.3: Synchronizing local changes with a remote repository

Working with Branches and References

You can use branches to update your project and work on new development without altering your main branch. When you are satisfied with your changes, you can merge the changes in your branch to the main development branch, integrating them.

A branch is a pointer to a particular commit in your commit tree. Each commit contains the changes it made, information about how to reference it, and what its relationship is to other commits in the commit tree.

Overview of Git Branching

Git version control features a branching model to track code changes. All Git repositories have a base branch. Many projects prefer to use main as the name of the base branch. When you create a commit in your repository, the base branch is updated with the new commit. Git uses the term HEAD to describe the pointer to where you are in the currently active branch.

Figure 3.4: Commits to the main branch of a Git repository.

By convention, the main or master branch in a Git repository contains the latest, stable version of the source code. To implement a new feature or functionality, create a branch from the main branch. This new branch, called a feature branch, contains commits corresponding to code changes for the new feature. The main branch is not affected by commits to the feature branch.

Figure 3.5: Commits to a feature branch of a Git repository.

When you use a branch for feature development, you can commit and share your code often without impacting the stability of code in the main branch. After ensuring that the code in the feature branch is complete, tested, and reviewed, you are ready to merge the branch into another branch, such as the main branch. Merging is the process of combining the commit histories from two separate branches into a single branch.

Figure 3.6: Merging a feature branch into the main branch.

Merge Conflicts

Git has sophisticated mechanisms to merge code changes from one branch into another branch. However, if there are changes to the same file in both branches, then a merge conflict can occur.

A merge conflict indicates that Git cannot automatically determine how to integrate changes from both branches. When this happens, Git inserts markers in each affected file to indicate the sections that contain content conflicts from both branches.

Figure 3.7: Viewing a merge conflict in VS Code.

For each conflict in a file, replace the content between the merge conflict markers (<<<<<<<< and >>>>>>>> inclusive) with the correct content from one branch or the other, or an appropriate combination of content from both branches.

You can also click Resolve in Merge Editor and resolve the merge conflict there.

Figure 3.8: Resolving a merge conflict in VS Code.

After you reconcile the content for each conflict in a file, you need to save, stage, and commit the file changes. You can then synchronize with the remote repository.

Note

For more information on merge conflicts, see Basic Merge Conflicts at https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging

Creating Branches

Different branches in Git enable different work streams to evolve in parallel in the same Git repository. Commits for each work stream append only to that branch.

From the command line, you can use the git branch command to create a branch from the current HEAD commit. This command creates a reference for the new branch, but it does not set the current HEAD to this branch. Use the git checkout command to move the HEAD to the appropriate branch.

To create a branch in VS Code, click the Source Control icon in the left navigation menu, or click ViewSource Control to display the Source Control panel. Click the Views and More Actions icon (…​) and then click BranchCreate Branch.

Figure 3.9: Creating a new branch in VS Code.

Important

Some Git servers, such as GitHub, GitLab, and Bitbucket, allow you to protect branches from unwanted changes. As a best practice you might protect certain branches on the remote repository, such as the main branch, to avoid merging unwanted changes to them from other branches.

These servers also often implement a feature called pull requests or merge requests. This provides a mechanism that you or other code reviewers can use to review and approve requests before the branch can be merged with the protected branch on the remote server.

Examining the Git Log

Part of the point of a version control system is to track a history of commits. A commit hash identifies each commit.

The git log command displays the commit log messages with the associated ID hashes for each commit.

The git show commit-hash command shows what was in the change set for a particular commit hash. You do not need to use the entire hash with this command; only enough of it to uniquely identify a particular commit in the repository. These hashes can also be used to revert to earlier commits or otherwise explore the version control system's history.

Table 3.1. Git Quick Reference

CommandDescription
git status Display the status of files in the working tree.
git log Display the commit log messages.
git show commit-hash Show what was in the change set for a particular commit hash.
git revert commit-hash Create a commit, undoing the changes in the referenced commit. You can use the commit hash that identifies the commit, although there are other ways to reference a commit.

Important

This is a simplified introduction to Git. It has made some assumptions and avoided discussion of other important topics related to branches and merging. Some of these assumptions include:

  • You cloned the local repository from a remote repository.

  • You configured the local branch to pull from and push to a branch on the original remote repository.

  • You provided write access to the remote repository, such that git push works.

Structuring Ansible Projects in Git

Each Ansible project should have its own Git repository. The structure of the files in that repository should follow the directory layout recommended at https://docs.ansible.com/ansible/6/user_guide/sample_setup.html#sample-directory-layout.

For example, the directory structure might appear as follows:

site.yml                  # main playbook
ios.yml                   # playbook for IOS managed nodes
junos.yml                 # playbook for Junos managed nodes

collections/              # holds Ansible Content Collections in directories
    requirements.yml      # specifies collections needed by this project

roles/
    requirements.yml      # specifies roles needed by this project
  ...additional roles...

Ansible Roles and Ansible Content Collections

Ansible Roles and Ansible Content Collections are ways that you can reuse code from other Ansible projects.

You can include roles and Ansible Content Collections in your Ansible project's Git repository. In this case, each collection is generally stored in subdirectories of the collections/ directory, and each role is stored in subdirectories of the roles/ directory.

There might also be a requirements.yml file in either or both of those directories that specifies collections or roles that are used by this project.

A role or collection can have its own Git repository. Then instead of keeping a copy of the role or collection in your Ansible project's repository, automation controller can retrieve it directly from the relevant role or collection repository when it runs playbooks that belong to the project.

To set this up, create requirements.yml files in your roles/ and collections/ directories. Then use the ansible-galaxy command to populate this directory with the latest version of roles from automation hub, Ansible Galaxy, or their Git repositories before you run the project's playbooks.

Note

Automation controller automatically updates the project with roles and collections based on the roles/requirements.yml and collections/requirements.yml files included in the Ansible project.

Configuring Git to Ignore Files

Not every file and directory in your Ansible project directory should be tracked by Git. You can configure Git to ignore files and directories that should not be tracked or committed.

To configure Git to ignore specific files and paths in your project, add a .gitignore file at the top of your Ansible project directory.

Each line in a .gitignore file represents a pattern to match, and that determines whether Git ignores a file in the repository. Generally, lines that match file names indicate files that Git ignores. Lines that start with an exclamation mark (!) indicate files that Git should not ignore, even if they were matched by a previous pattern. You can use blank lines to improve readability, and any line that starts with a number sign (#) is a comment.

Details on the pattern matching format for this file are documented in the gitignore(5) man page under "PATTERN FORMAT". Pay particular attention to the distinction between single asterisks (*) and double asterisks (**) in these pattern matching lines. (Double asterisks can match multiple directory levels.)

For example, if you use requirements.yml files with the ansible-galaxy command to populate the project's roles and collections directories, then you should configure Git to ignore the populated content.

A sample .gitignore file might contain the following content:

roles/**
!roles/requirements.yml
collections/ansible_collections

Revision: do457-2.3-7cfa22a