# Kubectl Fields: One-liner Kubernetes Resource Hierarchy Dumper

This blog post focuses on why I built the "Kubernetes resources hierarchy parser plugin". This plugin prints the hierarchy resources in one-liners & saves a ton of time for the end-users while writing or editing Kubernetes object configuration files.

**Github link:** [https://github.com/rewanthtammana/kubectl-fields](https://github.com/rewanthtammana/kubectl-fields)

### Problem Statement

For example, you want to add `capabilities`/`securitycontext` to your pod configuration. The only way to achieve this is by recursively expanding the `kubectl explain` and using the `grep` command. This default method to identify the hierarchy of specific fields for any resource in Kubernetes is cumbersome & tedious.

![rewanthtammana-kubectl-fields-tedious-default-approach.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1630670086713/N6_8Z15o_.png)

### Introduction to Kubernetes

> [Kubernetes](https://kubernetes.io/)  is an open-source container orchestration system for automating application deployment, scaling, and management.  [kubectl](https://kubernetes.io/docs/reference/kubectl/kubectl/)  provides a CLI interface to manage Kubernetes clusters. Kubectl enables the users to run different  [operations](https://kubernetes.io/docs/reference/kubectl/overview/#operations)  like describe, edit, exec, explain, logs, run, etc on Kubernetes clusters.

> Kubernetes objects can be created, updated, and deleted by writing object  [configuration files ](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/declarative-config/) either in declarative/imperative method. Kubernetes object configuration files need to follow a pre-defined parental hierarchy structure. All the configuration files need to be addressed in the same pre-defined sequential/parental order to get processed by Kubernetes.

### Kubectl CLI

> The kubectl CLI has an extended feature called **kubectl plugins** - this advanced feature allows the users to develop plugins to customize kubectl functionality. I leverage this feature & built this plugin to solve the inception problem.

### Default approach

Let' say you want to add `capabilities` to your pod configuration.

To achieve this, the first thing is to know the hierarchy of `capabilities` for chosen resources.

The current/default methodology to find the hierarchical order for any field is to use `grep` or similar commands for the specific field in the terminal.

```bash
$ kubectl explain --recursive po.spec | grep capabilities
         capabilities   <Object>
         capabilities   <Object>
```

The above result shows only the matched patterns but it doesn’t show the parental hierarchy. Alternatively, the search can be extended with grep advanced functionalities.

```bash
$ kubectl explain --recursive po.spec | grep capabilities -C 5
      resources <Object>
         limits <map[string]string>
         requests       <map[string]string>
      securityContext   <Object>
         allowPrivilegeEscalation       <boolean>
         capabilities   <Object>
            add <[]string>
            drop        <[]string>
         privileged     <boolean>
         procMount      <string>
         readOnlyRootFilesystem <boolean>
--
      resources <Object>
         limits <map[string]string>
         requests       <map[string]string>
      securityContext   <Object>
         allowPrivilegeEscalation       <boolean>
         capabilities   <Object>
            add <[]string>
            drop        <[]string>
         privileged     <boolean>
         procMount      <string>
         readOnlyRootFilesystem <boolean>
```

Though the above `grep` command gives us a rough idea of the hierarchy, it doesn’t show the complete sequence and we have to print the entire output & scroll through the terminal to find the right order.

<details>

<summary><strong>kubectl explain –recursive po.spec (click to expand 624 lines output)</strong></summary>

```bash
$ kubectl explain --recursive po.spec
KIND:     Pod
VERSION:  v1

RESOURCE: spec <Object>

DESCRIPTION:
     Specification of the desired behavior of the pod. More info:
     https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status

     PodSpec is a description of a pod.

FIELDS:
   activeDeadlineSeconds	<integer>
   affinity	<Object>
      nodeAffinity	<Object>
         preferredDuringSchedulingIgnoredDuringExecution	<[]Object>
            preference	<Object>
               matchExpressions	<[]Object>
                  key	<string>
                  operator	<string>
                  values	<[]string>
               matchFields	<[]Object>
                  key	<string>
                  operator	<string>
                  values	<[]string>
            weight	<integer>
         requiredDuringSchedulingIgnoredDuringExecution	<Object>
            nodeSelectorTerms	<[]Object>
               matchExpressions	<[]Object>
                  key	<string>
                  operator	<string>
                  values	<[]string>
               matchFields	<[]Object>
                  key	<string>
                  operator	<string>
                  values	<[]string>
      podAffinity	<Object>
         preferredDuringSchedulingIgnoredDuringExecution	<[]Object>
            podAffinityTerm	<Object>
               labelSelector	<Object>
                  matchExpressions	<[]Object>
                     key	<string>
                     operator	<string>
                     values	<[]string>
                  matchLabels	<map[string]string>
               namespaces	<[]string>
               topologyKey	<string>
            weight	<integer>
         requiredDuringSchedulingIgnoredDuringExecution	<[]Object>
            labelSelector	<Object>
               matchExpressions	<[]Object>
                  key	<string>
                  operator	<string>
                  values	<[]string>
               matchLabels	<map[string]string>
            namespaces	<[]string>
            topologyKey	<string>
      podAntiAffinity	<Object>
         preferredDuringSchedulingIgnoredDuringExecution	<[]Object>
            podAffinityTerm	<Object>
               labelSelector	<Object>
                  matchExpressions	<[]Object>
                     key	<string>
                     operator	<string>
                     values	<[]string>
                  matchLabels	<map[string]string>
               namespaces	<[]string>
               topologyKey	<string>
            weight	<integer>
         requiredDuringSchedulingIgnoredDuringExecution	<[]Object>
            labelSelector	<Object>
               matchExpressions	<[]Object>
                  key	<string>
                  operator	<string>
                  values	<[]string>
               matchLabels	<map[string]string>
            namespaces	<[]string>
            topologyKey	<string>
   automountServiceAccountToken	<boolean>
   containers	<[]Object>
      args	<[]string>
      command	<[]string>
      env	<[]Object>
         name	<string>
         value	<string>
         valueFrom	<Object>
            configMapKeyRef	<Object>
               key	<string>
               name	<string>
               optional	<boolean>
            fieldRef	<Object>
               apiVersion	<string>
               fieldPath	<string>
            resourceFieldRef	<Object>
               containerName	<string>
               divisor	<string>
               resource	<string>
            secretKeyRef	<Object>
               key	<string>
               name	<string>
               optional	<boolean>
      envFrom	<[]Object>
         configMapRef	<Object>
            name	<string>
            optional	<boolean>
         prefix	<string>
         secretRef	<Object>
            name	<string>
            optional	<boolean>
      image	<string>
      imagePullPolicy	<string>
      lifecycle	<Object>
         postStart	<Object>
            exec	<Object>
               command	<[]string>
            httpGet	<Object>
               host	<string>
               httpHeaders	<[]Object>
                  name	<string>
                  value	<string>
               path	<string>
               port	<string>
               scheme	<string>
            tcpSocket	<Object>
               host	<string>
               port	<string>
         preStop	<Object>
            exec	<Object>
               command	<[]string>
            httpGet	<Object>
               host	<string>
               httpHeaders	<[]Object>
                  name	<string>
                  value	<string>
               path	<string>
               port	<string>
               scheme	<string>
            tcpSocket	<Object>
               host	<string>
               port	<string>
      livenessProbe	<Object>
         exec	<Object>
            command	<[]string>
         failureThreshold	<integer>
         httpGet	<Object>
            host	<string>
            httpHeaders	<[]Object>
               name	<string>
               value	<string>
            path	<string>
            port	<string>
            scheme	<string>
         initialDelaySeconds	<integer>
         periodSeconds	<integer>
         successThreshold	<integer>
         tcpSocket	<Object>
            host	<string>
            port	<string>
         timeoutSeconds	<integer>
      name	<string>
      ports	<[]Object>
         containerPort	<integer>
         hostIP	<string>
         hostPort	<integer>
         name	<string>
         protocol	<string>
      readinessProbe	<Object>
         exec	<Object>
            command	<[]string>
         failureThreshold	<integer>
         httpGet	<Object>
            host	<string>
            httpHeaders	<[]Object>
               name	<string>
               value	<string>
            path	<string>
            port	<string>
            scheme	<string>
         initialDelaySeconds	<integer>
         periodSeconds	<integer>
         successThreshold	<integer>
         tcpSocket	<Object>
            host	<string>
            port	<string>
         timeoutSeconds	<integer>
      resources	<Object>
         limits	<map[string]string>
         requests	<map[string]string>
      securityContext	<Object>
         allowPrivilegeEscalation	<boolean>
         capabilities	<Object>
            add	<[]string>
            drop	<[]string>
         privileged	<boolean>
         procMount	<string>
         readOnlyRootFilesystem	<boolean>
         runAsGroup	<integer>
         runAsNonRoot	<boolean>
         runAsUser	<integer>
         seLinuxOptions	<Object>
            level	<string>
            role	<string>
            type	<string>
            user	<string>
         windowsOptions	<Object>
            gmsaCredentialSpec	<string>
            gmsaCredentialSpecName	<string>
      stdin	<boolean>
      stdinOnce	<boolean>
      terminationMessagePath	<string>
      terminationMessagePolicy	<string>
      tty	<boolean>
      volumeDevices	<[]Object>
         devicePath	<string>
         name	<string>
      volumeMounts	<[]Object>
         mountPath	<string>
         mountPropagation	<string>
         name	<string>
         readOnly	<boolean>
         subPath	<string>
         subPathExpr	<string>
      workingDir	<string>
   dnsConfig	<Object>
      nameservers	<[]string>
      options	<[]Object>
         name	<string>
         value	<string>
      searches	<[]string>
   dnsPolicy	<string>
   enableServiceLinks	<boolean>
   hostAliases	<[]Object>
      hostnames	<[]string>
      ip	<string>
   hostIPC	<boolean>
   hostNetwork	<boolean>
   hostPID	<boolean>
   hostname	<string>
   imagePullSecrets	<[]Object>
      name	<string>
   initContainers	<[]Object>
      args	<[]string>
      command	<[]string>
      env	<[]Object>
         name	<string>
         value	<string>
         valueFrom	<Object>
            configMapKeyRef	<Object>
               key	<string>
               name	<string>
               optional	<boolean>
            fieldRef	<Object>
               apiVersion	<string>
               fieldPath	<string>
            resourceFieldRef	<Object>
               containerName	<string>
               divisor	<string>
               resource	<string>
            secretKeyRef	<Object>
               key	<string>
               name	<string>
               optional	<boolean>
      envFrom	<[]Object>
         configMapRef	<Object>
            name	<string>
            optional	<boolean>
         prefix	<string>
         secretRef	<Object>
            name	<string>
            optional	<boolean>
      image	<string>
      imagePullPolicy	<string>
      lifecycle	<Object>
         postStart	<Object>
            exec	<Object>
               command	<[]string>
            httpGet	<Object>
               host	<string>
               httpHeaders	<[]Object>
                  name	<string>
                  value	<string>
               path	<string>
               port	<string>
               scheme	<string>
            tcpSocket	<Object>
               host	<string>
               port	<string>
         preStop	<Object>
            exec	<Object>
               command	<[]string>
            httpGet	<Object>
               host	<string>
               httpHeaders	<[]Object>
                  name	<string>
                  value	<string>
               path	<string>
               port	<string>
               scheme	<string>
            tcpSocket	<Object>
               host	<string>
               port	<string>
      livenessProbe	<Object>
         exec	<Object>
            command	<[]string>
         failureThreshold	<integer>
         httpGet	<Object>
            host	<string>
            httpHeaders	<[]Object>
               name	<string>
               value	<string>
            path	<string>
            port	<string>
            scheme	<string>
         initialDelaySeconds	<integer>
         periodSeconds	<integer>
         successThreshold	<integer>
         tcpSocket	<Object>
            host	<string>
            port	<string>
         timeoutSeconds	<integer>
      name	<string>
      ports	<[]Object>
         containerPort	<integer>
         hostIP	<string>
         hostPort	<integer>
         name	<string>
         protocol	<string>
      readinessProbe	<Object>
         exec	<Object>
            command	<[]string>
         failureThreshold	<integer>
         httpGet	<Object>
            host	<string>
            httpHeaders	<[]Object>
               name	<string>
               value	<string>
            path	<string>
            port	<string>
            scheme	<string>
         initialDelaySeconds	<integer>
         periodSeconds	<integer>
         successThreshold	<integer>
         tcpSocket	<Object>
            host	<string>
            port	<string>
         timeoutSeconds	<integer>
      resources	<Object>
         limits	<map[string]string>
         requests	<map[string]string>
      securityContext	<Object>
         allowPrivilegeEscalation	<boolean>
         capabilities	<Object>
            add	<[]string>
            drop	<[]string>
         privileged	<boolean>
         procMount	<string>
         readOnlyRootFilesystem	<boolean>
         runAsGroup	<integer>
         runAsNonRoot	<boolean>
         runAsUser	<integer>
         seLinuxOptions	<Object>
            level	<string>
            role	<string>
            type	<string>
            user	<string>
         windowsOptions	<Object>
            gmsaCredentialSpec	<string>
            gmsaCredentialSpecName	<string>
      stdin	<boolean>
      stdinOnce	<boolean>
      terminationMessagePath	<string>
      terminationMessagePolicy	<string>
      tty	<boolean>
      volumeDevices	<[]Object>
         devicePath	<string>
         name	<string>
      volumeMounts	<[]Object>
         mountPath	<string>
         mountPropagation	<string>
         name	<string>
         readOnly	<boolean>
         subPath	<string>
         subPathExpr	<string>
      workingDir	<string>
   nodeName	<string>
   nodeSelector	<map[string]string>
   preemptionPolicy	<string>
   priority	<integer>
   priorityClassName	<string>
   readinessGates	<[]Object>
      conditionType	<string>
   restartPolicy	<string>
   runtimeClassName	<string>
   schedulerName	<string>
   securityContext	<Object>
      fsGroup	<integer>
      runAsGroup	<integer>
      runAsNonRoot	<boolean>
      runAsUser	<integer>
      seLinuxOptions	<Object>
         level	<string>
         role	<string>
         type	<string>
         user	<string>
      supplementalGroups	<[]integer>
      sysctls	<[]Object>
         name	<string>
         value	<string>
      windowsOptions	<Object>
         gmsaCredentialSpec	<string>
         gmsaCredentialSpecName	<string>
   serviceAccount	<string>
   serviceAccountName	<string>
   shareProcessNamespace	<boolean>
   subdomain	<string>
   terminationGracePeriodSeconds	<integer>
   tolerations	<[]Object>
      effect	<string>
      key	<string>
      operator	<string>
      tolerationSeconds	<integer>
      value	<string>
   volumes	<[]Object>
      awsElasticBlockStore	<Object>
         fsType	<string>
         partition	<integer>
         readOnly	<boolean>
         volumeID	<string>
      azureDisk	<Object>
         cachingMode	<string>
         diskName	<string>
         diskURI	<string>
         fsType	<string>
         kind	<string>
         readOnly	<boolean>
      azureFile	<Object>
         readOnly	<boolean>
         secretName	<string>
         shareName	<string>
      cephfs	<Object>
         monitors	<[]string>
         path	<string>
         readOnly	<boolean>
         secretFile	<string>
         secretRef	<Object>
            name	<string>
         user	<string>
      cinder	<Object>
         fsType	<string>
         readOnly	<boolean>
         secretRef	<Object>
            name	<string>
         volumeID	<string>
      configMap	<Object>
         defaultMode	<integer>
         items	<[]Object>
            key	<string>
            mode	<integer>
            path	<string>
         name	<string>
         optional	<boolean>
      csi	<Object>
         driver	<string>
         fsType	<string>
         nodePublishSecretRef	<Object>
            name	<string>
         readOnly	<boolean>
         volumeAttributes	<map[string]string>
      downwardAPI	<Object>
         defaultMode	<integer>
         items	<[]Object>
            fieldRef	<Object>
               apiVersion	<string>
               fieldPath	<string>
            mode	<integer>
            path	<string>
            resourceFieldRef	<Object>
               containerName	<string>
               divisor	<string>
               resource	<string>
      emptyDir	<Object>
         medium	<string>
         sizeLimit	<string>
      fc	<Object>
         fsType	<string>
         lun	<integer>
         readOnly	<boolean>
         targetWWNs	<[]string>
         wwids	<[]string>
      flexVolume	<Object>
         driver	<string>
         fsType	<string>
         options	<map[string]string>
         readOnly	<boolean>
         secretRef	<Object>
            name	<string>
      flocker	<Object>
         datasetName	<string>
         datasetUUID	<string>
      gcePersistentDisk	<Object>
         fsType	<string>
         partition	<integer>
         pdName	<string>
         readOnly	<boolean>
      gitRepo	<Object>
         directory	<string>
         repository	<string>
         revision	<string>
      glusterfs	<Object>
         endpoints	<string>
         path	<string>
         readOnly	<boolean>
      hostPath	<Object>
         path	<string>
         type	<string>
      iscsi	<Object>
         chapAuthDiscovery	<boolean>
         chapAuthSession	<boolean>
         fsType	<string>
         initiatorName	<string>
         iqn	<string>
         iscsiInterface	<string>
         lun	<integer>
         portals	<[]string>
         readOnly	<boolean>
         secretRef	<Object>
            name	<string>
         targetPortal	<string>
      name	<string>
      nfs	<Object>
         path	<string>
         readOnly	<boolean>
         server	<string>
      persistentVolumeClaim	<Object>
         claimName	<string>
         readOnly	<boolean>
      photonPersistentDisk	<Object>
         fsType	<string>
         pdID	<string>
      portworxVolume	<Object>
         fsType	<string>
         readOnly	<boolean>
         volumeID	<string>
      projected	<Object>
         defaultMode	<integer>
         sources	<[]Object>
            configMap	<Object>
               items	<[]Object>
                  key	<string>
                  mode	<integer>
                  path	<string>
               name	<string>
               optional	<boolean>
            downwardAPI	<Object>
               items	<[]Object>
                  fieldRef	<Object>
                     apiVersion	<string>
                     fieldPath	<string>
                  mode	<integer>
                  path	<string>
                  resourceFieldRef	<Object>
                     containerName	<string>
                     divisor	<string>
                     resource	<string>
            secret	<Object>
               items	<[]Object>
                  key	<string>
                  mode	<integer>
                  path	<string>
               name	<string>
               optional	<boolean>
            serviceAccountToken	<Object>
               audience	<string>
               expirationSeconds	<integer>
               path	<string>
      quobyte	<Object>
         group	<string>
         readOnly	<boolean>
         registry	<string>
         tenant	<string>
         user	<string>
         volume	<string>
      rbd	<Object>
         fsType	<string>
         image	<string>
         keyring	<string>
         monitors	<[]string>
         pool	<string>
         readOnly	<boolean>
         secretRef	<Object>
            name	<string>
         user	<string>
      scaleIO	<Object>
         fsType	<string>
         gateway	<string>
         protectionDomain	<string>
         readOnly	<boolean>
         secretRef	<Object>
            name	<string>
         sslEnabled	<boolean>
         storageMode	<string>
         storagePool	<string>
         system	<string>
         volumeName	<string>
      secret	<Object>
         defaultMode	<integer>
         items	<[]Object>
            key	<string>
            mode	<integer>
            path	<string>
         optional	<boolean>
         secretName	<string>
      storageos	<Object>
         fsType	<string>
         readOnly	<boolean>
         secretRef	<Object>
            name	<string>
         volumeName	<string>
         volumeNamespace	<string>
      vsphereVolume	<Object>
         fsType	<string>
         storagePolicyID	<string>
         storagePolicyName	<string>
```
</details>

This is a tedious job and consumes a lot of time. If there are multiple matching fields in different objects, that only makes the situation worse.

### Proposed solution: kubectl-fields

I leveraged the *kubectl plugins* feature & built a plugin to demonstrate an alternative solution & approach to this problem.

`kubectl explain --recursive | grep` doesn’t show the exact hierarchy of matched fields, but this plugin does! `kubectl fields` solves this problem by printing a one-liner parental hierarchy of any field in any selected resource.

![kubectl-fields.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1622198111500/Dzy4aKMo2.png)

```bash
$ kubectl fields po capabilities
spec.containers.securityContext.capabilities
spec.ephemeralContainers.securityContext.capabilities
spec.initContainers.securityContext.capabilities
```

```bash
$ kubectl fields po.spec securitycontext
containers.securityContext
ephemeralContainers.securityContext
initContainers.securityContext
securityContext
```

### Bonus

`kubectl fields` is now integrated with  [krew](https://github.com/kubernetes-sigs/krew), a kubectl plugin manager. This plugin integration works on all platforms. So, this plugin can be installed directly with krew. It’s as simple as,

```bash
kubectl krew install fields
```

Huge thanks to [ahmetb](https://twitter.com/ahmetb) for the krew integration suggestion.

**References**

 [https://github.com/rewanthtammana/kubectl-fields](https://github.com/rewanthtammana/kubectl-fields) 

