apple / pkl-pantry

Shared Pkl packages
Apache License 2.0
229 stars 31 forks source link

[k8s.contrib] Convert K8sResources within the K8sResource #62

Open Avarei opened 3 weeks ago

Avarei commented 3 weeks ago

I have a CRD Object, which is used to create Kubernetes Resources in Remote Clusters. This CRD has a Field called manifest, which contains a full Kubernetes Manifest, which is to be deployed on the target Cluster.

While this field is not typesafe in the CRD itself, i would like it to be in Pkl. Here is a a simplified representation of the CRD as a Pkl Module.

What I tried

I created the following files and converted the yaml manifest to Pkl.

Object.pkl

// this is simplified from the actual CRD
module io.crossplane.kubernetes.v1alpha2.Object
extends "package://pkg.pkl-lang.org/pkl-k8s/k8s@1.0.1#/K8sResource.pkl"
import "package://pkg.pkl-lang.org/pkl-k8s/k8s@1.0.1#/K8sResource.pkl"
import "package://pkg.pkl-lang.org/pkl-k8s/k8s@1.0.1#/apimachinery/pkg/apis/meta/v1/ObjectMeta.pkl"

fixed apiVersion: "kubernetes.crossplane.io/v1alpha2"
fixed kind: "Object"

metadata: ObjectMeta?
spec: Spec
status: Status?
class Spec {
  manifest: K8sResource
}

class Status {
  manifest: K8sResource?
}

convert.pkl

amends "package://pkg.pkl-lang.org/pkl-pantry/k8s.contrib@1.0.1#/convert.pkl"
customResourceTemplates {
  ["Object"] {
    ["kubernetes.crossplane.io/v1alpha2"] = import("Object.pkl")
  }
}

object.yaml

apiVersion: kubernetes.crossplane.io/v1alpha2
kind: Object
metadata:
  name: hey
  namespace: world
spec:
  manifest:
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: foo
      namespace: bar
    data:
      exampleKey: exampleValue

Command

I ran the following command to convert from yaml to pkl.

pkl eval -p "input=object.yaml" -o object-actual.pkl convert.pkl

What I got

import "package://pkg.pkl-lang.org/pkl-k8s/k8s@1.0.1#/K8sResource.pkl"
import "Object.pkl" // <snipped absolute path>

resources: Listing<K8sResource> = new {
  new Object {
    metadata {
      name = "hey"
      namespace = "world"
    }
    spec {
      manifest {
        apiVersion = "v1"
        kind = "ConfigMap"
        metadata {
          name = "foo"
          namespace = "bar"
        }
        data {
          exampleKey = "exampleValue"
        }
      }
    }
  }
}

output {
  value = resources
  renderer = (K8sResource.output.renderer as YamlRenderer) {
    isStream = true
  }
}

What I want

import "package://pkg.pkl-lang.org/pkl-k8s/k8s@1.0.1#/K8sResource.pkl"
import "package://pkg.pkl-lang.org/pkl-k8s/k8s@1.0.1#/api/core/v1/ConfigMap.pkl"
import "Object.pkl"

resources: Listing<K8sResource> = new {
  new Object {
    metadata {
      name = "hey"
      namespace = "world"
    }
    spec {
      manifest = (ConfigMap) {
        metadata {
          name = "foo"
          namespace = "bar"
        }
        data {
          ["exampleKey"] = "exampleValue"
        }
      }
    }
  }
}

output {
  value = resources
  renderer = (K8sResource.output.renderer as YamlRenderer) {
    isStream = true
  }
}