From 2cf4fd8b9e9fc7f21570c154540caf293a8e3c67 Mon Sep 17 00:00:00 2001 From: Jonathan Matthews Date: Tue, 4 Feb 2025 17:37:34 +0000 Subject: [PATCH] docs/tutorial: add Roger's CfgMgmtCamp 2025 demo This is a very quickly written page mirroring what Roger presented with Marcel at CfgMgmtCamp 2025, in order to have a page for folks to follow in the CUE workshop at the same conference. This is a temporary page, which will move to some other path/site/etc at some point. DO NOT SUBMIT Preview-Path: /docs/tutorial/cfgmgmtcamp-2025/ Signed-off-by: Jonathan Matthews Change-Id: Ia544d789e5325deb6c2fbb5ec633e741f3c86c25 Dispatch-Trailer: {"type":"trybot","CL":1208305,"patchset":3,"ref":"refs/changes/05/1208305/3","targetBranch":"master"} --- content/docs/tutorial/cfgmgmtcamp-2025/en.md | 309 ++++++++++++++++ .../tutorial/cfgmgmtcamp-2025/gen_cache.cue | 210 +++++++++++ .../docs/tutorial/cfgmgmtcamp-2025/page.cue | 5 + .../docs/tutorial/cfgmgmtcamp-2025/index.md | 350 ++++++++++++++++++ 4 files changed, 874 insertions(+) create mode 100644 content/docs/tutorial/cfgmgmtcamp-2025/en.md create mode 100644 content/docs/tutorial/cfgmgmtcamp-2025/gen_cache.cue create mode 100644 content/docs/tutorial/cfgmgmtcamp-2025/page.cue create mode 100644 hugo/content/en/docs/tutorial/cfgmgmtcamp-2025/index.md diff --git a/content/docs/tutorial/cfgmgmtcamp-2025/en.md b/content/docs/tutorial/cfgmgmtcamp-2025/en.md new file mode 100644 index 0000000000..16fdfdaf86 --- /dev/null +++ b/content/docs/tutorial/cfgmgmtcamp-2025/en.md @@ -0,0 +1,309 @@ +--- +title: Config Management Camp 2025 +authors: [rogpeppe, jpluscplusm] +toc_hide: true +no_index: true +--- + +{{{with _script_ "en" "HIDDEN: cue login"}}} +mkdir -p $HOME/.config/cue +cat < $HOME/.config/cue/logins.json +{"registries":{"registry.cue.works":{"access_token":"${TEST_USER_AUTHN_CUE_USER_NEW}","token_type":"Bearer"}}} +EOD +{{{end}}} + +Here's how we can use CUE with a registry, including: +- using CUE to validate existing non-CUE data files +- how we can use schemas in the Central Registry to do a better job of that +- how we can use CUE to define/generate configuration +- how we can abstract that into a reusable component (module) +- how we can publish that module to a registry + +A lot of this is quite new, so don't be surprised if you find a few +rough edges. That said, it's reliable enough for us to dogfood it +in our own services. + +# Scenario: + +We're at a company that produces lots of different Docker images. +The maintainers of each image are expected to provide a `docker-compose.yaml` +file that is used for testing the service. + +Here's an example. Create a new directory, and place this file as +`docker-compose.yaml` inside: + +{{{with upload "en" "docker-compose.yml broken"}}} +-- docker-compose.yaml -- +service: + frontend: + image: docker.io/library/nginx:latest + ports: + - "80:80" + volume: + - ./html:/usr/share/nginx/html + - ./config/nginx.conf:/etc/nginx/nginx.conf:ro + db: + image: docker.ru/library/postgres:17.0 +{{{end}}} + +What aspects of this structured data do we care about? + +1. it's a valid docker compose file +1. it exposes a service named "web" that exports the HTTP interface on port 8080 +1. if there's a database service, it must be one of a few acceptable versions of Postgres +1. all our images come from our approved registry + +Let's start by just checking the broad outline of what it means to be "a valid docker compose file", and that there's a web service specified. + +Create this file as `schema.cue` alongside the `docker-compose.yaml` file: + +{{{with upload "en" "schema"}}} +-- schema.cue -- +package splotpolicy + +#WebService: { + services!: { + web!: { + ports!: ["8080:80"] + ... + } + db?: { + image!: "docker.io/library/postgres:16.4" | + "docker.io/library/postgres:16.5" | + "docker.io/library/postgres:16.6" + ... + } + [string]: image!: =~"^docker\\.io/" + } + ... +} +{{{end}}} + +Validate your data file: + +{{{with script "en" "vet 1"}}} +! cue vet .:splotpolicy docker-compose.yaml -d '#WebService' +{{{end}}} + +Oh dear! We've definitely found at least one problem in our +`docker-compose.yaml` file: the top-level `services` field is missing. Correct +this in your YAML file, and re-run the `cue vet` command from above. + +As you re-run `cue vet`, you'll find that there are more problems in your +`docker-compose.yaml` file. `cue vet` is only satisfied when it's completely +silent. Try and correct each problem as `cue vet` points it out. + +{{}} +Don't worry if you can't figure out all the problems in our deliberately broken data file! + +If you get stuck, here's a *corrected* `docker-compose.yaml` file - copying the +contents over from here to your file is absolutely fine ... +{{}} + +Here's the corrected file that `cue vet` will have led you towards: +{{{with upload "en" "docker-compose.yaml fixed"}}} +#force +-- docker-compose.yaml -- +services: + web: + image: docker.io/library/nginx:latest + ports: + - "8080:80" + volume: + - ./html:/usr/share/nginx/html + - ./config/nginx.conf:/etc/nginx/nginx.conf:ro + db: + image: docker.io/library/postgres:16.4 +{{{end}}} + +There might be some minor differences, such as the specific version of Postgres that you chose, but anything that satisfies the schema is fine. + +Check that it satisfies the schema with a final `cue vet`: + +{{{with script "en" "vet 2"}}} +cue vet .:splotpolicy docker-compose.yaml -d '#WebService' +{{{end}}} + +This is great - we can now assert some useful properties of the docker compose +files that the company's developers are handing to us. But we're not doing as +much checking as we could ... + +Wouldn't it be nice if someone had done lots of the work for us already, +assembling a schema that validates the general *shape* of a docker compose +file? + +**Enter the Central Registry** + +The CUE Central Registry is a place where schemas are published that we can +tell the `cue` command to use, seamlessly. + +Place this CUE code in `FIXME.cue`: + +{{{with upload "en" "FIXME"}}} +-- FIXME.cue -- +package splotpolicy + +import ( + "github.com/cue-tmp/jsonschema-pub/exp2/dockercompose" +) + +#WebService: dockercompose.#Schema & { + ... +} +{{{end}}} + +This CUE *unifies* the upstream schema, imported from the registry, with our local `#WebService` definition. This combines the company-specific policy validation (such the frontend web service being called `web`) with the FIXME of the general docker compose schema. + +You'll notice that the import path looks a bit temporary - as indeed it is. But one of the important properties ... FIXME idempotency. + + + +FIXME: what is this? + +{{{with script "en" "mod init tidy"}}} +cue mod init cue.example +cue mod tidy +{{{end}}} + +After `cue mod tidy` completes, check out the contents of `cue.mod/module.cue`: + +{{{with script "en" "module.cue"}}} +cat cue.mod/module.cue +{{{end}}} + +Notice FIXME FIXME. + +Now let's re-run our `cue vet` command, taking advantage of the upstream FIXME. + +{{{with script "en" "cue vet against imported module fail"}}} +! cue vet .:splotpolicy docker-compose.yaml -d '#WebService' +{{{end}}} + +Whoops - it's spotted an error in our original YAML file: the `web` service's +`volume` key isn't allowed! Let's correct it to `volumes`, so we end up with +this really *really* fixed data file: + +{{{with upload "en" "docker-compose.yaml really fixed"}}} +#force +-- docker-compose.yaml -- +services: + web: + image: docker.io/library/nginx:latest + ports: + - "8080:80" + volumes: + - ./html:/usr/share/nginx/html + - ./config/nginx.conf:/etc/nginx/nginx.conf:ro + db: + image: docker.io/library/postgres:16.4 +{{{end}}} + +A quick `cue vet` shows us that we're -- at last! -- in possession of some properly formed data: + +{{{with script "en" "cue vet against imported module pass"}}} +cue vet .:splotpolicy docker-compose.yaml -d '#WebService' +{{{end}}} + +{{{with script "en" "start local registry"}}} +cue mod registry 127.0.0.1:55443 & +{{{end}}} +{{{with _script_ "en" "HIDDEN: sleep to allow registry to start"}}} +sleep 2 +{{{end}}} +{{{with script "en" "break this out into steps"}}} +cue mod edit --source self +cue mod rename github.com/cue-examples/splotpolicy +export CUE_REGISTRY=github.com/cue-examples=127.0.0.1:55443 +cue mod publish v0.0.1 +cue import -p splotservice1 -l 'content:' docker-compose.yaml +cat docker-compose.cue +{{{end}}} + +{{{with upload "en" "link splotpolicy and splotservice1"}}} +-- FIXME-linker.cue -- +package splotservice1 + +import "github.com/cue-examples/splotpolicy" + +content: splotpolicy.#WebService +{{{end}}} + +{{{with script "en" "cue vet of consumer module"}}} +cue vet .:splotservice1 +sed -i 's/postgres:16.4/postgres:17/' docker-compose.cue +! cue vet .:splotservice1 +sed -i 's/postgres:17/postgres:16.4/' docker-compose.cue +cue vet .:splotservice1 +{{{end}}} + +This is basically as far as we managed to get during the CfgMgmtCamp 2025 demo +\- but there's so much more to CUE + Central Registry! Come and talk to Marcel +or Roger at the CUE workshop to get hands-on help with your specific use +cases .. + + + + diff --git a/content/docs/tutorial/cfgmgmtcamp-2025/gen_cache.cue b/content/docs/tutorial/cfgmgmtcamp-2025/gen_cache.cue new file mode 100644 index 0000000000..871da4ef6f --- /dev/null +++ b/content/docs/tutorial/cfgmgmtcamp-2025/gen_cache.cue @@ -0,0 +1,210 @@ +package site +{ + content: { + docs: { + tutorial: { + "cfgmgmtcamp-2025": { + page: { + cache: { + upload: { + "docker-compose.yml broken": "nBv/jmH0YhokkSVvTyg3p9hcfAHST7YOeMcl7bvgqtc=" + schema: "6fnb7vf+X9a3fq5pSARl8XL2bBPfqpWmgh5t6MU7bk8=" + "docker-compose.yaml fixed": "si6jb17/CNBPJZkqK+2OXqkgAZYt8S9NLiyoXxd1xHk=" + FIXME: "dxfJPefCc7xmf3eFCk0nVVnkod1cEApVFwuBe6v5+bg=" + "docker-compose.yaml really fixed": "PZoccnmvGDL89i+HjHuG1xTfRuQ3stkBTb0oKZFdAeE=" + "link splotpolicy and splotservice1": "tvNgBJ8C+MNq7Q4ukXPlm0lCeLIID/O6CVIidJ4ZLWk=" + } + multi_step: { + hash: "OD63BJ8OBSPJSAILC40BRJA2C4F3QANG1ROB98P312R6LFL6LDFG====" + scriptHash: "VDODH76BBJBP58B7VA0BIV6KJ484AVVD05HCFJ3JTADH0SBHI8EG====" + steps: [{ + doc: "" + cmd: "mkdir -p $HOME/.config/cue" + exitCode: 0 + output: "" + }, { + doc: "" + cmd: """ + cat <$HOME/.config/cue/logins.json + {"registries":{"registry.cue.works":{"access_token":"${TEST_USER_AUTHN_CUE_USER_NEW}","token_type":"Bearer"}}} + EOD + """ + exitCode: 0 + output: "" + }, { + doc: "" + cmd: "cue vet .:splotpolicy docker-compose.yaml -d '#WebService'" + exitCode: 1 + output: """ + services: field is required but not present: + ./schema.cue:4:2 + + """ + }, { + doc: "" + cmd: "cue vet .:splotpolicy docker-compose.yaml -d '#WebService'" + exitCode: 0 + output: "" + }, { + doc: "" + cmd: "cue mod init cue.example" + exitCode: 0 + output: "" + }, { + doc: "" + cmd: "cue mod tidy" + exitCode: 0 + output: "" + }, { + doc: "" + cmd: "cat cue.mod/module.cue" + exitCode: 0 + output: """ + module: "cue.example" + language: { + \tversion: "v0.12.0" + } + deps: { + \t"github.com/cue-tmp/jsonschema-pub/exp2/dockercompose@v0": { + \t\tv: "v0.0.1" + \t\tdefault: true + \t} + } + + """ + }, { + doc: "" + cmd: "cue vet .:splotpolicy docker-compose.yaml -d '#WebService'" + exitCode: 1 + output: """ + services.web.volume: field not allowed: + .cache/cue/mod/extract/github.com/cue-tmp/jsonschema-pub/exp2/dockercompose@v0.0.1/schema.cue:8:2 + .cache/cue/mod/extract/github.com/cue-tmp/jsonschema-pub/exp2/dockercompose@v0.0.1/schema.cue:8:8 + .cache/cue/mod/extract/github.com/cue-tmp/jsonschema-pub/exp2/dockercompose@v0.0.1/schema.cue:18:22 + .cache/cue/mod/extract/github.com/cue-tmp/jsonschema-pub/exp2/dockercompose@v0.0.1/schema.cue:19:4 + .cache/cue/mod/extract/github.com/cue-tmp/jsonschema-pub/exp2/dockercompose@v0.0.1/schema.cue:19:30 + .cache/cue/mod/extract/github.com/cue-tmp/jsonschema-pub/exp2/dockercompose@v0.0.1/schema.cue:272:18 + .cache/cue/mod/extract/github.com/cue-tmp/jsonschema-pub/exp2/dockercompose@v0.0.1/schema.cue:475:3 + ./FIXME.cue:7:14 + ./docker-compose.yaml:6:5 + ./schema.cue:3:14 + ./schema.cue:7:4 + ./schema.cue:15:13 + + """ + }, { + doc: "" + cmd: "cue vet .:splotpolicy docker-compose.yaml -d '#WebService'" + exitCode: 0 + output: "" + }, { + doc: "" + cmd: "cue mod registry 127.0.0.1:55443 &" + exitCode: 0 + output: "" + }, { + doc: "" + cmd: "sleep 2" + exitCode: 0 + output: """ + listening on 127.0.0.1:55443 + + """ + }, { + doc: "" + cmd: "cue mod edit --source self" + exitCode: 0 + output: "" + }, { + doc: "" + cmd: "cue mod rename github.com/cue-examples/splotpolicy" + exitCode: 0 + output: "" + }, { + doc: "" + cmd: "export CUE_REGISTRY=github.com/cue-examples=127.0.0.1:55443" + exitCode: 0 + output: "" + }, { + doc: "" + cmd: "cue mod publish v0.0.1" + exitCode: 0 + output: """ + tagged github.com/cue-examples/splotpolicy@v0.0.1 + published github.com/cue-examples/splotpolicy@v0.0.1 to 127.0.0.1:55443/github.com/cue-examples/splotpolicy:v0.0.1 + + """ + }, { + doc: "" + cmd: "cue import -p splotservice1 -l 'content:' docker-compose.yaml" + exitCode: 0 + output: "" + }, { + doc: "" + cmd: "cat docker-compose.cue" + exitCode: 0 + output: """ + package splotservice1 + + content: services: { + \tweb: { + \t\timage: "docker.io/library/nginx:latest" + \t\tports: ["8080:80"] + \t\tvolumes: [ + \t\t\t"./html:/usr/share/nginx/html", + \t\t\t"./config/nginx.conf:/etc/nginx/nginx.conf:ro", + \t\t] + \t} + \tdb: image: "docker.io/library/postgres:16.4" + } + + """ + }, { + doc: "" + cmd: "cue vet .:splotservice1" + exitCode: 0 + output: "" + }, { + doc: "" + cmd: "sed -i 's/postgres:16.4/postgres:17/' docker-compose.cue" + exitCode: 0 + output: "" + }, { + doc: "" + cmd: "cue vet .:splotservice1" + exitCode: 1 + output: """ + content.services.db.image: 3 errors in empty disjunction: + content.services.db.image: conflicting values "docker.io/library/postgres:16.4" and "docker.io/library/postgres:17": + ./FIXME-linker.cue:5:10 + ./docker-compose.cue:12:13 + ./schema.cue:10:12 + content.services.db.image: conflicting values "docker.io/library/postgres:16.5" and "docker.io/library/postgres:17": + ./FIXME-linker.cue:5:10 + ./docker-compose.cue:12:13 + ./schema.cue:11:5 + content.services.db.image: conflicting values "docker.io/library/postgres:16.6" and "docker.io/library/postgres:17": + ./FIXME-linker.cue:5:10 + ./docker-compose.cue:12:13 + ./schema.cue:12:5 + + """ + }, { + doc: "" + cmd: "sed -i 's/postgres:17/postgres:16.4/' docker-compose.cue" + exitCode: 0 + output: "" + }, { + doc: "" + cmd: "cue vet .:splotservice1" + exitCode: 0 + output: "" + }] + } + } + } + } + } + } + } +} diff --git a/content/docs/tutorial/cfgmgmtcamp-2025/page.cue b/content/docs/tutorial/cfgmgmtcamp-2025/page.cue new file mode 100644 index 0000000000..2a14ffb083 --- /dev/null +++ b/content/docs/tutorial/cfgmgmtcamp-2025/page.cue @@ -0,0 +1,5 @@ +package site + +content: docs: tutorial: "cfgmgmtcamp-2025": page: { + testUserAuthn: ["cue-user-new"] +} diff --git a/hugo/content/en/docs/tutorial/cfgmgmtcamp-2025/index.md b/hugo/content/en/docs/tutorial/cfgmgmtcamp-2025/index.md new file mode 100644 index 0000000000..68d37aad85 --- /dev/null +++ b/hugo/content/en/docs/tutorial/cfgmgmtcamp-2025/index.md @@ -0,0 +1,350 @@ +--- +title: Config Management Camp 2025 +authors: [rogpeppe, jpluscplusm] +toc_hide: true +no_index: true +--- + +Here's how we can use CUE with a registry, including: +- using CUE to validate existing non-CUE data files +- how we can use schemas in the Central Registry to do a better job of that +- how we can use CUE to define/generate configuration +- how we can abstract that into a reusable component (module) +- how we can publish that module to a registry + +A lot of this is quite new, so don't be surprised if you find a few +rough edges. That said, it's reliable enough for us to dogfood it +in our own services. + +# Scenario: + +We're at a company that produces lots of different Docker images. +The maintainers of each image are expected to provide a `docker-compose.yaml` +file that is used for testing the service. + +Here's an example. Create a new directory, and place this file as +`docker-compose.yaml` inside: + +{{< code-tabs >}} +{{< code-tab name="docker-compose.yaml" language="yaml" area="top-left" >}} +service: + frontend: + image: docker.io/library/nginx:latest + ports: + - "80:80" + volume: + - ./html:/usr/share/nginx/html + - ./config/nginx.conf:/etc/nginx/nginx.conf:ro + db: + image: docker.ru/library/postgres:17.0 +{{< /code-tab >}}{{< /code-tabs >}} + +What aspects of this structured data do we care about? + +1. it's a valid docker compose file +1. it exposes a service named "web" that exports the HTTP interface on port 8080 +1. if there's a database service, it must be one of a few acceptable versions of Postgres +1. all our images come from our approved registry + +Let's start by just checking the broad outline of what it means to be "a valid docker compose file", and that there's a web service specified. + +Create this file as `schema.cue` alongside the `docker-compose.yaml` file: + +{{< code-tabs >}} +{{< code-tab name="schema.cue" language="cue" area="top-left" >}} +package splotpolicy + +#WebService: { + services!: { + web!: { + ports!: ["8080:80"] + ... + } + db?: { + image!: "docker.io/library/postgres:16.4" | + "docker.io/library/postgres:16.5" | + "docker.io/library/postgres:16.6" + ... + } + [string]: image!: =~"^docker\\.io/" + } + ... +} +{{< /code-tab >}}{{< /code-tabs >}} + +Validate your data file: + +```text { title="TERMINAL" type="terminal" codeToCopy="Y3VlIHZldCAuOnNwbG90cG9saWN5IGRvY2tlci1jb21wb3NlLnlhbWwgLWQgJyNXZWJTZXJ2aWNlJw==" } +$ cue vet .:splotpolicy docker-compose.yaml -d '#WebService' +services: field is required but not present: + ./schema.cue:4:2 +``` + +Oh dear! We've definitely found at least one problem in our +`docker-compose.yaml` file: the top-level `services` field is missing. Correct +this in your YAML file, and re-run the `cue vet` command from above. + +As you re-run `cue vet`, you'll find that there are more problems in your +`docker-compose.yaml` file. `cue vet` is only satisfied when it's completely +silent. Try and correct each problem as `cue vet` points it out. + +{{}} +Don't worry if you can't figure out all the problems in our deliberately broken data file! + +If you get stuck, here's a *corrected* `docker-compose.yaml` file - copying the +contents over from here to your file is absolutely fine ... +{{}} + +Here's the corrected file that `cue vet` will have led you towards: +{{< code-tabs >}} +{{< code-tab name="docker-compose.yaml" language="yaml" area="top-left" >}} +services: + web: + image: docker.io/library/nginx:latest + ports: + - "8080:80" + volume: + - ./html:/usr/share/nginx/html + - ./config/nginx.conf:/etc/nginx/nginx.conf:ro + db: + image: docker.io/library/postgres:16.4 +{{< /code-tab >}}{{< /code-tabs >}} + +There might be some minor differences, such as the specific version of Postgres that you chose, but anything that satisfies the schema is fine. + +Check that it satisfies the schema with a final `cue vet`: + +```text { title="TERMINAL" type="terminal" codeToCopy="Y3VlIHZldCAuOnNwbG90cG9saWN5IGRvY2tlci1jb21wb3NlLnlhbWwgLWQgJyNXZWJTZXJ2aWNlJw==" } +$ cue vet .:splotpolicy docker-compose.yaml -d '#WebService' +``` + +This is great - we can now assert some useful properties of the docker compose +files that the company's developers are handing to us. But we're not doing as +much checking as we could ... + +Wouldn't it be nice if someone had done lots of the work for us already, +assembling a schema that validates the general *shape* of a docker compose +file? + +**Enter the Central Registry** + +The CUE Central Registry is a place where schemas are published that we can +tell the `cue` command to use, seamlessly. + +Place this CUE code in `FIXME.cue`: + +{{< code-tabs >}} +{{< code-tab name="FIXME.cue" language="cue" area="top-left" >}} +package splotpolicy + +import ( + "github.com/cue-tmp/jsonschema-pub/exp2/dockercompose" +) + +#WebService: dockercompose.#Schema & { + ... +} +{{< /code-tab >}}{{< /code-tabs >}} + +This CUE *unifies* the upstream schema, imported from the registry, with our local `#WebService` definition. This combines the company-specific policy validation (such the frontend web service being called `web`) with the FIXME of the general docker compose schema. + +You'll notice that the import path looks a bit temporary - as indeed it is. But one of the important properties ... FIXME idempotency. + + + +FIXME: what is this? + +```text { title="TERMINAL" type="terminal" codeToCopy="Y3VlIG1vZCBpbml0IGN1ZS5leGFtcGxlCmN1ZSBtb2QgdGlkeQ==" } +$ cue mod init cue.example +$ cue mod tidy +``` + +After `cue mod tidy` completes, check out the contents of `cue.mod/module.cue`: + +```text { title="TERMINAL" type="terminal" codeToCopy="Y2F0IGN1ZS5tb2QvbW9kdWxlLmN1ZQ==" } +$ cat cue.mod/module.cue +module: "cue.example" +language: { + version: "v0.12.0" +} +deps: { + "github.com/cue-tmp/jsonschema-pub/exp2/dockercompose@v0": { + v: "v0.0.1" + default: true + } +} +``` + +Notice FIXME FIXME. + +Now let's re-run our `cue vet` command, taking advantage of the upstream FIXME. + +```text { title="TERMINAL" type="terminal" codeToCopy="Y3VlIHZldCAuOnNwbG90cG9saWN5IGRvY2tlci1jb21wb3NlLnlhbWwgLWQgJyNXZWJTZXJ2aWNlJw==" } +$ cue vet .:splotpolicy docker-compose.yaml -d '#WebService' +services.web.volume: field not allowed: + .cache/cue/mod/extract/github.com/cue-tmp/jsonschema-pub/exp2/dockercompose@v0.0.1/schema.cue:8:2 + .cache/cue/mod/extract/github.com/cue-tmp/jsonschema-pub/exp2/dockercompose@v0.0.1/schema.cue:8:8 + .cache/cue/mod/extract/github.com/cue-tmp/jsonschema-pub/exp2/dockercompose@v0.0.1/schema.cue:18:22 + .cache/cue/mod/extract/github.com/cue-tmp/jsonschema-pub/exp2/dockercompose@v0.0.1/schema.cue:19:4 + .cache/cue/mod/extract/github.com/cue-tmp/jsonschema-pub/exp2/dockercompose@v0.0.1/schema.cue:19:30 + .cache/cue/mod/extract/github.com/cue-tmp/jsonschema-pub/exp2/dockercompose@v0.0.1/schema.cue:272:18 + .cache/cue/mod/extract/github.com/cue-tmp/jsonschema-pub/exp2/dockercompose@v0.0.1/schema.cue:475:3 + ./FIXME.cue:7:14 + ./docker-compose.yaml:6:5 + ./schema.cue:3:14 + ./schema.cue:7:4 + ./schema.cue:15:13 +``` + +Whoops - it's spotted an error in our original YAML file: the `web` service's +`volume` key isn't allowed! Let's correct it to `volumes`, so we end up with +this really *really* fixed data file: + +{{< code-tabs >}} +{{< code-tab name="docker-compose.yaml" language="yaml" area="top-left" >}} +services: + web: + image: docker.io/library/nginx:latest + ports: + - "8080:80" + volumes: + - ./html:/usr/share/nginx/html + - ./config/nginx.conf:/etc/nginx/nginx.conf:ro + db: + image: docker.io/library/postgres:16.4 +{{< /code-tab >}}{{< /code-tabs >}} + +A quick `cue vet` shows us that we're -- at last! -- in possession of some properly formed data: + +```text { title="TERMINAL" type="terminal" codeToCopy="Y3VlIHZldCAuOnNwbG90cG9saWN5IGRvY2tlci1jb21wb3NlLnlhbWwgLWQgJyNXZWJTZXJ2aWNlJw==" } +$ cue vet .:splotpolicy docker-compose.yaml -d '#WebService' +``` + +```text { title="TERMINAL" type="terminal" codeToCopy="Y3VlIG1vZCByZWdpc3RyeSAxMjcuMC4wLjE6NTU0NDMgJg==" } +$ cue mod registry 127.0.0.1:55443 & +``` +```text { title="TERMINAL" type="terminal" codeToCopy="Y3VlIG1vZCBlZGl0IC0tc291cmNlIHNlbGYKY3VlIG1vZCByZW5hbWUgZ2l0aHViLmNvbS9jdWUtZXhhbXBsZXMvc3Bsb3Rwb2xpY3kKZXhwb3J0IENVRV9SRUdJU1RSWT1naXRodWIuY29tL2N1ZS1leGFtcGxlcz0xMjcuMC4wLjE6NTU0NDMKY3VlIG1vZCBwdWJsaXNoIHYwLjAuMQpjdWUgaW1wb3J0IC1wIHNwbG90c2VydmljZTEgLWwgJ2NvbnRlbnQ6JyBkb2NrZXItY29tcG9zZS55YW1sCmNhdCBkb2NrZXItY29tcG9zZS5jdWU=" } +$ cue mod edit --source self +$ cue mod rename github.com/cue-examples/splotpolicy +$ export CUE_REGISTRY=github.com/cue-examples=127.0.0.1:55443 +$ cue mod publish v0.0.1 +tagged github.com/cue-examples/splotpolicy@v0.0.1 +published github.com/cue-examples/splotpolicy@v0.0.1 to 127.0.0.1:55443/github.com/cue-examples/splotpolicy:v0.0.1 +$ cue import -p splotservice1 -l 'content:' docker-compose.yaml +$ cat docker-compose.cue +package splotservice1 + +content: services: { + web: { + image: "docker.io/library/nginx:latest" + ports: ["8080:80"] + volumes: [ + "./html:/usr/share/nginx/html", + "./config/nginx.conf:/etc/nginx/nginx.conf:ro", + ] + } + db: image: "docker.io/library/postgres:16.4" +} +``` + +{{< code-tabs >}} +{{< code-tab name="FIXME-linker.cue" language="cue" area="top-left" >}} +package splotservice1 + +import "github.com/cue-examples/splotpolicy" + +content: splotpolicy.#WebService +{{< /code-tab >}}{{< /code-tabs >}} + +```text { title="TERMINAL" type="terminal" codeToCopy="Y3VlIHZldCAuOnNwbG90c2VydmljZTEKc2VkIC1pICdzL3Bvc3RncmVzOjE2LjQvcG9zdGdyZXM6MTcvJyBkb2NrZXItY29tcG9zZS5jdWUKY3VlIHZldCAuOnNwbG90c2VydmljZTEKc2VkIC1pICdzL3Bvc3RncmVzOjE3L3Bvc3RncmVzOjE2LjQvJyBkb2NrZXItY29tcG9zZS5jdWUKY3VlIHZldCAuOnNwbG90c2VydmljZTE=" } +$ cue vet .:splotservice1 +$ sed -i 's/postgres:16.4/postgres:17/' docker-compose.cue +$ cue vet .:splotservice1 +content.services.db.image: 3 errors in empty disjunction: +content.services.db.image: conflicting values "docker.io/library/postgres:16.4" and "docker.io/library/postgres:17": + ./FIXME-linker.cue:5:10 + ./docker-compose.cue:12:13 + ./schema.cue:10:12 +content.services.db.image: conflicting values "docker.io/library/postgres:16.5" and "docker.io/library/postgres:17": + ./FIXME-linker.cue:5:10 + ./docker-compose.cue:12:13 + ./schema.cue:11:5 +content.services.db.image: conflicting values "docker.io/library/postgres:16.6" and "docker.io/library/postgres:17": + ./FIXME-linker.cue:5:10 + ./docker-compose.cue:12:13 + ./schema.cue:12:5 +$ sed -i 's/postgres:17/postgres:16.4/' docker-compose.cue +$ cue vet .:splotservice1 +``` + +This is basically as far as we managed to get during the CfgMgmtCamp 2025 demo +\- but there's so much more to CUE + Central Registry! Come and talk to Marcel +or Roger at the CUE workshop to get hands-on help with your specific use +cases .. + + + +