From 6b98f336499134edddbd43d9b5c05e0f551f9d40 Mon Sep 17 00:00:00 2001 From: peefy Date: Thu, 11 Apr 2024 21:52:29 +0800 Subject: [PATCH] feat: add function pipeline ctx Signed-off-by: peefy --- README.md | 1 + examples/default/function_ctx/Makefile | 2 + examples/default/function_ctx/README.md | 113 ++++++++++++++++++ .../default/function_ctx/composition.yaml | 23 ++++ examples/default/function_ctx/functions.yaml | 9 ++ examples/default/function_ctx/xr.yaml | 6 + fn.go | 12 ++ pkg/resource/res.go | 8 ++ 8 files changed, 174 insertions(+) create mode 100644 examples/default/function_ctx/Makefile create mode 100644 examples/default/function_ctx/README.md create mode 100644 examples/default/function_ctx/composition.yaml create mode 100644 examples/default/function_ctx/functions.yaml create mode 100644 examples/default/function_ctx/xr.yaml diff --git a/README.md b/README.md index ff17e32..b640c5c 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ Here's what you can do in the KCL script: + Read the `ObservedComposedResources` from `option("params").ocds`. + Read the `DesiredCompositeResource` from `option("params").dxr`. + Read the `DesiredComposedResources` from `option("params").dcds`. ++ Read the function pipeline's context from `option("params").ctx`. ## Library diff --git a/examples/default/function_ctx/Makefile b/examples/default/function_ctx/Makefile new file mode 100644 index 0000000..f9a7429 --- /dev/null +++ b/examples/default/function_ctx/Makefile @@ -0,0 +1,2 @@ +run: + crossplane beta render xr.yaml composition.yaml functions.yaml -r diff --git a/examples/default/function_ctx/README.md b/examples/default/function_ctx/README.md new file mode 100644 index 0000000..7de91bc --- /dev/null +++ b/examples/default/function_ctx/README.md @@ -0,0 +1,113 @@ +# Example Manifests + +You can run your function locally and test it using `crossplane beta render` +with these example manifests. + +```shell +# Run the function locally +$ go run . --insecure --debug +``` + +```shell +# Then, in another terminal, call it with these example manifests +$ crossplane beta render xr.yaml composition.yaml functions.yaml -r +--- +apiVersion: example.crossplane.io/v1beta1 +kind: XR +metadata: + name: example +status: + dummy: cool-status +--- +apiVersion: iam.aws.upbound.io/v1beta1 +kind: AccessKey +metadata: + annotations: + crossplane.io/composition-resource-name: sample-access-key-1 + generateName: example- + labels: + crossplane.io/composite: example + name: sample-access-key-1 + ownerReferences: + - apiVersion: example.crossplane.io/v1beta1 + blockOwnerDeletion: true + controller: true + kind: XR + name: example + uid: "" +spec: + forProvider: + userSelector: + matchLabels: + testing.upbound.io/example-name: test-user-1 + writeConnectionSecretToRef: + name: sample-access-key-secret-1 + namespace: crossplane-system +--- +apiVersion: iam.aws.upbound.io/v1beta1 +kind: User +metadata: + annotations: + crossplane.io/composition-resource-name: test-user-0 + generateName: example- + labels: + crossplane.io/composite: example + dummy: foo + testing.upbound.io/example-name: test-user-0 + name: test-user-0 + ownerReferences: + - apiVersion: example.crossplane.io/v1beta1 + blockOwnerDeletion: true + controller: true + kind: XR + name: example + uid: "" +spec: + forProvider: {} +--- +apiVersion: iam.aws.upbound.io/v1beta1 +kind: AccessKey +metadata: + annotations: + crossplane.io/composition-resource-name: sample-access-key-0 + generateName: example- + labels: + crossplane.io/composite: example + name: sample-access-key-0 + ownerReferences: + - apiVersion: example.crossplane.io/v1beta1 + blockOwnerDeletion: true + controller: true + kind: XR + name: example + uid: "" +spec: + forProvider: + userSelector: + matchLabels: + testing.upbound.io/example-name: test-user-0 + writeConnectionSecretToRef: + name: sample-access-key-secret-0 + namespace: crossplane-system +--- +apiVersion: iam.aws.upbound.io/v1beta1 +kind: User +metadata: + annotations: + crossplane.io/composition-resource-name: test-user-1 + generateName: example- + labels: + crossplane.io/composite: example + dummy: foo + testing.upbound.io/example-name: test-user-1 + name: test-user-1 + ownerReferences: + - apiVersion: example.crossplane.io/v1beta1 + blockOwnerDeletion: true + controller: true + kind: XR + name: example + uid: "" +spec: + forProvider: {} +``` diff --git a/examples/default/function_ctx/composition.yaml b/examples/default/function_ctx/composition.yaml new file mode 100644 index 0000000..e3f0d37 --- /dev/null +++ b/examples/default/function_ctx/composition.yaml @@ -0,0 +1,23 @@ +apiVersion: apiextensions.crossplane.io/v1 +kind: Composition +metadata: + name: function-template-go +spec: + compositeTypeRef: + apiVersion: example.crossplane.io/v1 + kind: XR + mode: Pipeline + pipeline: + - step: normal + functionRef: + name: kcl-function + input: + apiVersion: krm.kcl.dev/v1alpha1 + kind: KCLRun + metadata: + name: basic + spec: + source: | + ctx = option("params").ctx + # Show function pipeline's context. + items = [{ctx = ctx}] diff --git a/examples/default/function_ctx/functions.yaml b/examples/default/function_ctx/functions.yaml new file mode 100644 index 0000000..602bf9b --- /dev/null +++ b/examples/default/function_ctx/functions.yaml @@ -0,0 +1,9 @@ +apiVersion: pkg.crossplane.io/v1beta1 +kind: Function +metadata: + name: kcl-function + annotations: + # This tells crossplane beta render to connect to the function locally. + render.crossplane.io/runtime: Development +spec: + package: xpkg.upbound.io/crossplane-contrib/function-kcl:latest diff --git a/examples/default/function_ctx/xr.yaml b/examples/default/function_ctx/xr.yaml new file mode 100644 index 0000000..27cae0a --- /dev/null +++ b/examples/default/function_ctx/xr.yaml @@ -0,0 +1,6 @@ +apiVersion: example.crossplane.io/v1beta1 +kind: XR +metadata: + name: example +spec: + count: 2 diff --git a/fn.go b/fn.go index ba4b275..63133ef 100644 --- a/fn.go +++ b/fn.go @@ -107,6 +107,18 @@ func (f *Function) RunFunction(_ context.Context, req *fnv1beta1.RunFunctionRequ response.Fatal(rsp, err) return rsp, nil } + // Set function context + ctxByte, err := req.Context.MarshalJSON() + if err != nil { + response.Fatal(rsp, err) + return rsp, nil + } + ctxObj, err := pkgresource.JsonByteToRawExtension(ctxByte) + if err != nil { + response.Fatal(rsp, err) + return rsp, nil + } + in.Spec.Params["ctx"] = ctxObj // Input Example: https://github.com/kcl-lang/krm-kcl/blob/main/examples/mutation/set-annotations/suite/good.yaml inputBytes, outputBytes := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{}) kclRunBytes, err := yaml.Marshal(in) diff --git a/pkg/resource/res.go b/pkg/resource/res.go index 5c8cb58..bd3af12 100644 --- a/pkg/resource/res.go +++ b/pkg/resource/res.go @@ -51,6 +51,14 @@ type Resource struct { Base unstructured.Unstructured `json:"base,omitempty"` } +func JsonByteToRawExtension(jsonByte []byte) (runtime.RawExtension, error) { + o, err := JsonByteToUnstructured(jsonByte) + if err != nil { + return runtime.RawExtension{}, err + } + return UnstructuredToRawExtension(o) +} + func JsonByteToUnstructured(jsonByte []byte) (*unstructured.Unstructured, error) { var data map[string]interface{} err := json.Unmarshal(jsonByte, &data)