Search code examples
kubernetesdhall

Is it possible to get a kubernetes object in json or yaml with all optional fields explicitly set to null?


I'm attempting to migrate a helm/kubernetes codebase to dhall-kubernetes. Dhall is typed, so I need to provide full records with optional fields set to null if there were not set. So I'm looking for something like kubectl get objname id -o yaml, but I need it to output all optional fields like fieldName: null. Is there a way to accomplish this? I don't know how to do it, so as a plan B I wrote dhall-default and I attempt to approach it in a different way.


Solution

  • I'll turn @sjakobi's solution into an answer like @dredozubov suggested

    You can pass the desired type from dhall-kubernetes to yaml-to-dhall and it will generate the equivalent Dhall code, albeit without any simplifications.

    As an example, suppose that you have the following Kubernetes resource:

    # ./nginx.yaml
    
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx
    spec:
      replicas: 2
      selector:
        matchLabels:
          name: nginx
      template:
        metadata:
          name: nginx
        spec:
          containers:
            - image: nginx:1.15.3
              name: nginx
              ports:
                - containerPort: 80
    

    ... and the following Dhall type for a Kubernetes deployment:

    -- ./Deployment.dhall
    
    let kubernetes = https://raw.githubusercontent.com/dhall-lang/dhall-kubernetes/506d633e382872346927b8cb9884d8b7382e6cab/package.dhall
    
    in  kubernetes.Deployment.Type
    

    Then you can translate the YAML to Dhall by running:

    $ yaml-to-dhall --file ./nginx.yaml ./Deployment.dhall
    

    The output is a bit large (~1300 lines), because yaml-to-dhall doesn't yet take advantage of support for default values, so I won't include the output here.

    If you pipe the result back into dhall-to-yaml then you will get the original Resource (albeit with fields sorted):

    $ yaml-to-dhall --file ./nginx.yaml ./Deployment.dhall | dhall-to-yaml 
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx
    spec:
      replicas: 2
      selector:
        matchLabels:
          name: nginx
      template:
        metadata:
          name: nginx
        spec:
          containers:
            - image: nginx:1.15.3
              name: nginx
              ports:
                - containerPort: 80
    

    ... and if you supply the --preserve-null option to dhall-to-yaml it will preserve all null fields as the question requests:

    $ yaml-to-dhall --file ./nginx.yaml ./Deployment.dhall | dhall-to-yaml --preserve-null 
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      annotations: null
      clusterName: null
      creationTimestamp: null
      deletionGracePeriodSeconds: null
      deletionTimestamp: null
      finalizers: null
      generateName: null
      generation: null
      labels: null
      managedFields: null
      name: nginx
      namespace: null
      ownerReferences: null
      resourceVersion: null
      selfLink: null
      uid: null
    spec:
      minReadySeconds: null
      paused: null
      progressDeadlineSeconds: null
      replicas: 2
      revisionHistoryLimit: null
      selector:
        matchExpressions: null
        matchLabels:
          name: nginx
      strategy: null
      template:
        metadata:
          annotations: null
          clusterName: null
          creationTimestamp: null
          deletionGracePeriodSeconds: null
          deletionTimestamp: null
          finalizers: null
          generateName: null
          generation: null
          labels: null
          managedFields: null
          name: nginx
          namespace: null
          ownerReferences: null
          resourceVersion: null
          selfLink: null
          uid: null
        spec:
          activeDeadlineSeconds: null
          affinity: null
          automountServiceAccountToken: null
          containers:
            - args: null
              command: null
              env: null
              envFrom: null
              image: nginx:1.15.3
              imagePullPolicy: null
              lifecycle: null
              livenessProbe: null
              name: nginx
              ports:
                - containerPort: 80
                  hostIP: null
                  hostPort: null
                  name: null
                  protocol: null
              readinessProbe: null
              resources: null
              securityContext: null
              startupProbe: null
              stdin: null
              stdinOnce: null
              terminationMessagePath: null
              terminationMessagePolicy: null
              tty: null
              volumeDevices: null
              volumeMounts: null
              workingDir: null
          dnsConfig: null
          dnsPolicy: null
          enableServiceLinks: null
          ephemeralContainers: null
          hostAliases: null
          hostIPC: null
          hostNetwork: null
          hostPID: null
          hostname: null
          imagePullSecrets: null
          initContainers: null
          nodeName: null
          nodeSelector: null
          overhead: null
          preemptionPolicy: null
          priority: null
          priorityClassName: null
          readinessGates: null
          restartPolicy: null
          runtimeClassName: null
          schedulerName: null
          securityContext: null
          serviceAccount: null
          serviceAccountName: null
          shareProcessNamespace: null
          subdomain: null
          terminationGracePeriodSeconds: null
          tolerations: null
          topologySpreadConstraints: null
          volumes: null
    status: null