Skip to content

Commit

Permalink
feat: impl default target with connection details in the function-kcl…
Browse files Browse the repository at this point in the history
… v0.4.0

Signed-off-by: peefy <xpf6677@163.com>
  • Loading branch information
Peefy committed Apr 2, 2024
1 parent 37be2a8 commit 2d5b783
Show file tree
Hide file tree
Showing 8 changed files with 284 additions and 20 deletions.
2 changes: 2 additions & 0 deletions examples/default/resources/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
run:
crossplane beta render xr.yaml composition.yaml functions.yaml -r
113 changes: 113 additions & 0 deletions examples/default/resources/README.md
Original file line number Diff line number Diff line change
@@ -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: {}
```
68 changes: 68 additions & 0 deletions examples/default/resources/composition.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
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: |
import base64
oxr = option("params").oxr
count = oxr.spec.count or 1
ocds = option("params").ocds
dxr = {
**oxr
status.dummy = "cool-status"
}
details = {
apiVersion: "meta.krm.kcl.dev/v1alpha1"
kind: "CompositeConnectionDetails"
if "sample-access-key-0" in ocds:
data: {
username = ocds["sample-access-key-0"].connectionDetails.username
password = ocds["sample-access-key-0"].connectionDetails.password
url = base64.encode("http://www.example.com")
}
else:
data: {}
}
items = sum([[{
apiVersion: "iam.aws.upbound.io/v1beta1"
kind: "User"
metadata.name = "test-user-{}".format(i)
metadata.labels: {
"testing.upbound.io/example-name" = "test-user-{}".format(i)
if "test-user-{}".format(i) in ocds:
dummy = ocds["test-user-{}".format(i)].Resource.metadata.labels.dummy
else:
dummy = "foo"
}
spec.forProvider: {}
}, {
apiVersion: "iam.aws.upbound.io/v1beta1"
kind: "AccessKey"
metadata.name = "sample-access-key-{}".format(i)
spec.forProvider.userSelector.matchLabels: {
"testing.upbound.io/example-name" = "test-user-{}".format(i)
}
spec.writeConnectionSecretToRef: {
name: "sample-access-key-secret-{}".format(i)
namespace: "crossplane-system"
}
}] for i in range(count)], []) + [
dxr
]
9 changes: 9 additions & 0 deletions examples/default/resources/functions.yaml
Original file line number Diff line number Diff line change
@@ -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
6 changes: 6 additions & 0 deletions examples/default/resources/xr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: example.crossplane.io/v1beta1
kind: XR
metadata:
name: example
spec:
count: 2
34 changes: 17 additions & 17 deletions fn.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (

"github.com/crossplane-contrib/function-kcl/input/v1beta1"
pkgresource "github.com/crossplane-contrib/function-kcl/pkg/resource"

"sigs.k8s.io/yaml"
)

Expand All @@ -38,20 +37,25 @@ func (f *Function) RunFunction(_ context.Context, req *fnv1beta1.RunFunctionRequ
response.Fatal(rsp, errors.Wrapf(err, "cannot get Function input from %T", req))
return rsp, nil
}
// Set default target
if in.Spec.Target == "" {
in.Spec.Target = pkgresource.Default
}
// Set default params
if in.Spec.Params == nil {
in.Spec.Params = make(map[string]runtime.RawExtension)
}
if err := in.Validate(); err != nil {
response.Fatal(rsp, errors.Wrap(err, "invalid function input"))
return rsp, nil
}

// The composite resource that actually exists.
oxr, err := request.GetObservedCompositeResource(req)
if err != nil {
response.Fatal(rsp, errors.Wrap(err, "cannot get observed composite resource"))
return rsp, nil
}
if in.Spec.Params == nil {
in.Spec.Params = make(map[string]runtime.RawExtension)
}
// Set option("params").oxr
in.Spec.Params["oxr"], err = pkgresource.UnstructuredToRawExtension(&oxr.Resource.Unstructured)
if err != nil {
response.Fatal(rsp, err)
Expand All @@ -70,14 +74,14 @@ func (f *Function) RunFunction(_ context.Context, req *fnv1beta1.RunFunctionRequ
response.Fatal(rsp, errors.Wrap(err, "cannot get desired composite resource"))
return rsp, nil
}
// Set option("params").oxr
dxr.Resource.SetAPIVersion(oxr.Resource.GetAPIVersion())
dxr.Resource.SetKind(oxr.Resource.GetKind())
in.Spec.Params["dxr"], err = pkgresource.UnstructuredToRawExtension(&dxr.Resource.Unstructured)
if err != nil {
response.Fatal(rsp, err)
return rsp, nil
}

// The composed resources desired by any previous Functions in the pipeline.
desired, err := request.GetDesiredComposedResources(req)
if err != nil {
Expand All @@ -103,7 +107,6 @@ func (f *Function) RunFunction(_ context.Context, req *fnv1beta1.RunFunctionRequ
response.Fatal(rsp, err)
return rsp, nil
}

// 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)
Expand Down Expand Up @@ -148,6 +151,13 @@ func (f *Function) RunFunction(_ context.Context, req *fnv1beta1.RunFunctionRequ
response.Fatal(rsp, errors.Wrapf(err, "cannot process xr and state with the pipeline output in %T", rsp))
return rsp, nil
}
log.Debug(fmt.Sprintf("Set %d resource(s) to the desired state", result.MsgCount))
for _, msg := range result.Msgs {
rsp.Results = append(rsp.Results, &fnv1beta1.Result{
Severity: fnv1beta1.Severity_SEVERITY_NORMAL,
Message: msg,
})
}

// Set dxr and desired state
log.Debug(fmt.Sprintf("Setting desired XR state to %+v", dxr.Resource))
Expand All @@ -162,16 +172,6 @@ func (f *Function) RunFunction(_ context.Context, req *fnv1beta1.RunFunctionRequ
response.Fatal(rsp, errors.Wrapf(err, "cannot set desired composed resources in %T", rsp))
return rsp, nil
}

log.Debug(fmt.Sprintf("Set %d resource(s) to the desired state", result.MsgCount))
for _, msg := range result.Msgs {
rsp.Results = append(rsp.Results, &fnv1beta1.Result{
Severity: fnv1beta1.Severity_SEVERITY_NORMAL,
Message: msg,
})
}

log.Info("Successfully processed crossplane KCL function resources", "input", in.Name)

return rsp, nil
}
6 changes: 3 additions & 3 deletions input/v1beta1/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ type KCLInput struct {
Spec RunSpec `json:"spec,omitempty" yaml:"spec,omitempty"`
}

func (in KCLInput) Validate() error {
func (in *KCLInput) Validate() error {
if in.Spec.Source == "" {
return field.Required(field.NewPath("spec.source"), "kcl source cannot be empty")
}

switch in.Spec.Target {
// Allowed targets
case resource.PatchDesired, resource.Resources, resource.XR:
case resource.Default, resource.PatchDesired, resource.Resources, resource.XR:
case resource.PatchResources:
if len(in.Spec.Resources) == 0 {
return field.Required(field.NewPath("spec.Resources"), fmt.Sprintf("%s target requires at least one resource", resource.PatchResources))
Expand All @@ -49,7 +49,7 @@ func (in KCLInput) Validate() error {
}
}
default:
return field.Required(field.NewPath("spec.target"), fmt.Sprintf("invalid target: %s", in.Spec.Target))
in.Spec.Target = resource.Default
}

return nil
Expand Down
Loading

0 comments on commit 2d5b783

Please sign in to comment.