yq: how to read a sibling element value?

1.5k views Asked by At

I am exploring yq to modify my YAML where I want to add a new element under spec of the ImageStream with name == openshift45

apiVersion: v1
items:
- apiVersion: image.openshift.io/v1
  kind: ImageStream
  metadata:
    annotations:
      openshift.io/generated-by: OpenShiftNewApp
    creationTimestamp: null
    labels:
      app: openshift45
      app.kubernetes.io/component: openshift45
      app.kubernetes.io/instance: openshift45
    name: nodejs-10
  spec:
    lookupPolicy:
      local: false
    tags:
    - annotations:
        openshift.io/imported-from: registry.access.redhat.com/ubi8/nodejs-10
      from:
        kind: DockerImage
        name: registry.access.redhat.com/ubi8/nodejs-10
      generation: null
      importPolicy: {}
      name: latest
      referencePolicy:
        type: ""
  status:
    dockerImageRepository: ""
- apiVersion: image.openshift.io/v1
  kind: ImageStream
  metadata:
    annotations:
      openshift.io/generated-by: OpenShiftNewApp
    creationTimestamp: null
    labels:
      app: openshift45
      app.kubernetes.io/component: openshift45
      app.kubernetes.io/instance: openshift45
    name: openshift45
  spec:
    lookupPolicy:
      local: false
  status:
    dockerImageRepository: ""

The below command returns the valid metadata element. Now, I want to move to the parent and then pick spec. Is this possible with yq - https://github.com/mikefarah/yq?

yq r openshift45.yaml --printMode pv "items(kind==ImageStream).(name==openshift45)"

returns

items.[1].metadata:
  annotations:
    openshift.io/generated-by: OpenShiftNewApp
  creationTimestamp: null
  labels:
    app: openshift45
    app.kubernetes.io/component: openshift45
    app.kubernetes.io/instance: openshift45
  name: openshift45

Expected output:

apiVersion: v1
items:
- apiVersion: image.openshift.io/v1
  kind: ImageStream
  metadata:
    annotations:
      openshift.io/generated-by: OpenShiftNewApp
    creationTimestamp: null
    labels:
      app: openshift45
      app.kubernetes.io/component: openshift45
      app.kubernetes.io/instance: openshift45
    name: nodejs-10
  spec:
    lookupPolicy:
      local: false
    tags:
    - annotations:
        openshift.io/imported-from: registry.access.redhat.com/ubi8/nodejs-10
      from:
        kind: DockerImage
        name: registry.access.redhat.com/ubi8/nodejs-10
      generation: null
      importPolicy: {}
      name: latest
      referencePolicy:
        type: ""
  status:
    dockerImageRepository: ""
- apiVersion: image.openshift.io/v1
  kind: ImageStream
  metadata:
    annotations:
      openshift.io/generated-by: OpenShiftNewApp
    creationTimestamp: null
    labels:
      app: openshift45
      app.kubernetes.io/component: openshift45
      app.kubernetes.io/instance: openshift45
    name: openshift45
  spec:
    *dockerImageRepository: <$MYREGISTRY>/<$MYNAMESPACE>/<$MYPROJECT>*
    lookupPolicy:
      local: false
  status:
    dockerImageRepository: ""
2

There are 2 answers

6
Inian On BEST ANSWER

The Path Expressions in mikefarah/yq is not quite documented to show a real example of how to use multiple conditions to get to the desired object. So for the YAML in question, using one unique condition you could do something like below. Verified in yq version 3.3.2

yq w openshift45.yaml 'items.(metadata.name == openshift45).spec.dockerImageRepository' '<$MYREGISTRY>/<$MYNAMESPACE>/<$MYPROJECT>'

You can use the -i flag along with write to modify the YAML in-place. See Updating files in-place

If this isn't desired and you need multiple conditional selection to get to the desired object, suggest raising a issue at the GitHub page - https://github.com/mikefarah/yq/issues requesting the right syntax for the same.

3
amsh On

Currently it is not possible in yq. You will have to get the output of first command in a variable and pass that variable to next one.

yq is a wrapper on jq but it doesn't have the functionality of custom functions. Custom functions make it possible to use any value from any hierarchy of the document at one place.

Thanks to Inian for pointing out that OP is not using the wrapper yq version. Unfortunately, the version used also doesn't allow using custom functions for now.