Skip to content

Commit

Permalink
feat: add the ability to override merged output from XR fields
Browse files Browse the repository at this point in the history
Signed-off-by: Jesús Fernández <7312236+fernandezcuesta@users.noreply.github.com>
  • Loading branch information
fernandezcuesta committed Nov 4, 2024
1 parent 9dfd2ff commit 3e50eb4
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 12 deletions.
9 changes: 9 additions & 0 deletions fn.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,15 @@ func (f *Function) RunFunction(_ context.Context, req *fnv1beta1.RunFunctionRequ
mergedData = mergeMaps(defaultData, mergedData)
}

if in.Spec.DataOverrides != nil {
xr := req.Observed.Composite.Resource.AsMap()
for k, v := range in.Spec.DataOverrides {
if val, err := fieldpath.Pave(xr).GetValue(v); err == nil {
mergedData[k] = val
}
}
}

// build environment and return it in the response as context
out := &unstructured.Unstructured{Object: mergedData}
if out.GroupVersionKind().Empty() {
Expand Down
165 changes: 153 additions & 12 deletions fn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,15 @@ func TestRunFunction(t *testing.T) {
"kind": "Input",
"spec": {
"environmentConfigs": [
{
{
"type": "Reference",
"ref": {
"ref": {
"name": "my-env-config"
}
},
{
{
"type": "Reference",
"ref": {
"ref": {
"name": "my-second-env-config"
}
},
Expand Down Expand Up @@ -283,15 +283,15 @@ func TestRunFunction(t *testing.T) {
"kind": "Input",
"spec": {
"environmentConfigs": [
{
{
"type": "Reference",
"ref": {
"ref": {
"name": "my-env-config"
}
},
{
{
"type": "Reference",
"ref": {
"ref": {
"name": "my-second-env-config"
}
},
Expand Down Expand Up @@ -427,9 +427,9 @@ func TestRunFunction(t *testing.T) {
"kind": "Input",
"spec": {
"environmentConfigs": [
{
{
"type": "Reference",
"ref": {
"ref": {
"name": "my-env-config"
}
}
Expand Down Expand Up @@ -475,6 +475,144 @@ func TestRunFunction(t *testing.T) {
"g": "overridden-from-env-config-2"
}
}`),
Input: resource.MustStructJSON(`{
"apiVersion": "template.fn.crossplane.io/v1beta1",
"kind": "Input",
"spec": {
"defaultData": {
"b": "only-from-default",
"e": "overridden-from-input",
"f": "overridden-from-env-config-2"
},
"environmentConfigs": [
{
"type": "Reference",
"ref": {
"name": "my-env-config"
}
},
{
"type": "Reference",
"ref": {
"name": "my-second-env-config"
}
}
]
}
}`),
ExtraResources: map[string]*fnv1beta1.Resources{
"environment-config-0": {
Items: []*fnv1beta1.Resource{
{
Resource: resource.MustStructJSON(`{
"apiVersion": "apiextensions.crossplane.io/v1alpha1",
"kind": "EnvironmentConfig",
"metadata": {
"name": "my-env-config"
},
"data": {
"c": "only-from-env-config-1",
"f": "overridden-from-env-config-1-ok",
"h": "override-from-env-config-1"
}
}`),
},
},
},
"environment-config-1": {
Items: []*fnv1beta1.Resource{
{
Resource: resource.MustStructJSON(`{
"apiVersion": "apiextensions.crossplane.io/v1alpha1",
"kind": "EnvironmentConfig",
"metadata": {
"name": "my-second-env-config"
},
"data": {
"d": "only-from-env-config-1",
"g": "overridden-from-env-config-2-ok",
"h": "override-from-env-config-1-ok"
}
}`),
},
},
},
},
},
},
want: want{
rsp: &fnv1beta1.RunFunctionResponse{
Meta: &fnv1beta1.ResponseMeta{Tag: "hello", Ttl: durationpb.New(response.DefaultTTL)},
Results: []*fnv1beta1.Result{},
Requirements: &fnv1beta1.Requirements{
ExtraResources: map[string]*fnv1beta1.ResourceSelector{
"environment-config-0": {
ApiVersion: "apiextensions.crossplane.io/v1alpha1",
Kind: "EnvironmentConfig",
Match: &fnv1beta1.ResourceSelector_MatchName{
MatchName: "my-env-config",
},
},
"environment-config-1": {
ApiVersion: "apiextensions.crossplane.io/v1alpha1",
Kind: "EnvironmentConfig",
Match: &fnv1beta1.ResourceSelector_MatchName{
MatchName: "my-second-env-config",
},
},
},
},
Context: &structpb.Struct{
Fields: map[string]*structpb.Value{
FunctionContextKeyEnvironment: structpb.NewStructValue(resource.MustStructJSON(`{
"apiVersion": "internal.crossplane.io/v1alpha1",
"kind": "Environment",
"a": "only-from-input",
"b": "only-from-default",
"c": "only-from-env-config-1",
"d": "only-from-env-config-1",
"e": "overridden-from-input-ok",
"f": "overridden-from-env-config-1-ok",
"g": "overridden-from-env-config-2-ok",
"h": "override-from-env-config-1-ok"
}`)),
},
},
},
},
},
"DataOverrides": {
reason: "The Function should merge the provided EnvironmentConfigs and allow data overrides",
args: args{
req: &fnv1beta1.RunFunctionRequest{
Meta: &fnv1beta1.RequestMeta{Tag: "hello"},
Context: resource.MustStructJSON(`{
"` + FunctionContextKeyEnvironment + `": {
"apiVersion": "internal.crossplane.io/v1alpha1",
"kind": "Environment",
"a": "only-from-input",
"e": "overridden-from-input-ok",
"f": "overridden-from-env-config-1",
"g": "overridden-from-env-config-2"
}
}`),
Observed: &fnv1beta1.State{
Composite: &fnv1beta1.Resource{
Resource: resource.MustStructJSON(`{
"apiVersion": "test.crossplane.io/v1alpha1",
"kind": "XR",
"metadata": {
"name": "my-xr"
},
"spec": {
"parameters": {
"override-g": "overridden-from-xr-parameters-ok",
"unused": "qux"
}
}
}`),
},
},
Input: resource.MustStructJSON(`{
"apiVersion": "template.fn.crossplane.io/v1beta1",
"kind": "Input",
Expand All @@ -497,7 +635,10 @@ func TestRunFunction(t *testing.T) {
"name": "my-second-env-config"
}
}
]
],
"dataOverrides": {
"g": "spec.parameters.override-g"
}
}
}`),
ExtraResources: map[string]*fnv1beta1.Resources{
Expand Down Expand Up @@ -573,7 +714,7 @@ func TestRunFunction(t *testing.T) {
"d": "only-from-env-config-1",
"e": "overridden-from-input-ok",
"f": "overridden-from-env-config-1-ok",
"g": "overridden-from-env-config-2-ok",
"g": "overridden-from-xr-parameters-ok",
"h": "override-from-env-config-1-ok"
}`)),
},
Expand Down
5 changes: 5 additions & 0 deletions input/v1beta1/composition_environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ type InputSpec struct {
// EnvironmentSourceReferences in EnvironmentConfigs list.
// +optional
Policy *Policy `json:"policy,omitempty"`

// DataOverrides allows overriding the resulting environment data with
// static values. The keys are field paths in the environment data, and the
// values are references to where the data should be taken from (e.g. "spec.parameters.foo")
DataOverrides map[string]string `json:"dataOverrides,omitempty"`
}

// Policy represents the Resolution policy of Reference instance.
Expand Down
7 changes: 7 additions & 0 deletions input/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions package/input/environmentconfigs.fn.crossplane.io_inputs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ spec:
An InputSpec specifies the environment for rendering composed
resources.
properties:
dataOverrides:
additionalProperties:
type: string
description: |-
DataOverrides allows overriding the resulting environment data with
static values. The keys are field paths in the environment data, and the
values are references to where the data should be taken from (e.g. .spec.parameters.foo)
type: object
defaultData:
additionalProperties:
x-kubernetes-preserve-unknown-fields: true
Expand Down

0 comments on commit 3e50eb4

Please sign in to comment.