Search code examples
replaceyamlyq

yq inline replace removes the rest of the file


I have the following yaml file

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-backend
  labels:
    app: app-backend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: app-backend
  template:
    metadata:
      labels:
        app: app-backend
    spec:
      serviceAccountName: app
#      securityContext:
#          fsGroup: 1001090001        
      containers:
      - name: app-backend
        image: registry/import-proj/app_backend:dc47096c66513dc252b21398e0307efd021c7c8e
        ports:
        - containerPort: 8080
        envFrom:
        - configMapRef:
            name: app-backend
        - secretRef:
            name: dbsecret
  strategy:
    type: Recreate                 
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-frontend
  labels:
    app: app-frontend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: app-frontend
  template:
    metadata:
      labels:
        app: app-frontend
    spec:
      serviceAccountName: app
#      securityContext:
#          fsGroup: 1001090002    
      containers:
      - name: app-frontend
        image: registry/import-proj/app_frontend:c6e525b71e5c9480330431e55418ff15dcbe4f36
        ports:
        - containerPort: 3000

I am trying to use yq to replace the tag c6e525b71e5c9480330431e55418ff15dcbe4f36 of app_frontend.

My command is the following -

yq eval-all -i 'select(.kind == "Deployment" and .metadata.name == "app-frontend") | .spec.template.spec.containers[] |= (select(.name == "app-frontend") | .image |= sub(":.*", ":new-tag"))' try.yaml

The problem is, the backend part is completely gone after replacement. I have tried using yq eval-all -i [] .|select(.. I cannot understand where the problem is.


Solution

  • Using the pipe in select(…) | .spec.template.spec.containers[] changes the primary context, and makes only the latter part being the LHS of the following update |=. Solution: Don't use it, just continue with the traversal after the selection, making all of it a single expression on the LHS of the update:

    select(…).spec.template.spec.containers[] |= (…)
    

    Alternatively, if you actually do need that pipe (because you just over-simplified this sample data, inadvertently rendering it dispensable), use parens to combine selection and traversal into one expression on the LHS of the update:

    (select(…) | … | .spec.template.spec.containers[]) |= (…)
    

    Tested with mikefarah/yq version v4.35.1

    Note that, at least with this sample input, you don't need the ea command. e does the job as well (and can even be omitted since version 4.18.1).