How to update a multi document yaml file on condition using yq? - kubernetes

I am trying to add namespace to a multi document kubernetes yaml file if it doesn't exist but if the namespace field already exists don't update it using yq but i can't seem to get it to work. Is this possible?
e.g.
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: serviceaccount1
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: serviceaccount2
namespace: namespace2
should end up something like this:
apiVersion: v1
kind: ServiceAccount
metadata:
name: serviceaccount1
namespace: namespace1
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: serviceaccount2
namespace: namespace2
UPDATE:
After successfully updating the yaml file thanks to:
https://stackoverflow.com/a/74736018/16126608
I am getting the namespace populated however due to the fact my yaml file was produced as an output of a helm template I am seeing the following issue where an empty document is having {} added as a result of the yq command, e.g.
---
# Source: path/to/chart/templates/configmap.yaml
---
# Source: ppath/to/chart/templates/network-policy.yaml
---
Is coming out like this afterwards:
---
# Source: path/to/chart/templates/configmap.yaml
---
{}
# Source: path/to/chart/templates/network-policy.yaml
---
{}
Is it possible to have yq to not add the {} and ignore the empty documents?
I am using mikefarah/yq

You can use has to check the existence of a field, and not to negate, then select it and add the new field.
Which implementation of yq are you using?
Using kislyuk/yq:
yq -y 'select(.metadata | has("namespace") | not).metadata.namespace = "namespace1"'
Using mikefarah/yq:
yq 'select(.metadata | has("namespace") | not) |= .metadata.namespace = "namespace1"'

Related

YAML code to create a configmap with a particular file (.js/.sh)

What will be the equivalent ConfigMap YAML code for the following command line?
kubectl create configmap mongo-initdb --from-file=init-mongo.js
There is actually a kubectl command that lets you get the generated yaml for a created config map. In your case:
kubectl get configmaps mongo-initdb -o yaml
You can use the command as suggested by Mo Xue, however here is YAML,
Example :
apiVersion: v1
kind: ConfigMap
metadata:
name: mongo-initdb
data:
init-mongo.js: |
<Content>
Read more about : https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#create-configmaps-from-directories
Create the configmap from a file.
Just create a sample file like ui.properties
example:
cat ui.properties
1. name=x
2. rollno=y
Command to create a configmap from above file
kubectl create configmap ui-configmap --from-file=ui.properties
Verify the data.
kubectl get configmap ui-configmap -o yaml
apiVersion: v1
kind: ConfigMap
metadata:
creationTimestamp: <>
name: ui-configmap
namespace: default
data:
name: x
role: y

How can I make a dependent on K8S configuration file?

I have below k8s configuration yml file but when run kubectl apply, it gives me the error namespaces "aws-observability" not found.
I understand that the aws-observability namespace is not deployed when deploying the ConfigMap.
It can be solved by split this config to two files and deploy the namespace first then the ConfigMap. But I'd like to put them in one file and deploy them in one go. How can I add a depend between these two configurations?
kind: Namespace
apiVersion: v1
metadata:
name: aws-observability
labels:
aws-observability: enabled
kind: ConfigMap
apiVersion: v1
metadata:
name: aws-logging
namespace: aws-observability
labels:
data:
output.conf: |
[OUTPUT]
Name cloudwatch
Match *
region <ap-southeast-2>
log_group_name elk-fluent-bit-cloudwatch
log_stream_prefix from-elk-fluent-bit-
auto_create_group true
You should add separator (---) between two components. I have tested below YAML on my machine and its working as expected:
kind: Namespace
apiVersion: v1
metadata:
name: aws-observability
labels:
aws-observability: enabled
---
kind: ConfigMap
apiVersion: v1
metadata:
name: aws-logging
namespace: aws-observability
labels:
data:
output.conf: |
[OUTPUT]
Name cloudwatch
Match *
region <ap-southeast-2>
log_group_name elk-fluent-bit-cloudwatch
log_stream_prefix from-elk-fluent-bit-
auto_create_group true

How to patch multi document yaml file on condition using yq?

