Implements a resource that passes sets of key-value pairs between jobs without using any external storage with resource like Git or S3.
Pulled by a get step, key-value pairs are provided to the build plan as an artifact directory with one file per key-value pair. The name of a file is the “key”, and its contents is the “value”. These key-value pairs can then be loaded as local build vars using a load_var step.
Pushed by a put step, key-value pairs are persisted in the Concourse SQL database. For this to be possible, the trick is that they are serialized as keys and values in version JSON objects. As such, they are designed to hold small, textual, non-secret data.
In case you're dealing with large text, binary data or secrets, we recommend you opt for other solutions. Indeed, secrets will be best stored in a vault like CredHub, large text files in Git, and binary data in some object storage or Git with Git-LFS, the “Large File Storage” addon.
This resource is a fork of the keyval resource by @moredhel, thanks for the work done!
Compared to the original keyval resource from SWCE by @regevbr and @ezraroi, writing key-value pairs as plain files in some resource folder is more consistent with usual conventions in Concourse, when it comes to storing anything in step artifacts. It is also compliant with the ConfigMap pattern from Kubernetes.
Writing/reading files is always easier in Bash scripts than parsing some Java Properties file, because much less boilerplate code is required.
Inital v1.1.0 release has fixed many defects, that made it not usable (non-working put steps).
That one implements Bloblang-generated contents, and only allow creating new key-values through the params of put steps, not through writing plain files in some artifact directory of tasksteps like we do here.
resource_types: - name: key-value type: registry-image source: repository: gstack/keyval-resource resources: - name: key-value type: key-valuehistory_identifier: Optional. When the “global resources” feature is enabled on your Concourse installation, and you don't want a single resource history for all the keyval resources defined in your Concourse installation, then set this property to a relevant identifier, possibly unique or not. See the “global resources” section for a detailed discussion on use-cases and solutions.
This is a version-less resource so check behavior is no-op.
It will detect the latest store key/value pairs, if any, and won't provide any version history.
None.
Fetches the given key & values from the stored resource version JSON (in the Concourse SQL database) and write them in their respective files where the key is the file name and the value is the file contents.
"version": { "some_key": "some_value" }would result in:
$ cat resource/some_key some_valueNone.
Converts each file in the artifact directory designated by directory to a set of key-value pairs, where file names are the keys and file contents are the values. This set of key-value pairs is persisted in the version JSON object, to be stored in the Concourse SQL database.
A value from a file in directory can be overridden by a matching key with different value in the dictionary given as the overrides parameter. If you need to store some Concourse ((vars)) value in a key-value resource, then add it to the overrides parameter of some put step.
-
directory: Required. The artifact directory to be scanned for files, in order to generate key-value pairs -
overrides: Optional. A dictionary of key-value pairs that will override any matching pair with same key found indirectory.
This example make intentional ellipsis in order to focus on the main ideas behind the “keyval” resource. Seasoned Concourse practitioners can find an illustration here in one catch.
resource_types: - name: key-value type: registry-image source: repository: gstack/keyval-resource resources: - name: build-info type: key-value jobs: - name: build plan: - task: build file: tools/tasks/build/task.yml # <- must declare a 'build-info' output artifact - put: build-info params: directory: build-info - name: test-deploy plan: - in_parallel: - get: build-info passed: [ build ] - task: test-deploy file: tools/tasks/task.yml # <- must declare a 'build-info' input artifactThe build task writes all the key-value pairs it needs to pass along in files inside the build-info output artifact directory.
The test-deploy job then reads the files from the build-info resource, which produces a build-info artifact directory to be used by the test-deploy task.
This fully-working and detailed example goes deeper in showcasing what the resource can actually do and how. Concourse beginners are recommended to read this as it details very clearly the relation between resource, artifact directories, and tasks.
resource_types: - name: key-value type: registry-image source: { repository: gstack/keyval-resource } resources: - name: some-keyval-resource type: key-value - name: runner-image type: registry-image source: { repository: busybox } jobs: - name: step-1-job plan: - get: runner-image - task: write-keyval-aaa-1-task image: runner-image config: platform: linux outputs: [ { name: created-keyvals-artifact } ] run: path: sh args: - -exc - | echo "1" > created-keyvals-artifact/aaa - put: some-keyval-resource params: directory: created-keyvals-artifact - name: step-2-job plan: - in_parallel: - get: keyvals-artifact # here artifact directory is resource: some-keyval-resource # different from resource name trigger: true passed: [ step-1-job ] - get: runner-image - task: read-aaa-keyval-task image: runner-image config: platform: linux inputs: [ { name: keyvals-artifact } ] run: path: sh args: - -exc - | cat keyvals-artifact/aaa # -> 1 - task: write-bbb-keyval-task image: runner-image config: platform: linux inputs: [ { name: keyvals-artifact } ] outputs: [ { name: keyvals-artifact } ] run: path: sh args: - -exc - | echo "2" > build-info/bbb - put: some-keyval-resource params: directory: keyvals-artifact overrides: aaa: "11" ccc: "3" - name: step-3-job plan: - in_parallel: - get: some-keyval-resource # artifact dir will have same name trigger: true passed: [ step-2-job ] - get: runner-image - task: read-aaa-bbb-ccc-keyvals-task image: runner-image config: platform: linux inputs: [ { name: some-keyval-resource } ] run: path: sh args: - -exc - | cat build-info/aaa # -> 11 cat build-info/bbb # -> 2 cat build-info/ccc # -> 3The write-keyval-aaa-1-task creates a file named aaa with content 1 to the created-keyvals-artifact output artifact directory. The some-keyval-resource resource will read files in the created-keyvals-artifact directory and store a key-value pair {"aaa": "1"}.
The read-aaa-keyval-task reads the value from the aaa file in keyvals-artifact input artifact directory provided from the some-keyval-resource resource. This outputs 1.
The write-bbb-keyval-task creates a file named bbb with content 2 to keyvals-artifact output artifact directory. Because this directory is same as keyvals-artifact input artifact directory which already contains aaa. The some-keyval-resource resource will read all files in the keyvals-artifact directory and store key-value pairs {"aaa": "1"} and {"bbb": "2"}.
The put: some-keyval-resource in step-2-job provides the overrides option, which changes the original key-value pair {"aaa": "1"} to {"aaa": "11"} and add a new pair {"ccc": "3"}.
The read-aaa-bbb-ccc-keyvals-task reads values from files in the some-keyval-resource input artifact directory, as provided by the some-keyval-resource resource.
When the “global resources” feature is enabled, all resources with same resource.type and resource.source configuration will share the same version history. If you leave the resource.source configuration blank in all your keyval resources, then they will all be considered the exact same resource by Concourse, sharing the exact same history.
For most keyval resource-related use-case though, this is not releavant and thus requires proper scoping.
In many scearios, the key-value resources is used to transmit pipeline-specific data between jobs of the same pipeline. In such case, sharing resource history is most probably irrelevant. In order to avoid this, you can set the history_identifier to some value that will be unique in your Concourse installation.
For best portability of your pipeline across different Concourse installations, we recommend that you use a UUID that can be generated with the uuidgen command-line tool like this:
$ uuidgen | tr [:upper:] [:lower:] fc4cb2ba-d0d4-44e2-8589-8fa89a8271fdThen use it in the resource configuration, so that the resource history is scoped privately:
resources: - name: key-value type: key-value source: history_identifier: fc4cb2ba-d0d4-44e2-8589-8fa89a8271fdIn some scenarios though, it may be interesting to share the resources history between different pipelines. Then you can leverage key-value resources that share the same history_identifier value.
As a result, as soon as a new version is pushed on the shared key-value resources, all other pipelines will see it.
This is interesting in case some pipeline has to trigger other pipelines. A usual solution is to use a “dummy” semver resource, backed by Git or some object storage.
Using the keyval resource can bring an elegant alternative. A limitation is that this resource basically has no version history. At every point in time, only the last vesion exisits for the resource. This is not an issue for this use-case, though. Indeed with a “dummy” semver resource, experience shows that nobody actually pays attention to the version history anyway.
With the keyval resource, the triggering version only need to specify the date and relevant data showing the reason why the pipeline has been triggered. These will appear and properly stay in job build logs, for later inspection.
Key-value pairs are no more written as Java .properties file, but rather one file per key-value pair. The name of a file is a “key”, and its contents is the related “value”.
The required file paramerter for put steps is replaced by directory.
The required directory paramerter has been added to put steps.
The file parameter of put steps is renamed overrides.
Golang unit tests can be run from some shell command-line with Ginkgo, that has to be installed first.
make testThese unit test are embedded in the Dockerfile, ensuring they are consistently run in a determined Docker image providing proper test environment. Whenever the tests fail the Docker build will be stopped.
In order to build the image and run the unit tests, use docker build as follows:
docker build -t keyval-resource .Please make all pull requests to the master branch and ensure tests pass locally.
When submitting a Pull Request or pushing new commits, the Concourse CI/CD pipeline provides feedback with building the Dockerfile, which implies running Ginkgo unit tests.
Copyright © 2021-present, Benjamin Gandon, Gstack
Like Concourse, the key-value resource is released under the terms of the Apache 2.0 license.