Contents

Nautobot Jobs - Cookiecutter & Cookiecutter Testing

Nautobot Jobs Cookiecutter

Hello! I recently had to create a new job for Nautobot, but I didn’t have a development environment readily available. Typically, one could just write the script on a server that has Nautobot running, reload the server and test execution. But, this doesn’t work too well if it’s a server that you don’t have the correct level of access to, thus preventing a proper development environment like a remote vscode session. Additionally, sometimes we either don’t have a proper dev environment or don’t want to cause errors on the server while developing. It’s also a good practice to have a locallized development env before pushing to a commond project for others to contribute to.

Shout out to NetworkToCode for open sourcing the Chatops Cookiecutter. I forked this project and made quite a few changes to create the jobs cookie. I’ll go into some detail on the result (as of time of this writing) and some cool tips and tricks about testing cookies.

Enter Nautobot Jobs Cookiecutter

How to Use It

There isn’t much to it, other than baking a cookie from the public repository. This will provide a project scaffold that will have the local development environment that is orchestrated with docker and docker compose. Additionally, a job directory with the __init__.py and an example-job.py file will be included. Once the local environment is up and running, any work that you do inside of your jobs directory, will be automatically loaded and refreshed as you develop and test.

Jobs Imported from an external Git Repository

Based on the Jobs Documentation, after you bake your cookie and fully test your Job, you should be checking the code into Git. At this point, you should have or need to create a Git Repository object inside of your Nautobot instance. This repository will need to provide jobs capabilities upon sync. The requirements that are met from this cookiecutter are the following:

  • The repository’s jobs/ directory must contain a file named init.py.
  • Each Job file in the repository is considered a separate module; there is no support for cross-file dependencies (such as a file acting as a common “library” module of functions shared between jobs) for files installed in this way.

If you need to create a Git Repository in Nautobot, just follow the Documentation.

Once you create the Git Repository, you should be able to simply sync and run your jobs. The idea behind this project is to give you the buffer before pushing to your Nautobot deployment. Having a peace of mind that your code works in a local development is a great advantage.

To test the output generated by the cookiecutter project, we leverage Pytest Cookies. I’ll go over a simple test case scenario, to ensure that your cookiecutter generates the correct files and assert against your expectations.

Conftest for Pytest - Template Directories

As I decided to break the template of the cookie under it’s own directory, jobs - we need to ensure to tell our pytest functions where the template lives. Here is the snippet of the conftest.py fixture to tells us where the nautobot jobs directory is.

COOKIECUTTER_PROJECT = str(pathlib.Path(__file__).parent.parent)


@pytest.fixture
def nautobot_jobs_dir():
    """Return the path to the Nautobot Jobs Cookie directory."""
    return f"{COOKIECUTTER_PROJECT}/jobs"

This will give us the correct path to the jobs template inside of our repository.

Testing Output

Inside of /tests/test_nautobot_jobs_cookie.py there is a constant that has a list of filenames that are expected. This will be used for assertions and validations of what is expected to be produced by our template. This is a simple, must have for all cookiecutter projects.

NAUTOBOT_JOBS_COOKIE_OUTPUT = [
    "LICENSE",
    "pyproject.toml",
    "docs",
    "README.md",
    ".gitignore",
    ".github",
    "FAQ.md",
    "tasks.py",
    "invoke.example.yml",
    ".yamllint.yml",
    "development",
    "jobs",
    "GETTING_STARTED.md",
    ".bandit.yml",
    ".flake8",
    ".dockerignore",
]

Now, that we know what is expected to be generated, lets create the pytest function that will assert these filenames versus what’s actually generated.

def test_cookie_output_dir(cookies, nautobot_jobs_dir):
    """Test cookie output dir."""
    result = cookies.bake(template=nautobot_jobs_dir)
    assert set(NAUTOBOT_JOBS_COOKIE_OUTPUT) == set(dirf.name for dirf in result.project_path.iterdir())

Notice that the cookies fixture is available because of our pytest-cookies. This allows for us to simply bake a cookie in a test and provide some extra arguments to modify the generation output.

Summary

The cookiecutter project for Nautobot Jobs repository will help you create a repository that will be eventually synchronized to your production deployment to provide jobs for your organization. It simplifies the local development effort while creating the jobs, before being tested against real, production data. The local development is meant to be used and abused in efforts of providing successful jobs. There are a lot of patterns for testing the output of cookie cutter templates, but using pytest-cookies greatly simplifies the process by providing a simple and easy to use fixture during unit tests.

Hope you enjoy and and get to use this project!

  • Hugo