Search code examples
jsonbashshellyq

Use yq to substitute string in a yaml file


I am trying to substitute all substrings in a yaml file with yq.

File:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: <SOME_NAME>
  name: <SOME_NAME>
  namespace: default
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: <SOME_NAME>
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: <SOME_NAME>
    spec:
      serviceAccountName: api
      containers:
        - image: some-docker-repo/<SOME_NAME>:latest

Right now I am using command like this:

yq e '
  .metadata.labels.app = "the-name-to-use" |
  .metadata.name = "the-name-to-use" |
  .spec.selector.matchLabels.app = "the-name-to-use" |
  .spec.template.metadata.labels.app = "the-name-to-use" |
  .spec.template.spec.containers[0].image |= sub("<SOME_NAME>", "the-name-to-use")
' template.yaml  > result.yaml

But I am sure it can be done as a one-liner. I tried using different variations of

yq e '.[] |= sub("<SOME_NAME>", "the-name-to-use")' template.yaml  > result.yaml

but I am getting error like

Error: cannot substitute with !!map, can only substitute strings. Hint: Most often you'll want to use '|=' over '=' for this operation.

Can you please suggest where I might have missed the point?

As an extra request, how would it look like if there would be 2 substitutions in template file?

e.x. <SOME_NAME_1> and <SOME_NAME_2> that need to be substituted with some_var_1 and some_var_2 respectively.


Solution

  • The trick is to use '..' to match all the nodes, then filter out to only include strings

    yq e ' (.. | select(tag == "!!str")) |= sub("<SOME_NAME>", "the-name-to-use")' template.yaml
    

    Disclosure: I wrote yq