|
1 | 1 | # Wadsworth |
2 | 2 |
|
3 | | -_The Mister Handy robot of automation!_ |
| 3 | +_The [Mister Handy robot][wadsworth] of automation!_ |
4 | 4 |
|
5 | | - |
| 5 | +Wadsworth is a git-driven task runner to automate the application of configs. |
6 | 6 |
|
7 | | -(Work in progress, come back later...) |
| 7 | +## Overview |
| 8 | + |
| 9 | +Wadsworth is a little tool for implementing [Git-Ops][git-ops] in single-server environments. It's not a cloud/cluster |
| 10 | +tool however it could easily be used as one, but you'd probably be better off using something like |
| 11 | +[kube-applier][kube-applier], [Terraform][terraform], [Ansible][ansible] or any of these more "serious" tools. |
| 12 | + |
| 13 | +Instead, Wadsworth aims to be extremely simple. You give it some Git repositories and tell it to run commands when those |
| 14 | +Git repositories receive commits and that's about it. It also provides a way of safely passing in credentials from |
| 15 | +[Hashicorp's Vault][vault] so you can say goodbye to storing your MySQL password in a .env file! |
| 16 | + |
| 17 | +## Usage |
| 18 | + |
| 19 | +Currently, Wadsworth has a single command: `run` and it takes a single parameter: a Git URL. This Git URL defines the |
| 20 | +"Config Repo" which contains Wadsworth configuration files. These configuration files declare where Wadsworth can find |
| 21 | +"Target Repos" which are the repos that contain all the stuff you want to automate. The reason Wadsworth is designed |
| 22 | +this way instead of just using the target repos to define what Wadsworth should do is 1. to consolidate Wadsworth config |
| 23 | +into one place, 2. separate the config of the tools from the applications and 3. keep your target repos clean. |
| 24 | + |
| 25 | +### Configuration |
| 26 | + |
| 27 | +The precursor to Wadsworth used JSON for configuration, this was fine for simple tasks but the ability to provide a |
| 28 | +little bit of logic and variables for repetitive configurations is very helpful. Inspired by [StackExchange's |
| 29 | +dnscontrol][dnscontrol], Wadsworth uses JavaScript files as configuration. This provides a JSON-like environment with |
| 30 | +the added benefit of conditional logic. |
| 31 | + |
| 32 | +Here's a simple example of a configuration that should exist in the Wadsworth config repo that re-deploys a Docker |
| 33 | +Compose stack whenever it changes: |
| 34 | + |
| 35 | +```js |
| 36 | +T({ |
| 37 | + name: "my_app", |
| 38 | + url: "git@github.com:username/my-docker-compose-project", |
| 39 | + up: ["docker-compose", "up", "-d"], |
| 40 | + down: ["docker-compose", "down"] |
| 41 | +}); |
| 42 | +``` |
| 43 | + |
| 44 | +#### The `T` Function |
| 45 | + |
| 46 | +The `T` function declares a "Target" which is essentially a Git repository. In this example, the repository |
| 47 | +`git@github.com:username/my-docker-compose-project` would contain a `docker-compose.yml` file for some application |
| 48 | +stack. Every time you make a change to this file and push it, Wadsworth will pull the new version and run the command |
| 49 | +defined in the `up` attribute of the target, which is `docker-compose up -d`. |
| 50 | + |
| 51 | +You can put as many target declarations as you want in the config file, and as many config files as you want in the |
| 52 | +config repo. You can also use variables to cut down on repeated things: |
| 53 | + |
| 54 | +```js |
| 55 | +var GIT_HOST = "git@github.com:username/"; |
| 56 | +T({ |
| 57 | + name: "my_app", |
| 58 | + url: GIT_HOST + "my-docker-compose-project", |
| 59 | + up: ["docker-compose", "up", "-d"] |
| 60 | +}); |
| 61 | +``` |
| 62 | + |
| 63 | +Or, if you have a ton of Docker Compose projects and they all live on the same Git host, why not declare a function that |
| 64 | +does all the hard work: |
| 65 | + |
| 66 | +```js |
| 67 | +var GIT_HOST = "git@github.com:username/"; |
| 68 | + |
| 69 | +function Compose(name) { |
| 70 | + return { |
| 71 | + name: name, |
| 72 | + url: GIT_HOST + name, |
| 73 | + up: ["docker-compose", "up", "-d"] |
| 74 | + }; |
| 75 | +} |
| 76 | + |
| 77 | +T(Compose("homepage")); |
| 78 | +T(Compose("todo-app")); |
| 79 | +T(Compose("world-domination-scheme")); |
| 80 | +``` |
| 81 | + |
| 82 | +The object passed to the `T` function accepts the following keys: |
| 83 | + |
| 84 | +- `name`: The name of the target |
| 85 | +- `url`: The Git URL (ssh or https) |
| 86 | +- `up`: The command to run on first-run and on changes |
| 87 | +- `down`: The command to run when the target is removed |
| 88 | +- `env`: Environment variables to pass to the target |
| 89 | + |
| 90 | +#### The `E` Function |
| 91 | + |
| 92 | +The only other function available in the configuration runtime is `E`, this declares an environment variable that will |
| 93 | +be passed to the `up` and `down` commands for all targets. |
| 94 | + |
| 95 | +For example: |
| 96 | + |
| 97 | +```js |
| 98 | +E("MOUNT_POINT", "/data"); |
| 99 | +T({ name: "postgres", url: "...", up: "docker-compose", "up", "-d" }); |
| 100 | +``` |
| 101 | + |
| 102 | +This would pass the environment variable `MOUNT_POINT=/data` to the `docker-compose` invocation. This is useful if you |
| 103 | +have a bunch of compose configs that all mount data to some path on the machine, you then use |
| 104 | +`${MOUNT_POINT}/postgres:/var/lib/postgres/data` as a volume declaration in your `docker-compose.yml`. |
| 105 | + |
| 106 | +## Roadmap |
| 107 | + |
| 108 | +The current implementation is an MVP that does one thing well, but there some features I'd like to implement in future |
| 109 | +to ease the maintenance and user experience: |
| 110 | + |
| 111 | +- Daemon control - currently, `wadsworth run` will just run and block until it is killed, I would like to provide a way |
| 112 | + to interact with a running instance of `wadsworth` via a Unix socket file and a simple API (similar to Docker). This |
| 113 | + would open up the ability to perform forced triggers of targets or disable certain targets via the command line. |
| 114 | +- Proper releases - Right now you grab the binary and run it, how you daemonise it is up to you. I'd like to provide a |
| 115 | + systemd unit file and a Snapcraft app for easier installation and usage. |
| 116 | +- Dependency Tree - this is a maybe but it could be useful if all repos are both config repos and target repos. In other |
| 117 | + words, every repo can contain `.js` config files to build a dependency tree of repos. But I'm not sure if there's a |
| 118 | + use-case for this yet (or ever). |
| 119 | + |
| 120 | +[wadsworth]: https://d1u5p3l4wpay3k.cloudfront.net/fallout_gamepedia/8/8c/Mister_Handy.png |
| 121 | +[git-ops]: https://www.weave.works/blog/gitops-operations-by-pull-request |
| 122 | +[kube-applier]: https://github.com/box/kube-applier |
| 123 | +[terraform]: https://terraform.io |
| 124 | +[ansible]: https://ansible.com |
| 125 | +[vault]: https://vaultproject.io |
| 126 | +[dnscontrol]: https://stackexchange.github.io/dnscontrol/ |
0 commit comments