Using Mustache For Parameterizing Score Specifications

Markus Stahl
3 min readAug 21, 2023
Idea of score: define one spec, deploy on any target infrastructure.

Score is a developer-centric and platform-agnostic workload specification. Despite being developer-centric, it currently provides only limited parametrization capabilites.

Consider the following workload:

This will deploy the latest version of the famous hello-world container. Now, usually you are not interested in the hello-world container, but something more relevant. But often you are also not blindly interested on the latest version. Often you want to have a specific version for better tracebility.

You can update score files by overriding properties on comandline. For instance, if you want to deploy this previous workload to Humanitec, you could override the image property by

score-humanitec -p .containers.greeter.image=hello-world:$CI_PIPELINE_IID

When you build the image with the version of the current CI_PIPELINE_IID you have a specific version for your container that you could provide to Humanitec like this.

However, the property option has a few downsides:

  • you need to override the full path of the property, which is a bit complicated
  • the path of the property contains the name of the container — which might change! If you change the container name in score.yaml, you need to update all property-overrides in your CI pipeline. That is error-prone
  • property overrides only work on pure score files. If you use a score-implementation that requires override files (for instance: score-humanitec) for certain workloads, you cannot even use the -p option

For a developer-centric workload definition, we would like to have something like:

We could work with simple string replacement. But if we want to use score-humanitec we run in to the next issue: ${} is reserved for Humanitec values. How can we template our Score configs then?

Mustache Templates

Templating is not a Score specific challenge but generic across software engineering. The mustache templates tackle exactly that challenge. We are lucky, that the default syntax for Mustache templates are already different to the usualy ${} syntax:

Mustache templating engine is implemented in many popular programming language. I will demonstrate the python implementation here. But as we will work on command line only, you can easily choose any other implementation. Be aware though, that the template data format is sometimes different. Some implementation require the data as JSON others as YAML.

Check out Mustache website for other implementations than Python.

In this example, we will be using chevron which is the Python implementation for Mustache. Chevron require the parameters with their values in a json file. If we run a pipeline, we need to generate the JSON data dynamically. The following 2 commands create the JSON data for the Mustache template and replace the IMAGE_VERSION in the score.yaml file:

The result will be a score.yaml file with replaced parameters exactly as we had hoped for. Since the template engine is completely independent from Score, we can apply the commands on all kind of configurations.

In this example, more complex example, we create 1 JSON data file, rendering 2 Score files:

Summary

Parameterizing Score files is not comfortable, yet. By using Mustache templates we can configure Score files in our CI pipelines already today.

If you are interested in a demo project, review my project on Gitlab: https://gitlab.com/noordsestern/score-cronjob

The project even has a command line script (implemented in Python) replacing all Mustache templates with environment variables with the same name.

--

--

Markus Stahl

Sustainable automation with open source technologies.