YLG Database for YAML generation

Rangaswamy P V
13 min readJun 15, 2023

--

In this article we will go over the concept of the “ylgdb.sh” Database that we created to generate a Kubernetes resource based YAML.

The database can be found in this repo.

A brief introduction of the database schema. Every entry has 3 values.

  1. The first the spec() ..which is the way it gets displayed in a YAML.
  2. The second is the value().. which is the user friendly display to input values in the values file.
  3. And finally the tag() which is a binary value of 0/1 , “0” meaning it is merely an header and does not hold the value and “1” meaning it holds a particular user defined value.
...
...
spec[4.1]="replicas:"
value[4.1]="Replicas"
tag[4.1]="1"
spec[4.3]="selector:"
value[4.3]="The selector details for the Pod if any"
tag[4.3]="0"
....
....

This is how the Database is built.

In order to generate the YAML for the k8s resources , we use a custom generator.sh script which in turn calls “gen.sh” and “fill.sh” to generate and populate the resource YAML. And also a custom variable “myindx”.

The Architecture:

All the generators are the same code but differ in the variable “myindx” which holds the starting index number in the database with the fields that needs to be omitted.

The “gen.sh” will generate the skeletal resource YAML and also a values file for the user to input values specific to his requirements. Then the same script with “fill.sh” passed as a command line to the file “generate.sh” file will fill the skeletal resource YAML file with the values that was user populated to generate the filled resource YAML which can then be applied to the Kubernetes resource.

Let us clone/pull the repo as shown below

$ git pull https://github.com/rangapv/CloudNative.git
remote: Enumerating objects: 2115, done.
remote: Counting objects: 100% (63/63), done.
remote: Compressing objects: 100% (45/45), done.
remote: Total 2115 (delta 30), reused 44 (delta 17), pack-reused 2052
Receiving objects: 100% (2115/2115), 26.85 MiB | 22.76 MiB/s, done.
Resolving deltas: 100% (1267/1267), done.
From https://github.com/rangapv/CloudNative
* branch HEAD -> FETCH_HEAD

To work with the Database I have a utility script in the repo under the YLG directory, that houses the “ylgdb.sh” database; it is called the “mul.sh”. You can invoke the script as shown below…

$ cd ylg
$ ls
README.md data draft index.sh mul.sh ylgdb.sh

ubuntu@ip-172-1-104-212:~/cn/ylg$ ./mul.sh -h
Usage: ./mul.sh function ( For list of functions defined in script )
./mul.sh -h ( For usage of this script )
./mul.sh -f ( List of Functions )
./mul.sh -d ( List of Database starting Index Numbers )

Now let us try one of the options. To list the functions that can be invoked on the database …

ubuntu@ip-172-1-104-212:~/cn/ylg$ ./mul.sh -f

*FUNCTION* *USE_CASE*
_________________________________________________________________________________________________

fix14 Sorts the database(usuage: ./mul.sh fix14)
fix51 Adds entries from a file in data directory to database(usuage: ./mul.sh fix51 httpRule.txt)
lint lints the file in data-directory (usuage: ./mul.sh lint GW.txt)
display1 enter the index for resource and level to display eg: 25-1 to display initContainer level 1;
dbdetails function is to display the Database starting index of various resource YAML currently in the database(YLGDB.sh)
fixshiftright function to Right-Shift Index varaible from start index to index index

..
..
..

Currently Database generates YAML definitions for the following k8s resources:

Namespace, Services, Deployment, Ingress, IngressClass, Configmap, StorageClass, Persistent Volume, PersistentVolume-Claim, Secrets, GatewayAPI, CertManager(JetStack).

To know all the starting indexes currently supported in the database there is a function called “dbdetails”. Invoke it as shown below


