https://github.com/mcorbin/kvert
A powerful tool to generate YAML files
https://github.com/mcorbin/kvert
Last synced: 8 months ago
JSON representation
A powerful tool to generate YAML files
- Host: GitHub
- URL: https://github.com/mcorbin/kvert
- Owner: mcorbin
- License: epl-2.0
- Created: 2021-12-21T21:35:53.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2022-08-10T20:34:54.000Z (almost 4 years ago)
- Last Synced: 2025-04-12T17:44:34.025Z (about 1 year ago)
- Language: Clojure
- Homepage:
- Size: 59.6 KB
- Stars: 32
- Watchers: 3
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# kvert: a powerful tool to generate YAML files
`kvert` lets you generate yaml files in a declarative way. You can for example use it to manage your Kubernetes manifests.
It supports including parts of definitions into other ones, variables, generating files with a different shape based on a `profile`, reading values from environment variables... All of this allows you to manage your YAML files in an effective way.
The tool leverages the [EDN](https://github.com/edn-format/edn) format and the [Aero](https://github.com/juxt/aero) library.
Why `kvert` ? It's simple, powerful and extensible.
I think neither templating or using YAML to generate more YAML are good solutions to manage Kubernetes resources and that's why I built this tool.
## Install
For Linux (x86-64), download the `kvert` binary from the [release page](https://github.com/mcorbin/kvert/releases) and put it in your PATH. This binary is built using [GraalVM](https://www.graalvm.org/), more targets may be added soon (help welcome).
You can alternatively download the `jar` file and then run it with `java -jar kvert.jar` (Java 17 needed).
A docker image is also provided. Note that this image uses `java` as well so executing it is a bit slower than the static binary built with GraalVM.
All example described below can be done using the Docker image by executing in the directory containing your templates `docker run -v $(pwd):/data mcorbin/kvert:v0.2.0 `. The files will be availables in `/data`. Example: `docker run -v $(pwd):/data mcorbin/kvert:v0.2.0 yaml -t /data/example.edn`.
## Quick start
### Simple EDN example
Once `kvert` installed, you are ready to use it. Let's for example generate a yaml file from a simple EDN definition. Put in `pod.edn` this content:
```clojure
;; this is a comment
{:apiVersion "v1"
:kind "Pod"
:metadata {:name "dnsutils"
:namespace "default"}
:spec {:containers [{:name "dnsutils"
:image "k8s.gcr.io/e2e-test-images/jessie-dnsutils:1.3"
:command ["sleep" "3600"]
:imagePullPolicy "ifNotPresent"}]
:restartPolicy "Always"}}
```
Now run `kvert yaml --template pod.edn`:
```yaml
---
apiVersion: v1
kind: Pod
metadata:
name: dnsutils
namespace: default
spec:
containers:
- name: dnsutils
image: k8s.gcr.io/e2e-test-images/jessie-dnsutils:1.3
command:
- sleep
- '3600'
imagePullPolicy: ifNotPresent
restartPolicy: Always
```
You can pass the `-o` (or `--output`) flag to save the output into a file.
As you can see, we can easily translate EDN to YAML. You can define multiple YAML resources into the same file as well:
```clojure
[{:name "yaml-file-1"}
{:name "yaml-file-2"}]
```
`kvert` will output:
```yaml
---
name: yaml-file-1
---
name: yaml-file-2
```
### Customizations
EDN supports `readers`, which can be used to extend it. Let's now put in `pod.edn` this content:
```clojure
{:apiVersion "v1"
:kind "Pod"
:metadata {:name "dnsutils"
:namespace #kvert/var :namespace}
:spec {:containers [{:name "dnsutils"
:image #join ["k8s.gcr.io/e2e-test-images/jessie-dnsutils:" #kvert/var :container-version]
:command ["sleep" #or [#env SLEEP_DURATION 3600]]
:imagePullPolicy #profile {:production "ifNotPresent"
:default "Always"}}]
:restartPolicy "Always"}}
```
As you an see, we use a few readers (which start with `#`) in this file:
- `#kvert/var` which will replace the next keyword (`:namespace` for example here) with a variable value
- `#join` which will concatenate several values together
- `#or` which allows you to define default values
- `#env` to read values from environment variables
- `#profile` which create a switch based on the value on the profile you used to run `kvert` (more on that later). This reader also supports default values in `:default`
Readers can be combined together, like in `["sleep" #or [#env SLEEP_DURATION 3600]]` in this example which will first read the SLEEP_DURATION environment variable and fallback to `3600` if it's not defined.
Let's create a new file named `config.edn`:
```clojure
{:variables {:namespace "default"
:container-version "1.3"}
:profile :production}
```
This file defines variables (referenced by `#kvert/var` in the `pod.edn` file) and the profile (`:production`).
Launch `kvert yaml --template pod.edn -c config.edn`, the output is:
```yaml
---
apiVersion: v1
kind: Pod
metadata:
name: dnsutils
namespace: default
spec:
containers:
- name: dnsutils
image: k8s.gcr.io/e2e-test-images/jessie-dnsutils:1.3
command:
- sleep
- 3600
imagePullPolicy: ifNotPresent
restartPolicy: Always
```
Thank to the readers we are able to customize our manifest. We could for example use variables and the profile to have variation between environment, kubernetes clusters...
## Profile
We configured in this example the profile into the `config.edn` file. You can also set it by configuring the `PROFILE` environment variable when running `kvert`.
## More readers
[Aero](https://github.com/juxt/aero), the library used by `kvert` to parse EDN files supports tons of readers out of the box. You can find them in the library [documentation](https://github.com/juxt/aero#tag-literals). Here are some interesting ones:
**#include**
For example, the `#include` reader allows you to include an EDN file into another one. Let's create a file named `example.edn` containing:
```clojure
{:apiVersion "v1"
:kind "Pod"
:metadata {:labels #include "labels.edn"}}
```
`labels.edn` (which can also contain readers if you need to) being:
```clojure
{:foo "bar"
:environment "prod"}
```
The output of `kvert yaml --template example.edn` will be:
```yaml
---
apiVersion: v1
kind: Pod
metadata:
labels:
foo: bar
environment: prod
```
**#kvert/include**
THe `#kvert/include` reader works exactly like `#include` but allows you to pass additional variables and configure another profile to the included file:
```clojure
{:apiVersion "v1"
:kind "Pod"
:metadata {:labels #kvert/include {:path "labels.edn"
:variables {:foo "bar"}
:profile :prod}}}
```
In this example, the content of the `labels.edn` file will be included. Additional variables (`:foo` in this example) are also provided and the profile is also overrided.
**#ref**
Another cool one is `#ref`, let's modify our `example.edn` with:
```clojure
{:apiVersion "v1"
:kind "Pod"
:metadata {:name "foo"
:labels {:name #ref [:metadata :name]}}}
```
This file will produce using `kvert yaml --template example.edn`:
```yaml
---
apiVersion: v1
kind: Pod
metadata:
name: foo
labels:
name: foo
```
As you can see, ref allows you to reference another part of your edn file.
Don't hesitate to check the Aero [documentation](https://github.com/juxt/aero#tag-literals) for more examples !
## Generate EDN from YAML
You can use `kvert` to convert an existing YAML file to EDN. This can help you to get started with the tool by using existing YAML files. An example with this file named `pod.yml`:
```yaml
---
apiVersion: v1
kind: Pod
metadata:
name: dnsutils
namespace: default
spec:
containers:
- name: dnsutils
image: k8s.gcr.io/e2e-test-images/jessie-dnsutils:1.3
command:
- sleep
- '3600'
imagePullPolicy: ifNotPresent
restartPolicy: Always
```
`kvert edn --template pod.yaml` will produce:
```clojure
[{:apiVersion "v1",
:kind "Pod",
:metadata {:name "dnsutils", :namespace "default"},
:spec
{:containers
[{:name "dnsutils",
:image "k8s.gcr.io/e2e-test-images/jessie-dnsutils:1.3",
:command ["sleep" "3600"],
:imagePullPolicy "ifNotPresent"}],
:restartPolicy "Always"}}]
```