From 45efd643e9ef642e995bd63824bdef3f53e3bd19 Mon Sep 17 00:00:00 2001 From: Greg Hellings Date: Mon, 10 Oct 2022 16:04:24 -0500 Subject: [PATCH] Add DRY CI post --- .envrc | 4 ++ .gitignore | 2 + content/posts/dry_ci.md | 73 +++++++++++++++++++++++++++++++++++++ content/posts/what-is-ci.md | 3 ++ flake.lock | 43 ++++++++++++++++++++++ flake.nix | 18 +++++++++ 6 files changed, 143 insertions(+) create mode 100644 .envrc create mode 100644 content/posts/dry_ci.md create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..5e9005b --- /dev/null +++ b/.envrc @@ -0,0 +1,4 @@ +if ! has nix_direnv_version || ! nix_direnv_version 2.1.1; then + source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.1.1/direnvrc" "sha256-b6qJ4r34rbE23yWjMqbmu3ia2z4b2wIlZUksBke/ol0=" +fi +use flake diff --git a/.gitignore b/.gitignore index 26bd4cc..dd2ab72 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ public/* .*.swp .hugo_build.lock +None +.direnv diff --git a/content/posts/dry_ci.md b/content/posts/dry_ci.md new file mode 100644 index 0000000..79b3dce --- /dev/null +++ b/content/posts/dry_ci.md @@ -0,0 +1,73 @@ +--- +title: "DRY CI" +date: 2022-10-10T15:32:19-05:00 +draft: false +tags: +- ci +- continuous integration +- ansible +- software engineering +- technology +series: +- Ansible CI +--- + +{{< series "Ansible CI" >}} + +So I have talked before about [what CI actually means](/posts/what-is-ci/). That post was, admittedly, +rather dry and academic. I think it's important to sometimes make the distinction between what is just +regular automation and what is strictly CI. When there is automation but no CI it is still very easy +for errors to slip into a supposedly stable code base, as not every commit is tested before it is +merged to the main. However, with the complexity of modern software, it is pragmatically impossible to +separate these two concerns, as CI without automation quickly overwhelms any manual system. + +To that point, I have long had a fascination with [Ansible](https://www.ansible.com), which I encountered +early in my experience with CI. Ansible is more suited to Continuous Deployment than specifically to +Continuous Integration, but if you give someone CD tools when they are fascinated by CI, you are going to +end up with a strange assortment of mashups. + +## CD for your CI + +Ansible, as configuration management software, is great at deploying software and services. I don't want +to try and convince anyone to switch from their favorite system to Ansible, that's not what I'm about. +But, maybe, there are some things I've learned and done with Ansible that you can use either in your +own Ansible journey or in your own configuration management and continuous deployment tools. + +Naturally, CD sits after any sort of test and, most commonly, after CI. If a build system is relatively +mature and can produce well tested code with a high confidence, it is a great candidate for Continuous +Deployment. Some tools perform this natively (such as Kubernetes). Others can be used to perform deployments +for generalized code. However, either way, you have code deploying code. + +So how can you be sure your code is doing what you expect? + +## CI for your CD/Configuration + +Well, you test it in CI, of course! That's right, if you are unfamiliar with writing good Ansbile, there are +testing tools that exist specifically to test Ansible code. There are two main tools for this: + +* [Ansible Test](https://www.ansible.com/blog/introduction-to-ansible-test) exists to specifically test + things like modules and plugins to Ansible to ensure that they are behaving as expected +* [Molecule](https://molecule.readthedocs.io/en/latest/index.html) exists to specifically test playbooks, + roles, and the YAML side of Ansible code + +So the automated tools exist to run automated CI for Ansible code. The question becomes, how do we configure +our CI system to find and execute these tests on each merge? My answers will focus primarily on +[Github Actions](https://github.com/actions/), as that is where I execute the tests for my own Ansible +collections, but a similar technique can be leveraged in most other modern CI executors. + +### First Version + +The first times I wrote CI scripts for my Ansible code using Molecule there were not yet Collections available, +so each role existed to be tested on its own. Whenever a change to my CI process arose, or an update to a +version was available, I would need to update 30+ separate repositories. This was obviously unweildy, so the +first step towards sanity was moving to collection once those were available in Ansible 2.9. Now, I only had +one repository to manage. + +However, I had 3 different places tests needed to be defined. I would need to write a test, first, in the +`roles/my_role/molecule/scenario_name` folder. This was the actual Molecule test definition. I would then +need to add the new scenario name, folder, and job to my `tox.ini` file, which I used to manage the Python +package installation for Ansible, Molecule, pytest, testinfra, yamllint, and more. Tox was a natural place +to manage all of these, but it meant a second place to add the test definition. And, thirdly, I had to update +my Github Actions workflow file and tell it to execute the particular tox target. + +In the next post I will write about how I tamed the beast before it got out of hand. diff --git a/content/posts/what-is-ci.md b/content/posts/what-is-ci.md index db0c718..5dbc5fe 100644 --- a/content/posts/what-is-ci.md +++ b/content/posts/what-is-ci.md @@ -11,6 +11,9 @@ tags: series: - Ansible CI --- + +{{< series "Ansible CI" >}} + At work I have been doing CI for nearly 10 years, now. Having been working at Red Hat for the past 6 of those, some of the CI work that I do is available in open source contributions up on Git Hub. I plan to make a series of posts about that work, so I am going to start diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..561ff7f --- /dev/null +++ b/flake.lock @@ -0,0 +1,43 @@ +{ + "nodes": { + "flake-utils": { + "locked": { + "lastModified": 1659877975, + "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1665296151, + "narHash": "sha256-uOB0oxqxN9K7XGF1hcnY+PQnlQJ+3bP2vCn/+Ru/bbc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "14ccaaedd95a488dd7ae142757884d8e125b3363", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..5ea9355 --- /dev/null +++ b/flake.nix @@ -0,0 +1,18 @@ +{ + description = "A basic flake with a shell"; + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + inputs.flake-utils.url = "github:numtide/flake-utils"; + + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: let + pkgs = nixpkgs.legacyPackages.${system}; + in { + devShells.default = pkgs.mkShell { + nativeBuildInputs = [ + pkgs.bashInteractive + pkgs.hugo + ]; + buildInputs = [ ]; + }; + }); +}