ubuntu@ip-172-1-222-164:~/cncf/ylg$ ./mul.sh -d
Version Begins from index 1
kind Begins from index 2
Metadata For this kind Begins from index 3
spec for the kind Deployment Begins from index 4
spec for the kind PV/PVC Begins from index 5
spec for the kind Service Begins from index 6
spec of configmap for Prometheus data Begins from index 7
spec of provisioner for aws/gcp/azure Begins from index 8
spec parameters of provisioner for aws/gcp/azure Begins from index 9
Spec to hold access/secret keys Begins from index 10
Spec for the container Begins from index 11
Details for PODS begin here- template Begins from index 20
spec for PODS affinity-taints- like scheduling constraints etc Begins from index 21
spec for PODS host-details- Specifies the hostname of the Pod(pods hostname will be set to a system-defined value) Begins from index 22
spec for PODS host-details- Host networking requested for this pod. Use the host's network namespace(Boolean default-false) Begins from index 23
spec for PODS secuirty-details- holds pod-level security attributes and common container settings Begins from index 24
spec for init-containers- The init container details for the Pod if any Begins from index 25
Spec for containers Begins from index 26
Spec for containers with setting resource limits- Compute Resources required by this container Begins from index 27
Spec for The ephemeral containers starts here Begins from index 28
Spec for various Volumes in PODS- List of volumes that can be mounted by containers belonging to the pod; Persistent Volume Claim Begins from index 29
spec for Volume Configmap Volume Begins from index 30
spec for Volume hostmap Begins from index 31
spec for Volume gitrepo volume Begins from index 32
spec for NFS- NFS volume associated with pod that can be used by Container-s Begins from index 33
spec for cephfs volume assoicated with pod that can be used by Container-s Begins from index 34
spec for csi volume assoicated with pod that can be used by Container-s Begins from index 35
spec for the rd block device volume assoicated with pod that can be used by Container-s Begins from index 36
Gateway Class specs Begins from index 37
Gateway specs Begins from index 38
Spec defines the desired state of HTTPRoute(CommonRouteSpec embedded) Begins from index 39
Spec defines the Cluster Issuer for a Cert-Manager Begins from index 42
Spec for IngressClass Begins from index 50
Spec for the Ingress Begins from index 51

..

Also the above values in tabular form…

If you would like to know what are the default values in the database(YLGDB.sh) for a particular index , then you can run the utility “mul.sh display1" as shown below with the indexnumer-depthlevel

ubuntu@ip-172-1-104-212:~/cn/ylg$ ./mul.sh display1
enter the index for resouce and level to display eg: 25-1 to display initContainer level 1;
25-2

initContainers:
- name:
image:
command:
volumeMounts:
- name:
mountPath:
ubuntu@ip-172-1-104-212:~/cn/ylg$ ./mul.sh display1
enter the index for resouce and level to display eg: 25-1 to display initContainer level 1;
25-1

initContainers:
- name:
image:
command:
volumeMounts:
- name:
ubuntu@ip-172-1-104-212:~/cn/ylg$ ./mul.sh display1
enter the index for resouce and level to display eg: 25-1 to display initContainer level 1;
26-1

containers:
- name:
image:
imagePullPolicy:
command:
args:
workingDir:
env:
envFrom:
ports:
volumeMounts:
volumeDevices:
ubuntu@ip-172-1-104-212:~/cn/ylg$ ./mul.sh display1
enter the index for resouce and level to display eg: 25-1 to display initContainer level 1;
26-2

containers:
- name:
image:
imagePullPolicy:
command:
args:
workingDir:
env:
name:
value:
valueFrom:
envFrom:
configMapRef:
prefix:
secretRef:
ports:
- containerPort:
volumeMounts:
- name:
volumeDevices:
- name:
devicePath:

From the above output one can choose what attributes that needs to be omitted for a particular index spec and include them in the round brackets next to the index number.

Lets us Look at an Example:

The generator.sh file takes in the variable “myindx” which specifies what specs from the database that the resource will hold. The code for a typical Deployment generator is shown below

#deployment-generaor.sh
#!/bin/bash

set -E

