ansible

Utilize Ansible for opening and closing tickets with ServiceNow - Part 4.

Here are links to Part 1 , Part 2 , and Part 3

This article is part four in a series covering the role Ansible can play in ticket automation. This time we’ll cover creating and managing a reusable and scalable role.

This blog post will cover my journey in creating and managing an open-source Ansible role for creating ServiceNow network tickets. The role can be found here on Galaxy.

This role is not a completed out of the box solution for network ticketing. What it is meant to be is merely a starting point that accelerates your adoption of automating ServiceNow with Ansible. If you follow all four blog posts this will be the one that starts to introduce more developer tools. Feel free to send me pull requests if you want to contribute to growing this role.

I will cover the tools and best practices I used while maintaining the GitHub repo.

Including the GitFlow process for making changes to the role and merging between dev and master branches.

But first…​ let me show you my idea of how this role would be used. Let’s review one of the playbooks found in the examples folder here. These five playbooks are designed for config compliance. They will add or remove any configs that don’t match the intended state declared in the playbook. In a production network the declared state may live somewhere else like in a host vars file or perhaps you could use a CMDB like ServiceNow or Netbox as your source of truth.

---
- hosts: ios
  gather_facts: no

  vars:

    log_servers:
      - logging 8.8.8.8
      - logging 8.8.4.4


  tasks:

  - name: get the current log server configs
    ios_command:
      commands:
        - show running-config full | include logging [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+
    register: log

  - debug: var=log.stdout_lines


  - name: set logging commands
    ios_config:
      commands: "{{ item }}"
    loop: "{{ log_servers }}"
    register: set_logging


  - name: remove logging commands
    ios_config:
      commands: "no {{ item }}"
    when:  "item not in log_servers"
    loop: "{{ log.stdout_lines[0] }}"
    register: remove_logging


  - name: servicenow_network_tickets
    when: set_logging.changed or remove_logging.changed
    import_role:
      name: servicenow_network_tickets

This playbook was written in a way that it can be idempotent. On the first run the configs on the device do not match the state in the playbook. There are two extra logging servers configured on the switches. You can see the playbook find them and remove those configs, which triggers a ticket to be created for each switch.

However, if you watch the second run no configs needed to be added or removed, so all those tasks were skipped and the ticket role was not imported.

asciicinema

GitFlow

While I developed this role on my own I still wanted to hold myself to using Git collaboration best practices. I used the GitFlow workflow for all changes to the code. I created a devel branch and worked in there for all my testing and additions to the codebase. Once I had something new or a bug fix figured out and was happy with it, I created a Pull request against the master branch. If you ever have a chance to contribute to the open-source Ansible project on GitHub you will follow the same process of forking and creating pull requests.

Learning this flow is the most important things you can do to embrace and benefit from these developer tools our field is moving towards adopting. When you are working on a code project with other people who are also contributing this flow becomes imperative. Learn this before worrying about Travis CI, hooks, or anything else.

One Role One Repo

Utilizing the one role one repo thought process for scalability and compatibility with Galaxy.

I am a firm believer you should store your roles in their own repo, I like to call this style One Role One Repo. I am often asked how to structure your Git repos when getting started with network automation so that you can easily scale and not have to make a bunch of changes later down the road. Some folks look at my strange when I advise them to structure their repos like this. They say well what if I we grow to having 1000 roles, we don’t want to have 1000 repo’s. Yes you do actually!

A great presentation on this subject was given by Sam Doran a Senior Software Dev at Ansible/Red Hat during AnsibleFest London 2017. I always recommend folks go and watch that if they want to understand how to scale. You can find that presentation recording here

Every role should be documented, permissioned and shared on it’s own. What if you want to share your BGP roles with a certain department but they don’t need to see your OSPF and MPLS roles. How would you easily share those if they were all in the same repo.

Ansible Galaxy uses this same system, every role can be downloaded or cloned separately. Hopefully you may have some roles that you wish to share with the community. Also when you start to maintain these roles with a CI/CD mindset and start using tools like ZUUL. It all makes sense why they should live in their own repo’s.

Dependencies

When you create a role using the ansible-galaxy init command it will automatically create a meta/main.yml file. This file is where you can list your role dependencies. In this case my role does require another role in order to function. If you read Part 3 I introduced you to network-engine. There is no need to include a task to import the network-engine role as this is implied once you mention it in the meta/main.yml file. Because I use Ansible Tower for everything I just add a requirements.yml file to the roles directory where my playbooks live and Tower automatically runs the ansible-galaxy install -r roles/requirements.yml -p ./roles/ --force command. You can find an example here.

galaxy_info:
  author: Colin McCarthy
  description: your description
  company: Red Hat

  # If the issue tracker for your role is not on github, uncomment the
  # next line and provide a value
  # issue_tracker_url: http://example.com/issue/tracker

  # Some suggested licenses:
  # - BSD (default)
  # - MIT
  # - GPLv2
  # - GPLv3
  # - Apache
  # - CC-BY
  license: license (GPLv2, CC-BY, etc)

  min_ansible_version: 2.6

  # If this a Container Enabled role, provide the minimum Ansible Container version.
  # min_ansible_container_version:

  # Optionally specify the branch Galaxy will use when accessing the GitHub
  # repo for this role. During role install, if no tags are available,
  # Galaxy will use this branch. During import Galaxy will access files on
  # this branch. If Travis integration is configured, only notifications for this
  # branch will be accepted. Otherwise, in all cases, the repo's default branch
  # (usually master) will be used.
  # github_branch:

  #
  # Provide a list of supported platforms, and for each platform a list of versions.
  # If you don't wish to enumerate all versions for a particular platform, use 'all'.
  # To view available platforms and versions (or releases), visit:
  # https://galaxy.ansible.com/api/v1/platforms/
  #

  platforms:
    - name: ios
      version:
        - any

  galaxy_tags:
    - network
    - cisco
    - ios

dependencies:
  - ansible-network.network-engine

TravisCI

I have been looking into adding some CI to this repo based on the repos of GeerlingGuy and Nick Russo.

This is a tricky subject when dealing with Network Automation. What we are trying to accomplish can sometimes be harder to emulate and test. For instance trying to use CI/CD against a change to an Ansible playbook that modifies BGP neighbors can be a beast to reproduce in a test environment. It seems like the trend currently is to automate a linting test against the YAML and call it good. I decided to use TravisCI because it is a cloud based SaaS model and does not require me to spin up and maintain a server. I have been looking into ZUUL as it uses Ansible playbooks to drive the CI however it would require I stand up a server. I didn’t want to take on that kind of task right now but would like to try this out in the future hopefully.

I’m going to add CI to this the repo soon and create a follow up blog on this subject.

Pre Commit Hooks

pre-commit is very valuable when you start to contribute to a repo with business rules and production code. A great place to start is with linting your YAML and Ansible. Another great example is a hook that searches for secrets just in case someone tries to commit them by accident. If you set up a pre-commit hook that kicks off when you try to git commit, it will save you from sending bad code to your repo. It will also save your CI from running and then blocking your commit. If you set up Travis CI to use yaml-lint you could set up a pre-commit hook on your local system that also uses yaml-lint and then you should never submit code that gets rejected by your Travis CI. This is another one of those developer tools that I really liked when I started looking into it.

Ansible lint is a command line checker tool.

yaml lint is a yaml linter.

SecretsChecker will scan for accidental passwords or secrets in the code your trying to commit.

Stay tuned for more blogs where I will dig deeper into these individual subjects

TheNetwork.Engineer - March 31 2019 - Colin McCarthy

Free DevOps Resources


Get DevOps news, tutorials and resources in your inbox. A perfect way If you want to get started with devops. Like you, we don't like spam.