Skip to content

Commit

Permalink
feat: adds new deployment subcommands to updater
Browse files Browse the repository at this point in the history
  • Loading branch information
jmgilman authored Jan 30, 2024
1 parent b92d3be commit 45ff406
Show file tree
Hide file tree
Showing 11 changed files with 606 additions and 50 deletions.
1 change: 1 addition & 0 deletions .config/dictionaries/project.dic
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ sqlfluff
subproject
subprojects
superfences
templating
testpackage
Timoni
transpiling
Expand Down
4 changes: 4 additions & 0 deletions services/jorm-metrics-server/deployment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
overrides:
- app: jormungandr
path: exporter.image.tag
value: GITHUB_SHA
2 changes: 1 addition & 1 deletion tools/updater/Earthfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
VERSION 0.7
FROM golang:1.20-alpine3.18
FROM golang:1.21-alpine3.18

# cspell: words onsi ldflags extldflags

Expand Down
169 changes: 154 additions & 15 deletions tools/updater/README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,45 @@
# updater

> A helper tool for modifying CUE files to override arbitrary values.
> Useful for updating Timoni bundles.
> A helper tool for updating CUE files, especially [Timoni] bundle files.
The `updater` CLI provides an interface for overriding existing concrete values in a given CUE file.
Normally, concrete values in CUE files are immutable and thus not possible to override using the CUE CLI.
However, in some cases, it may be desirable to override an existing concrete value.
This is especially true in GitOps scenarios where a source of truth needs to be updated.
The `updater` CLI provides an interface for performing common deployment operations within Project Catalyst.
It has various subcommands centered around supporting GitOps operations by updating CUE files, especially [Timoni] bundle files.
It can be used in tandem with a CI/CD provider to easily update CUE configuration files within an existing repository.

## Usage

The `updater` CLI is most commonly used to update Timoni bundle image tags.
Assuming you have a `bundle.cue` file like this:
The `updater` CLI can be used in various workflows.
This section will provide high-level examples of the different workflows it can be used to support.

### Updating CUE files

By design, CUE files are intended to be immutable.
If a CUE file has a concrete value in a field, it's not possible to easily override it using the CUE CLI.
The `updater` CLI provides a subcommand for easily overriding concrete values within an existing CUE file.
This is especially important for supporting GitOps patterns.

Assuming we have an existing CUE file:

```cue
foo: {
bar: 1
}
```

We can update the value of `bar` with:

```terminal
$ updater update file -f ./file.cue "foo.bar" "2" # Pass --in-place to update the file in place
foo: {
bar: 2
}
```

### Updating Timoni bundle files

A common GitOps flow is to update specific values within a [Timoni bundle file](https://timoni.sh/bundle/).
The `updater` CLI provides a specific subcommand for updating the `values` specified in a bundle.
Given the following bundle file:

```cue
bundle: {
Expand All @@ -25,19 +53,130 @@ bundle: {
}
namespace: "default"
values: {
server: image: tag: "ed2951cf049e779bba8d97413653bb06d4c28144"
server: image: tag: "v0.1.0"
}
}
}
}
```

You can update the value of `server.image.tag` like so:
We can update the value of `server.image.tag` with:

```terminal
$ updater update bundle -f ./bundle.cue -i instance "server.image.tag" "v0.2.0"
# ...
values: {
server: image: tag: "v0.2.0"
}
# ...
```

### Mass updating Timoni bundle files

The primary use of the `updater` CLI is for performing a mass update of Timoni bundle files.
This approach is quite opinionated and requires some additional context.

#### Deployment files

Much like Catalyst CI, the `updater` CLI assumes a mono-repo setup for applications.
Where Catalyst CI expects each application to contain an `Earthfile` describing how to build the application, the `updater` CLI
expects each application to contain a `deployment.yml` file describing how to update the application's associated deployment.
For example:

* `/app1`
* `Earthfile`
* `deployment.yml`
* `/app2`
* `Earthfile`
* `deployment.yml`

Each deployment file contains a set of override operations that instruct the `updater` CLI on which Timoni bundle files to update.
For example:

```yaml
overrides:
- app: app1
instance: app1 # Can be omitted if same as app
path: server.image.tag
value: v0.2.0
```
The exact purpose of each of these fields will become more clear later.
#### Deployment repository
The `updater` CLI assumes a mono-repo deployment repository exists containing Timoni bundle files for each environment.
An example structure would look like this:

* `/bundles`
* `/dev`
* `/app1`
* `bundle.cue`
* `/app2`
* `bundle.cue`
* `/staging`
* `/app1`
* `bundle.cue`

The root directory (`/bundles`) has subdirectories for each environment and each environment has subdirectories for every
application.
Each application in turn has a dedicated `bundle.cue` that contains the deployment code for the application.

#### Updating files

Given the previous example structure and deployment file, the `updater` CLI can automatically update the correct bundle file.
First, we will use the `scan` subcommand to automatically discover all `deployment.yml` files and parse their respective overrides:

```terminal
$ updater scan .
[{"app":"app1","instance":"app1","path":"server.image.tag","value":"v0.2.0"}]
```

This produces a JSON output containing a list of overrides.
The JSON output can be used stand-alone, however, it can also be passed directly to the `update deployments` subcommand:

```terminal
$ updater scan . | updater update deployments -e dev /path/to/deployment-repo/bundles
# Empty output
```

The above command performs the following for each given override:

* Constructs a path to the bundle file: `<root_path>/<environment>/<app>/bundle.cue`
* Constructs a path to override: `bundle.instances.<instance>.values.<value>`
* Overrides the constructed value path within the constructed file path with the override value

Using the previous examples, it would perform the following:

* Constructs a path to the bundle file: `/path/to/deployment-repo/bundles/dev/app1/bundle.cue`
* Constructs a path to override: `bundle.instances.app1.values.server.image.tag`
* Overrides the constructed value path with `v0.2.0`

This setup allows updating arbitrary bundle files and their respective values by defining a single `deployment.yml` file at the root
of a given application.
In a normal GitOps flow, the changes would then be committed to the deployment repository and picked up by a GitOps operator.

#### Templating

The previous example hardcoded an override value in the `deployment.yml`.
In some cases, the value is only known at runtime (i.e., when the CI/CD system is running).
For these cases, it's possible to override arbitrary "template" literals:

```yaml
overrides:
- app: app1
path: server.image.tag
value: GIT_SHA
```

When the CI/CD is performing an update, it can pass the value for this template literal like so (assuming GitHub Actions):

```shell
updater -b bundle.cue "bundle.instances.instance.values.server.image.tag" "0fe74bf77739a3ef78de5fcc81c5c7a8dcae6199"
```terminal
$ updater scan -t "GIT_SHA=${{ github.sha }}" . | updater update deployments -e dev /path/to/deployment-repo/bundles
# Empty output
```

The `updater` CLI will overwrite the image tag with the provided one and update the `bundle.cue` file in place.
Note that the CLI uses the CUE API underneath the hood which may format the existing CUE syntax slightly differently.
In some cases, the resulting syntax might be a bit unsightly, so it's recommended to run `cue fmt` on the file after processing.
Prior to updating the bundle files, the `updater` CLI will replace all occurrences of `GIT_SHA` with the current commit SHA.
This allows dynamically updating the image tag of the application deployment at runtime if you tag images using the commit SHA

[timoni]: https://timoni.sh/
Loading

0 comments on commit 45ff406

Please sign in to comment.