#The YAMl file name for this resource ; this can be changed
pvfile="dgr.yaml"
#The Values file name for this resource ; this can be changed
pvvfile="dgv.yaml"
#The starting Index in the database(ylgdb.sh) for this resource ; this can have multiple indexes depending on your particular use case
myindx="1,2,3(type annotations),4,20,25(mountPath),26(mountPath protocol command envFrom env workingDir volumeDevices),29,30(defaultMode)"


if [[ "$1" == "gen" ]]
then

source <(curl -s https://raw.githubusercontent.com/rangapv/CloudNative/main/generator/gen.sh) "gen" "$pvfile" "$pvvfile" "$myindx"

elif [[ "$1" == "fill" ]]
then

source <(curl -s https://raw.githubusercontent.com/rangapv/CloudNative/main/generator/gen.sh) "fill" "$pvfile" "$pvvfile" "$myindx"
else
echo "usuage: deployment-generator.sh gen/fill"

fi

If you observer there are variables “pvfile” and “pvvfile” these are the filename for generating skeletal YAML and the user generated values file. The user generated file is descriptive for the user to enter values that the YAML keys should hold, like number of replicas, restartPolicy etc. One can change the file names as required.

The next part “myindx” variable is the start index in the Database for this YAML resource definition.

myindx="1,2,3(type annotations),4,20,25(mountPath),26(mountPath protocol command envFrom env workingDir volumeDevices),29,30(defaultMode)"
#myindx="4"

I am saying for my deployment YAML items in the database(ylgdb.sh) are requiring spec from indexes 1,2,3,4,20,25,26,29 and 30.

If you are wondering why so many values, just a recall that Kubernetes deployment is a nested YAML spec. It contains the API section, the Pod spec which in turn has Container specs. Hence we are nesting those specs to generate the appropriate values. The indexes 1,2,3,4 are pretty common across all the resources for k8s( which encompasses api,version info,metadata etc of YAML). “20” is for Pod spec, “25” is for initContainer spec, “26” is for containers, “29” is for Volume spec for a Pod, and “30” is again Volume for pod but configmap type etc…

If you see there are entries in round brackets next to the Index number, for example “3” has {type and annotations}. What this means is that by default the database has these entries but in my current requirement there is no need for type or annotation hence , I am requesting it to be omitted during the YAML creation. No harm in including it in the generation and not filling in the value in values file, it just makes the YAML look decluttered. The same with container index 26 {mountPath protocol command envFrom env workingDir volumeDevices}. Here I am saying that I don't need envForm, env, workingDir, command values in the container spec for my specific use case.

Note: Anything that goes inside the round brackets next to the index are that needs to be EXCLUDED in the final YAML generation

All Deployment containers may not necessarily have a “volumeMounts” all the time so if you include this item(volumeMount) then the generator will not include volumeMount in the deployment YAML. Another example all Deployments may not have “initContainer” in the YAML definition so you do not include index number “25” in the variable “myindx”. If that is your particular use case.

Now just let us run the deployment generator script.

$ cd deployment/
ubuntu@ip-172-1-104-212:~/ft/generator/Prometheus/deployment$ ls
deployment-generator.sh dgr.yaml dgv.yaml

#Run the generator with gen argument
$ ./deployment-generator.sh gen

#This is the skeletal file First time generated
$vi dgr.yaml
apiVersion:
kind:
metadata:
name:
namespace:
labels:
app:
spec:
replicas:
selector:
matchLabels:
app:
strategy:
rollingUpdate:
maxSurge:
maxUnavailable:
type:
template:
metadata:
labels:
app:
spec:
initContainers:
- name:
image:
command:
volumeMounts:
- name:
mountPath:
containers:
- name:
image:
args:
ports:
- containerPort:
volumeMounts:
- name:
mountPath:
volumes:
- name:
configMap:
name:
- name:
persistentVolumeClaim:
claimName:

#This is the generated values file that user needs to populate with his values
$ vi dgv.yaml
Version:
kind:
Name for this kind:
Namespaces that you want this kind to be deployed:
app name to be referenced:
Replicas:
The app name for the Pod to match:
The max surge number for the Pod:
The max Unavailabe details for the Pod:
The strategy type for the Pod:
app name for the container:
The name for the init container:
The init container image:
The command to be executed for the init container:
The name for the volume mount in init container:
Name of this Container:
image tag:
args that may be needed to for the container to start/run:
containerports:
Name of the container mount points;mountpath:
Name of the Volume(configMapName):
Name fo this Configmap;DefaultMode:
Name of the Volume(PersistentVolumeClaim):
The Claim name of PersistentVolumeClaim:

#This is the user filled file , you can customize this with your values
$ vi dgv.yaml
Version:apps/v1
kind:Deployment
Name for this kind:prometheus
Namespaces that you want this kind to be deployed:monitoring
app name to be referenced:prometheus
Replicas:1
The app name for the Pod to match:prometheus
The max surge number for the Pod:1
The max Unavailabe details for the Pod:1
The strategy type for the Pod:RollingUpdate
app name for the container:prometheus
The name for the init container:prom-busy-bos-set-permis
The init container image:busybox
The command to be executed for the init container:["/bin/chmod","-R","777","/prometheus"]
Name of the volume mount in init container in the format mountpoints;mountpath :prometheus-storage;/prometheus
Name of this Container:prometheus
image tag:prom/prometheus:v2.44.0
args that may be needed to for the container to start/run:--storage.tsdb.retention=6h,--storage.tsdb.path=/prometheus,--config.file=/etc/prometheus/prometheus.yml
containerports:9090
Name of the container mount points;mountpath:prometheus-config;/etc/prometheus,prometheus-storage;/prometheus
Name of the Volume(configMapName):prometheus-config
Name fo this Configmap;DefaultMode:prometheus-config;420
Name of the Volume(PersistentVolumeClaim):prometheus-storage
The Claim name of PersistentVolumeClaim:pvc1-data

#Re-run the generator file with "fill" command line argument as show below
$ ./deployment-generator.sh fill


#Note the YAML is auto populated below with the values you entered in the above
$ vi dgr.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
name: prometheus
namespace: monitoring
labels:
app: prometheus
spec:
replicas: 1
selector:
matchLabels:
app: prometheus
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:
app: prometheus
spec:
initContainers:
- name: prom-busy-bos-set-permis
image: busybox
command: ["/bin/chmod","-R","777","/prometheus"]
volumeMounts:
- name: prometheus-storage
mountPath: /prometheus
containers:
- name: prometheus
image: prom/prometheus:v2.44.0
args:
- "--storage.tsdb.retention=6h"
- "--storage.tsdb.path=/prometheus"
- "--config.file=/etc/prometheus/prometheus.yml"
ports:
- containerPort: 9090
volumeMounts:
- name: prometheus-config
mountPath: /etc/prometheus
- name: prometheus-storage
mountPath: /prometheus
volumes:
- name: prometheus-config
configMap:
name: prometheus-config
defaultMode: 420
- name: prometheus-storage
persistentVolumeClaim:
claimName: pvc1-data


$ kubectl apply -f ./dgr.yaml
deployment.apps/prometheus created

Now lets look at “Persistentvolume-claim” , myindx is “1,2,3,5(capacity nfs csi)”. Again for the spec part, I want to omit “capacity”, “nfs” and “csi” items in the YAML definitions hence it goes right next to the index number 5. Note that these are valid choices for a PersistenVolumeClaim YAML, it is just that I am not using them in the present use case.

#pvc-generator.sh
#!/bin/bash


set -E

#The YAMl file name for this resource ; this can be changed
pvfile="pvc.yaml"
#The Values file name for this resource ; this can be changed
pvvfile="pvcv.yaml"
#The starting Index in the database(ylgdb.sh) for this resource ;
myindx="1,2,3,5(capacity nfs csi)"

if [[ "$1" == "gen" ]]
then
source <(curl -s https://raw.githubusercontent.com/rangapv/CloudNative/main/generator/gen.sh) "gen" "$pvfile" "$pvvfile" "$myindx"

elif [[ "$1" == "fill" ]]
then
source <(curl -s https://raw.githubusercontent.com/rangapv/CloudNative/main/generator/gen.sh) "fill" "$pvfile" "$pvvfile" "$myindx"
else
echo "usuage: pvc-generator.sh gen/fill"

fi

All the resource generators are the same and they differ in the “myindx” array values.

In the above file we have “myindx” is ..

myindx="1,2,3,5(capacity nfs csi)"

Since I am using Cloud based storage, I am omitting (nfs,csi..) parameters when generating my YAML in this particular case.

To know all of the valid arguments for any resource you can browse the definition in the database(YLGDB.sh) file and scroll to the index item. Or you could use the utility script “mul.sh” with “display1” functionality and give the starting indexnumer and the depth level(higher the value ..lists all values for a particular resource).

Usually for a particular resource it starts with a whole number so the entire “5” onwards until the next whole number 6 belongs to PersistentVolume-Claim resource. For service YAML the “myindx” starts from “6” up until “7”.

As an example let us look into Namespace generator as shown below. The “myindx” is “1,2,3(namespace labels annotations)”. Index “3” is for metadata and I am saying omit {namespace, labels and annotations} when generating Namespace YAML itself.

#ns-generator.sh
#!/bin/bash


set -E

#The YAMl file name for this resource ; this can be changed
pvfile="nsr.yaml"
#The Values file name for this resource ; this can be changed
pvvfile="nsv.yaml"
#The starting Index in the database(ylgdb.sh) for this resource ;
myindx="1,2,3(namespace labels annotations)"

if [[ "$1" == "gen" ]]
then
# source /home/ubuntu/cn/generator/gen.sh "gen" "$pvfile" "$pvvfile" "$myindx"
source <(curl -s https://raw.githubusercontent.com/rangapv/CloudNative/main/generator/gen.sh) "gen" "$pvfile" "$pvvfile" "$myindx"

elif [[ "$1" == "fill" ]]
then
#source /home/ubuntu/cn/generator/gen.sh "fill" "$pvfile" "$pvvfile" "$myindx"
source <(curl -s https://raw.githubusercontent.com/rangapv/CloudNative/main/generator/gen.sh) "fill" "$pvfile" "$pvvfile" "$myindx"
else
echo "usuage: ns-generator.sh gen/fill"

fi

Lets run this script …

ubuntu@ip-172-1-104-212:~/cn/generator/Prometheus$ cd namespace/
ubuntu@ip-172-1-104-212:~/ft/generator/Prometheus/namespace$ ls
ns-generator.sh nsr.yaml nsv.yaml nsv.yaml.bkp

$ ./ns-generator.sh gen

#This is the skeletal file First time generated
$ vi nsr.yaml
apiVersion:
kind:
metadata:
name:

#This is the generated values file that user needs to populate with his values
$ vi nsv.yaml

Version:
kind:
Name for this kind:

#This is the user filled file
$ vi nsv.yaml

Version: v1
kind: Namespace
Name for this kind: monitoring

#Re-run the generator file with "fill" command line argument as show below
$ ./ns-generator.sh fill


#Note the YAML is auto populated below with the values you entered in the above
$ vi nsr.yaml

apiVersion: v1
kind: Namespace
metadata:
name: monitoring

$ kubectl apply -f ./nsr.yaml
namespace/monitoring created

Likewise if you check other resources “myindx” will be different. For service-generation myindx is “6”.

You can also checkout this article on Prometheus Installs where I would have applied all the resource generator scripts.

And more Database entries for liveliness Probes, Readiness Probes etc.. are getting added to the Database.

If you have any issues , you can open issue in the github repo page or alternatively contact me at rangapv@yahoo.com or find me on Twitter @rangapv

--

--

Rangaswamy P V

Works on Devops in Startups, reach me @rangapv on X/twitter or email: rangapv@gmail.com