Skip to content

Commit

Permalink
Add support for To|FromEnvironmentFieldPath type in environment patches
Browse files Browse the repository at this point in the history
Resolves #123

Signed-off-by: Truong Nguyen <[email protected]>
  • Loading branch information
truongnht committed May 29, 2024
1 parent 901f6a0 commit cf8cbaa
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 7 deletions.
108 changes: 108 additions & 0 deletions fn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -896,6 +896,114 @@ func TestRunFunction(t *testing.T) {
Context: contextWithEnvironment(map[string]interface{}{
"widgets": "30",
})}}},
"PatchToCompositeSupportsFromEnvironmentFieldPath": {
reason: "A basic FromEnvironmentFieldPath patch should work with environment.patches.",
args: args{
req: &fnv1beta1.RunFunctionRequest{
Input: resource.MustStructObject(&v1beta1.Resources{
Resources: []v1beta1.ComposedTemplate{
{
Name: "cool-resource",
Base: &runtime.RawExtension{Raw: []byte(`{"apiVersion":"example.org/v1","kind":"CD"}`)},
}},
Environment: &v1beta1.Environment{
Patches: []v1beta1.EnvironmentPatch{
{
Type: v1beta1.PatchTypeFromEnvironmentFieldPath,
Patch: v1beta1.Patch{
FromFieldPath: ptr.To[string]("widgets"),
ToFieldPath: ptr.To[string]("spec.watchers"),
Transforms: []v1beta1.Transform{
{
Type: v1beta1.TransformTypeConvert,
Convert: &v1beta1.ConvertTransform{
ToType: v1beta1.TransformIOTypeInt64,
},
},
{
Type: v1beta1.TransformTypeMath,
Math: &v1beta1.MathTransform{
Type: v1beta1.MathTransformTypeMultiply,
Multiply: ptr.To[int64](3),
}}}}}}}}),
Observed: &fnv1beta1.State{
Composite: &fnv1beta1.Resource{
Resource: resource.MustStructJSON(`{"apiVersion":"example.org/v1","kind":"CD","spec":{}}`),
},
Resources: map[string]*fnv1beta1.Resource{},
},
Context: contextWithEnvironment(map[string]interface{}{
"widgets": "10",
})},
},
want: want{
rsp: &fnv1beta1.RunFunctionResponse{
Meta: &fnv1beta1.ResponseMeta{Ttl: durationpb.New(response.DefaultTTL)},
Desired: &fnv1beta1.State{
Composite: &fnv1beta1.Resource{
// spec.watchers = 10 * 3 = 30
Resource: resource.MustStructJSON(`{"apiVersion":"example.org/v1","kind":"CD","spec":{"watchers":30}}`),
},
Resources: map[string]*fnv1beta1.Resource{
"cool-resource": {
Resource: resource.MustStructJSON(`{"apiVersion":"example.org/v1","kind":"CD"}`),
}}},
Context: contextWithEnvironment(map[string]interface{}{
"widgets": "10",
})}}},
"EnvironmentPatchSupportsToEnvironmentFieldPath": {
reason: "ToEnvironmentFieldPath patch should work with environment.patches.",
args: args{
req: &fnv1beta1.RunFunctionRequest{
Input: resource.MustStructObject(&v1beta1.Resources{
Resources: []v1beta1.ComposedTemplate{
{
Name: "cool-resource",
Base: &runtime.RawExtension{Raw: []byte(`{"apiVersion":"example.org/v1","kind":"CD"}`)},
}},
Environment: &v1beta1.Environment{
Patches: []v1beta1.EnvironmentPatch{
{
Type: v1beta1.PatchTypeToEnvironmentFieldPath,
Patch: v1beta1.Patch{
FromFieldPath: ptr.To[string]("spec.watchers"),
ToFieldPath: ptr.To[string]("widgets"),
Transforms: []v1beta1.Transform{
{
Type: v1beta1.TransformTypeMath,
Math: &v1beta1.MathTransform{
Type: v1beta1.MathTransformTypeMultiply,
Multiply: ptr.To[int64](3),
},
},
{
Type: v1beta1.TransformTypeConvert,
Convert: &v1beta1.ConvertTransform{
ToType: v1beta1.TransformIOTypeString,
},
}}}}}}}),
Observed: &fnv1beta1.State{
Composite: &fnv1beta1.Resource{
Resource: resource.MustStructJSON(`{"apiVersion":"example.org/v1","kind":"CD","spec":{"watchers":10}}`),
},
Resources: map[string]*fnv1beta1.Resource{},
},
Context: contextWithEnvironment(nil)},
},
want: want{
rsp: &fnv1beta1.RunFunctionResponse{
Meta: &fnv1beta1.ResponseMeta{Ttl: durationpb.New(response.DefaultTTL)},
Desired: &fnv1beta1.State{
Composite: &fnv1beta1.Resource{
Resource: resource.MustStructJSON(`{"apiVersion":"example.org/v1","kind":"CD"}`),
},
Resources: map[string]*fnv1beta1.Resource{
"cool-resource": {
Resource: resource.MustStructJSON(`{"apiVersion":"example.org/v1","kind":"CD"}`),
}}},
Context: contextWithEnvironment(map[string]interface{}{
"widgets": "30",
})}}},
"EnvironmentPatchOptionalNotFoundSkipped": {
reason: "A basic ToEnvironment patch with optional or not field path policy should be skipped",
args: args{
Expand Down
2 changes: 1 addition & 1 deletion input/v1beta1/resources_patches.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ type EnvironmentPatch struct {
// Type sets the patching behaviour to be used. Each patch type may require
// its own fields to be set on the Patch object.
// +optional
// +kubebuilder:validation:Enum=FromCompositeFieldPath;ToCompositeFieldPath;CombineFromComposite;CombineToComposite
// +kubebuilder:validation:Enum=FromCompositeFieldPath;ToCompositeFieldPath;CombineFromComposite;CombineToComposite;FromEnvironmentFieldPath;ToEnvironmentFieldPath
// +kubebuilder:default=FromCompositeFieldPath
Type PatchType `json:"type,omitempty"`

Expand Down
2 changes: 2 additions & 0 deletions package/input/pt.fn.crossplane.io_resources.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,8 @@ spec:
- ToCompositeFieldPath
- CombineFromComposite
- CombineToComposite
- FromEnvironmentFieldPath
- ToEnvironmentFieldPath
type: string
type: object
type: array
Expand Down
10 changes: 5 additions & 5 deletions patches.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,21 +198,21 @@ func ApplyCombineFromVariablesPatch(p PatchInterface, from, to runtime.Object) e
func ApplyEnvironmentPatch(p *v1beta1.EnvironmentPatch, env *unstructured.Unstructured, oxr, dxr *composite.Unstructured) error {
switch p.GetType() {
// From observed XR to environment.
case v1beta1.PatchTypeFromCompositeFieldPath:
case v1beta1.PatchTypeFromCompositeFieldPath,
v1beta1.PatchTypeToEnvironmentFieldPath:
return ApplyFromFieldPathPatch(p, oxr, env)
case v1beta1.PatchTypeCombineFromComposite:
return ApplyCombineFromVariablesPatch(p, oxr, env)

// From environment to desired XR.
case v1beta1.PatchTypeToCompositeFieldPath:
case v1beta1.PatchTypeToCompositeFieldPath,
v1beta1.PatchTypeFromEnvironmentFieldPath:
return ApplyFromFieldPathPatch(p, env, dxr)
case v1beta1.PatchTypeCombineToComposite:
return ApplyCombineFromVariablesPatch(p, env, dxr)

// Invalid patch types in this context.
case v1beta1.PatchTypeFromEnvironmentFieldPath,
v1beta1.PatchTypeCombineFromEnvironment,
v1beta1.PatchTypeToEnvironmentFieldPath,
case v1beta1.PatchTypeCombineFromEnvironment,
v1beta1.PatchTypeCombineToEnvironment:
// Nothing to do.

Expand Down
4 changes: 3 additions & 1 deletion validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@ func ValidateEnvironment(e *v1beta1.Environment) *field.Error {
v1beta1.PatchTypeFromCompositeFieldPath,
v1beta1.PatchTypeToCompositeFieldPath,
v1beta1.PatchTypeCombineFromComposite,
v1beta1.PatchTypeCombineToComposite:
v1beta1.PatchTypeCombineToComposite,
v1beta1.PatchTypeFromEnvironmentFieldPath,
v1beta1.PatchTypeToEnvironmentFieldPath:
default:
return field.Invalid(field.NewPath("patches").Index(i).Key("type"), p.GetType(), "invalid environment patch type")
}
Expand Down

0 comments on commit cf8cbaa

Please sign in to comment.