Programatically apply a single resource from a multi resource Kubernetes YAML file

Viewed 609

I have a file with three configmaps in it, like the one below.

apiVersion: v1
data:
  TEST: "one"
kind: ConfigMap
metadata:
  name: test-config-one
---
apiVersion: v1
data:
  TEST: "two"
kind: ConfigMap
metadata:
  name: test-config-two
---
apiVersion: v1
data:
  TEST: "three"
kind: ConfigMap
metadata:
  name: test-config-three

I'm trying to apply only test-config-three to the cluster. I know I can break that out into its own file and run kubectl apply -f test-config-three.yaml, but is there a way to do that without having to create a new file?

I was hoping to be able to do something like:

cat file.yml | yq <get only test-config-three> | kubectl apply -f -

But yq doesn't seem to support finding a single resource in a file. I also looked at tools like kubesplit but they tend to output all resources to separate files.

Is there a way to isolate and output a single resource from a yaml file containing multiple resources without creating a new file?

Update

Thanks to @Inian's answer below, I was able to get this full command working.

cat file.yml | yq e 'select(.data.TEST == "three")' - | kubectl apply -f -
2 Answers

There are two versions of yq implemented, one in Python and one in Go as I've highlighted in my answer at How can I parse a YAML file from a Linux shell script?

Using the Python version - kislyuk/yq

yq -y 'select(.data.TEST == "three")' yaml

Go version - mikefarah/yq

yq e 'select(.data.TEST == "three")' yaml

If you have python you can try following

export MYFILE=file.yml
export DOC_NUMBER=2

python3 -c "import yaml; print(yaml.dump(list(yaml.safe_load_all(open('"$MYFILE"')))["$DOC_NUMBER"]))" | kubectl apply -f -

yaml.safe_load_all(open('"$MYFILE"')) loads all the documents in the yaml file into a list. Then you are selecting "$DOC_NUMBER" document with ["$DOC_NUMBER"].

yaml.dump would dump the loaded object back into yaml format which is then printed.

Related