Skip to content

feat: Environment variable helm args

This change adds a series of HELM_SET_* variables to set values in GitLab Auto DevOps Helm deployments. These follow a similar logic to K8S_SECRET_* or Terraform's TF_VAR_* variables, with the added functionality that underscores are interpreted as dot object notation and expanded:

HELM_SET_gitlab_app=example becomes: {"gitlab": {"app": "example"}}

Functionality and Behaviour

By default values will be assumed to be string litterals, (eg HELM_SET_foo=example has a value of "example").

Exceptions to this rule:

  • Values containing only digits are treated as numbers
  • An empty string is taken to mean null (not, "").
  • Values surrounded by [] or {} are parsed as JSON
  • Values surrounded by "" are always treated as string litterals
  • Objects with only numberic values are converted into arrays (eg see image.secrets in the example below)
Long Example
HELM_SET_examples_stringLiteral=example
HELM_SET_examples_numeric=123
HELM_SET_examples_inlineArray='[1,2,3]'
HELM_SET_examples_inlineObject='{"foo": "bar", "favouritePlatform": "GitHub"}'
HELM_SET_examples_inlineObject_addedField=foobar # This will merge with the object above
HELM_SET_examples_inlineObject_favourtePlatform=GitLab # This will override favouritePlatform above
HELM_SET_examples_forcedString='"123"'
HELM_SET_examples_nullValue=
HELM_SET_gitlab_app=example
HELM_SET_gitlab_env=production
HELM_SET_image_secrets_0_name=gitlab-registry-token
HELM_SET_image_secrets_1_name=another-registry-token
HELM_SET_image_tag='"123"' # Forced to be interpreted as a string
HELM_SET_livenessProbe='{"probeType": "exec", "command": ["echo", "Hello", "GitLab"]}'
HELM_SET_readinessProbe_port=80

Is equivalent to:

examples:
  stringLiteral: "example"
  numberic: 123
  inlineArray:
    - 1
    - 2
    - 3
  inlineObject:
    foo: "bar"
    addedField: "foobar"
    favouritePlatform: "GitLab"
  forcedString: "123"
  nullValue: ~

gitlab:
  app: "example"
  production: "production"

image:
  tag: "123"
  secrets:
    - name: "gitlab-registry-token"
    - name: "another-registry-token"

livenessProbe:
  probeType: "exec"
  command:
    - "echo"
    - "Hello"
    - "GitLab"

readinessProbe:
  port: 80

Reasoning

This proposal aims to solve two issues:

Firstly, while the .gitlab/auto-deploy-values.yaml file is useful, it is sometimes desirable to set values via CI variables so that they can be configured via the UI, or set at the Group level (if you have a group full of projects which are deployed in the same way).

Secondly, as has been pointed out in #31, values currently set by auto-devops are set as --set command line arguments, which are difficult to override in values files. This MR is a potential solution to that Issue.

While both of these issues can be resolved by the existing HELM_UPGRADE_EXTRA_ARGS environment variable, this does not create the nicest user experience when editing lots of values via CI Variables. Also, as this is just one variable, projects using more complex gitlab-ci setups have to share and piece this together. Splitting each value into its own environment variable, allows different ci templates / config to manage the values it needs.

Known Issues & Gotchas

The following is a list of potential drawbacks / gotchas with this approach. Nothing that IMO would make the MR un-mergable, however definately things to be aware of / worthy of discussion.

You cannot mix array creation styles

Unlike objects, you cannot mix and match between JSON and dot notation for arrays, eg:

# This works fine to produce {"gitlab": {"app": "example", "env": "production"}}
HELM_SET_gitlab='{"app":"example"}'
HELM_SET_gitlab_env=production

# This won't merge properly and you'll just end up with {"image": {"secrets": [{"name": "second-token"}]}}
HELM_SET_image_secrets='[{"name":"first-token"}]'
HELM_SET_image_secrets_1_name=second-token

# Sticking with one style, works, however: {"image": {"secrets": [{"name": "first-token"},{"name": "second-token"}]}}
HELM_SET_image_secrets_0_name=first-token
HELM_SET_image_secrets_1_name=second-token

Explictly defining an object with numeric keys still becomes an array:

# This will become {"example": ["foo", "bar"]}
HELM_SET_example='{"0": "foo", "1": "bar"}'

Array indicies don't actually matter at all

The actual values you set for array indicies, and indeed their order, don't really matter at all. All that is checked is that an object has only numerical fields. Their order is dependant on the order that variables are "seen" by the scraper. Examples:

# This is {"example": ["foo", "bar", "foobar"]}
HELM_SET_example_999=foo
HELM_SET_example_3=bar
HELM_SET_example_03=foobar # This is different

This could be a useful trick, however, when injecting the GitLab registry token. By using some high random number, users could set their own image secrets without knowing that "0" is offlimits":

# auto-deploy
HELM_SET_image_secrets_999_name=gitlab-registry-${CI_PROJECT_PATH_SLUG}

# User set somewhere w/ No collision:
HELM_SET_image_secrets_0_name=my-extra-secret

Lower case environment names

This is perhaps a matter of taste but it is a bit nasty having lower case characters in environment variable names. The only defence I can provide for this is that this is how Terraform TF_VAR_* variables work.

Edited by Emily Shepherd

Merge request reports