Having YAML document something like:
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-scraping
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: allow-webhooks
I am trying to get something like
---
apiVersion: **networking.k8s.io/v1beta1**
kind: NetworkPolicy
metadata:
name: allow-scraping
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: allow-webhooks
So basically get document, if document has kind: NetworkPolicy then patch apiVersion: networking.k8s.io/v1beta1.
Ideally one liner, ideally with yq v4, but other solutions will be helpful too.
With mikefarah/yq on versions beyond 4, you could do a select and update |= operation on the required document
yq e 'select(.kind == "NetworkPolicy").apiVersion |= "networking.k8s.io/v1beta1"' yaml
The above works fine on yq version 4.6.0. Use the -i flag to replace the file in-place.
Given that other solutions will be helpful - an alternative solution would be using kustomize:
Create the kustomization.yaml file:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- network-policy.yaml
patches:
- target:
kind: NetworkPolicy
group: networking.k8s.io
version: v1
patch: |
- op: replace
path: /apiVersion
value: networking.k8s.io/v1beta1
Run
kustomize build | kubectl apply -f -
or
kubectl apply -k .

Kubernetes Ansible Operators - Patch an Existing Kubernetes Resource

With ansible: is it possible to patch resources with json or yaml snippets? I basically want to be able to accomplish the same thing as kubectl patch <Resource> <Name> --type='merge' -p='{"spec":{ "test":"hello }}', to append/modify resource specs.
https://docs.ansible.com/ansible/latest/modules/k8s_module.html
Is it possible to do this with the k8s ansible module? It says that if a resource already exists and "status: present" is set that it will patch it, however it isn't patching as far as I can tell
Thanks
Yes, you can provide just a patch and if the resource already exists it should send a strategic-merge-patch (or just a merge-patch if it's a custom resource). Here's an example playbook that creates and modifies a configmap:
---
- hosts: localhost
connection: local
gather_facts: no
vars:
cm: "{{ lookup('k8s',
api_version='v1',
kind='ConfigMap',
namespace='default',
resource_name='test') }}"
tasks:
- name: Create the ConfigMap
k8s:
definition:
apiVersion: v1
kind: ConfigMap
metadata:
name: test
namespace: default
data:
hello: world
- name: We will see the ConfigMap defined above
debug:
var: cm
- name: Add a field to the ConfigMap (this will be a PATCH request)
k8s:
definition:
apiVersion: v1
kind: ConfigMap
metadata:
name: test
namespace: default
data:
added: field
- name: The same ConfigMap as before, but with an extra field in data
debug:
var: cm
- name: Change a field in the ConfigMap (this will be a PATCH request)
k8s:
definition:
apiVersion: v1
kind: ConfigMap
metadata:
name: test
namespace: default
data:
hello: everyone
- name: The added field is unchanged, but the hello field has a new value
debug:
var: cm
- name: Delete the added field in the ConfigMap (this will be a PATCH request)
k8s:
definition:
apiVersion: v1
kind: ConfigMap
metadata:
name: test
namespace: default
data:
added: null
- name: The hello field is unchanged, but the added field is now gone
debug:
var: cm

Can we use "data" as a yaml file instead of Json file in Config map

lets take this example of a config map
apiVersion: v1
kind: ConfigMap
data:
abc.yml: |-
<yml here>
Getting an error like failed to parse yaml to Json.
Yes you can do that, but you should care about the syntax. You can also follow techniques for yaml from here.
If you use kubectl create configmap myconfig --from-file=abc.yml, then it is ok.
But if you write the whole yaml file for your configmap in myconfig.yaml and then run kubectl create -f myconfig.yaml, then you should care about syntax.
Say your abc.yml file is as followings:
a:
b: b1
c: c1
d: d1
Then write your myconfig.yaml file:
apiVersion: v1
kind: ConfigMap
data:
abc.yml: |
a:
b: b1
c: c1
d: d1
Now just run kubectl create -f myconfig.yaml.
That's it.
Happy Kubernetes!!!.
Create ConfigMap from file.
kubectl create configmap myconfig --from-file=youfile.yml.
You can check more examples on kubernetes docs
These could be the problems
1. most likely the issue could with the indentation.
2. remove '-' from abc.yml: |- and check
I followed the below steps and was able to load yaml file into configmap. it worked fine.
master $ cat c.yaml
apiVersion: v1
data:
redis-config: |
maxmemory 2mb
maxmemory-policy allkeys-lru
kind: ConfigMap
metadata:
name: example-redis-config
master $ kubectl create configmap testcfg --from-file=./c.yaml
master $ kubectl get cm testcfg -oyaml
apiVersion: v1
data:
c.yaml: |
apiVersion: v1
data:
redis-config: |
maxmemory 2mb
maxmemory-policy allkeys-lru
kind: ConfigMap
metadata:
name: example-redis-config
kind: ConfigMap
metadata:
creationTimestamp: 2019-03-07T08:35:18Z
name: testcfg
namespace: default
resourceVersion: "7520"
selfLink: /api/v1/namespaces/default/configmaps/testcfg
uid: f033536d-40b3-11e9-a67d-0242ac11005b