How to insert or add a field in a yaml after a specific key in yq

4/8/2020

I have a k8s yaml file with below block

spec:
  replicas: 1
  strategy:
    type: Recreate

and I want to add below block after "spec:"

selector:
  matchLabels:
    app: test-app

The file is huge and has many "spec:" fields, so it should be added at the first match.

Final file content should look like this :

spec:
  selector:
    matchLabels:
      app: test-app
  replicas: 1
  strategy:
    type: Recreate

I came up with this working solution using yq with correct indentation but it appends at the end of the file, Its painful to maintain and reading similar 100's of files.

yq  -i -y '.spec += {selector:{matchLabels:{app:"test-app"}}}' filename.yaml

Any answers with tools like sed or awk are welcome.

-- karthik101
jq
kubernetes
yaml
yq

3 Answers

4/8/2020

I'm not familiar with yq, but I know it supports limited JSON I/O. Here's a solution to the structural problem with jq:

.spec |= ({selector: {matchLabels: {app: "test-app"}}} + .)

Maybe worth a shot in native yq?

Sample pipeline (untested):

yq r -j k8s.yaml | jq "$script" | yq r --prettyPrint

There are also these jq yamlifiers by the incorrigible Jeff Mercado.

-- vintnes
Source: StackOverflow

4/9/2020

Here you go

$ yq --yaml-output '.spec |= ({selector: {matchLabels: {app: "test-app"}}} + .)' </tmp/your-yaml-file.yaml 

spec:
  selector:
    matchLabels:
      app: test-app
  replicas: 1
  strategy:
    type: Recreate

Since you mentioned you have hundreds of files and each has many spec elements, it's unclear if this will solve your actual problem but hopefully it can be of help. Good luck!

-- Bean Taxi
Source: StackOverflow

4/10/2020

You want a pickup-truck solution. I'm suggesting an Earth-mover instead.
(ATTENTION: Following requires Node.JS, Java-8 and command-line Git installed)..

npm install -g commander@2.20.0
npm install -g @asux.org/cli-npm
export NODE_PATH=`npm root -g`
asux

The above does installation.


For what you want.. Create a /tmp/batch-file.txt containing the following lines.

## This is a comment.  No temporary files are created by this.
saveTo !ORIGINALINPUT
yaml read spec
saveTo !SAVED
useAsInput !ORIGINALINPUT
yaml delete 'spec/*'
yaml insert spec @/tmp/HugeSelectorFile.yaml
yaml insert spec !SAVED

Run the command:

asux yaml batch @/tmp/batch-file.txt -i ./YOURORIGINAL.yaml -o ./NEW.yaml

ASSUMPTIONS:
1) Your original YAML file is ./YOURORIGINAL.yaml
2) You want a new file called ./NEW.yaml
3) Your "huge selector" file is called /tmp/HugeSelectorFile.yaml (see 2nd-last lime in batch.txt above)

NOTE: The '@' character prefixing file-names is by-design (as without that '@' character, it means you are passing in JSON/YAML in-line within the command-line).

More can be found at https://github.com/org-asux/org-ASUX.github.io/wiki/Welcome-to-WIKI-for-org.ASUX

-- Sarma
Source: StackOverflow