Search code examples
yamlyq

yq replace value keep rest intact


I want just to replace a value in a multi .yaml file with yq and leaving the rest of the document intact. So the question is how do i replace the value of the image key only when the above key value contains name: node-red i have tried:

yq '.spec.template.spec.containers[] | select(.name = "node-red") | .image |= "test"' ./test.yaml`

with this yaml:

---
kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
  name: node-red
spec:
  ingressClassName: nginx-private
  rules:
    - host: node-red.k8s.lan
      http:
        paths:
          - path: "/"
            pathType: Prefix
            backend:
              service:
                name: node-red
                port:
                  number: 1880

---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: node-red
spec:
  replicas: 1
  selector:
    matchLabels:
      app: node-red
  template:
    metadata:
      labels:
        app: node-red
    spec:
      containers:
        - name: node-red
          image: "cir.domain.com/node-red:84"

the output is:

name: node-red
image: "test"

What I want is a yaml output with only a updated value in the image key like this:

---
kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
  name: node-red
spec:
  ingressClassName: nginx-private
  rules:
    - host: node-red.k8s.lan
      http:
        paths:
          - path: "/"
            pathType: Prefix
            backend:
              service:
                name: node-red
                port:
                  number: 1880

---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: node-red
spec:
  replicas: 1
  selector:
    matchLabels:
      app: node-red
  template:
    metadata:
      labels:
        app: node-red
    spec:
      containers:
        - name: node-red
          image: "test"

Solution

  • Keep the context by including the traversal and selection into the LHS of the assignment/update, ie. putting parentheses around all of it:

    yq '(.spec.template.spec.containers[] | select(.name == "node-red") | .image) |= "test"'
    

    In order to prevent the creation of elements previously not present in one of the documents, add filters using select accordingly, e.g.:

    yq '(.spec | select(.template).template.spec.containers[] | select(.name == "node-red").image) |= "test"'
    

    Note that in any case it should read == not = when checking for equality.