diff --git a/apis/common/v1/policies.go b/apis/common/v1/policies.go index 7efb25988..81b74814f 100644 --- a/apis/common/v1/policies.go +++ b/apis/common/v1/policies.go @@ -30,3 +30,18 @@ const ( // managed resource is deleted. DeletionDelete DeletionPolicy = "Delete" ) + +// An UpdatePolicy determines how something should be updated - either +// automatically (without human intervention) or manually. +// +kubebuilder:validation:Enum=Automatic;Manual +type UpdatePolicy string + +const ( + // UpdateAutomatic means the resource should be updated automatically, + // without any human intervention. + UpdateAutomatic UpdatePolicy = "Automatic" + + // UpdateManual means the resource requires human intervention to + // update. + UpdateManual UpdatePolicy = "Manual" +) diff --git a/pkg/resource/fake/mocks.go b/pkg/resource/fake/mocks.go index 647114f5c..10b653196 100644 --- a/pkg/resource/fake/mocks.go +++ b/pkg/resource/fake/mocks.go @@ -163,6 +163,32 @@ func (m *CompositionSelector) SetCompositionSelector(s *metav1.LabelSelector) { // GetCompositionSelector gets the CompositionSelector. func (m *CompositionSelector) GetCompositionSelector() *metav1.LabelSelector { return m.Sel } +// CompositionRevisionReferencer is a mock that implements CompositionRevisionReferencer interface. +type CompositionRevisionReferencer struct{ Ref *corev1.ObjectReference } + +// SetCompositionRevisionReference sets the CompositionRevisionReference. +func (m *CompositionRevisionReferencer) SetCompositionRevisionReference(r *corev1.ObjectReference) { + m.Ref = r +} + +// GetCompositionRevisionReference gets the CompositionRevisionReference. +func (m *CompositionRevisionReferencer) GetCompositionRevisionReference() *corev1.ObjectReference { + return m.Ref +} + +// CompositionUpdater is a mock that implements CompositionUpdater interface. +type CompositionUpdater struct{ Policy *xpv1.UpdatePolicy } + +// SetCompositionUpdatePolicy sets the CompositionUpdatePolicy. +func (m *CompositionUpdater) SetCompositionUpdatePolicy(p *xpv1.UpdatePolicy) { + m.Policy = p +} + +// GetCompositionUpdatePolicy gets the CompositionUpdatePolicy. +func (m *CompositionUpdater) GetCompositionUpdatePolicy() *xpv1.UpdatePolicy { + return m.Policy +} + // CompositeResourceReferencer is a mock that implements CompositeResourceReferencer interface. type CompositeResourceReferencer struct{ Ref *corev1.ObjectReference } @@ -262,6 +288,8 @@ type Composite struct { metav1.ObjectMeta CompositionSelector CompositionReferencer + CompositionRevisionReferencer + CompositionUpdater ComposedResourcesReferencer ClaimReferencer ConnectionSecretWriterTo @@ -314,6 +342,8 @@ type CompositeClaim struct { metav1.ObjectMeta CompositionSelector CompositionReferencer + CompositionRevisionReferencer + CompositionUpdater CompositeResourceReferencer LocalConnectionSecretWriterTo diff --git a/pkg/resource/interfaces.go b/pkg/resource/interfaces.go index 8352fcd23..049e0e22b 100644 --- a/pkg/resource/interfaces.go +++ b/pkg/resource/interfaces.go @@ -109,6 +109,20 @@ type CompositionReferencer interface { GetCompositionReference() *corev1.ObjectReference } +// A CompositionRevisionReferencer may reference a specific revision of a +// composition of resources. +type CompositionRevisionReferencer interface { + SetCompositionRevisionReference(*corev1.ObjectReference) + GetCompositionRevisionReference() *corev1.ObjectReference +} + +// A CompositionUpdater uses a composition, and may update which revision of +// that composition it uses. +type CompositionUpdater interface { + SetCompositionUpdatePolicy(*xpv1.UpdatePolicy) + GetCompositionUpdatePolicy() *xpv1.UpdatePolicy +} + // A ComposedResourcesReferencer may reference the resources it composes. type ComposedResourcesReferencer interface { SetResourceReferences([]corev1.ObjectReference) @@ -191,6 +205,8 @@ type Composite interface { CompositionSelector CompositionReferencer + CompositionUpdater + CompositionRevisionReferencer ComposedResourcesReferencer ClaimReferencer ConnectionSecretWriterTo @@ -213,6 +229,8 @@ type CompositeClaim interface { CompositionSelector CompositionReferencer + CompositionUpdater + CompositionRevisionReferencer CompositeResourceReferencer LocalConnectionSecretWriterTo diff --git a/pkg/resource/interfaces_test.go b/pkg/resource/interfaces_test.go new file mode 100644 index 000000000..1617cbf49 --- /dev/null +++ b/pkg/resource/interfaces_test.go @@ -0,0 +1,32 @@ +/* +Copyright 2021 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package resource + +import "github.com/crossplane/crossplane-runtime/pkg/resource/fake" + +// We test that our fakes satisfy our interfaces here rather than in the fake +// package to avoid a cyclic dependency. + +var ( + _ Managed = &fake.Managed{} + _ ProviderConfig = &fake.ProviderConfig{} + _ ProviderConfigUsage = &fake.ProviderConfigUsage{} + + _ CompositeClaim = &fake.CompositeClaim{} + _ Composite = &fake.Composite{} + _ Composed = &fake.Composed{} +) diff --git a/pkg/resource/unstructured/claim/claim.go b/pkg/resource/unstructured/claim/claim.go index 9d7867a98..e36bf8e43 100644 --- a/pkg/resource/unstructured/claim/claim.go +++ b/pkg/resource/unstructured/claim/claim.go @@ -93,6 +93,35 @@ func (c *Unstructured) SetCompositionReference(ref *corev1.ObjectReference) { _ = fieldpath.Pave(c.Object).SetValue("spec.compositionRef", ref) } +// GetCompositionRevisionReference of this resource claim. +func (c *Unstructured) GetCompositionRevisionReference() *corev1.ObjectReference { + out := &corev1.ObjectReference{} + if err := fieldpath.Pave(c.Object).GetValueInto("spec.compositionRevisionRef", out); err != nil { + return nil + } + return out +} + +// SetCompositionRevisionReference of this resource claim. +func (c *Unstructured) SetCompositionRevisionReference(ref *corev1.ObjectReference) { + _ = fieldpath.Pave(c.Object).SetValue("spec.compositionRevisionRef", ref) +} + +// SetCompositionUpdatePolicy of this resource claim. +func (c *Unstructured) SetCompositionUpdatePolicy(p *xpv1.UpdatePolicy) { + _ = fieldpath.Pave(c.Object).SetValue("spec.compositionUpdatePolicy", p) +} + +// GetCompositionUpdatePolicy of this resource claim. +func (c *Unstructured) GetCompositionUpdatePolicy() *xpv1.UpdatePolicy { + p, err := fieldpath.Pave(c.Object).GetString("spec.compositionUpdatePolicy") + if err != nil { + return nil + } + out := xpv1.UpdatePolicy(p) + return &out +} + // GetResourceReference of this composite resource claim. func (c *Unstructured) GetResourceReference() *corev1.ObjectReference { out := &corev1.ObjectReference{} diff --git a/pkg/resource/unstructured/claim/claim_test.go b/pkg/resource/unstructured/claim/claim_test.go index 14487d5ba..7d6878532 100644 --- a/pkg/resource/unstructured/claim/claim_test.go +++ b/pkg/resource/unstructured/claim/claim_test.go @@ -166,6 +166,56 @@ func TestCompositionReference(t *testing.T) { } } +func TestCompositionRevisionReference(t *testing.T) { + ref := &corev1.ObjectReference{Namespace: "ns", Name: "cool"} + cases := map[string]struct { + u *Unstructured + set *corev1.ObjectReference + want *corev1.ObjectReference + }{ + "NewRef": { + u: New(), + set: ref, + want: ref, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + tc.u.SetCompositionRevisionReference(tc.set) + got := tc.u.GetCompositionRevisionReference() + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("\nu.GetCompositionRevisionReference(): -want, +got:\n%s", diff) + } + }) + } +} + +func TestCompositionUpdatePolicy(t *testing.T) { + p := xpv1.UpdateManual + cases := map[string]struct { + u *Unstructured + set *xpv1.UpdatePolicy + want *xpv1.UpdatePolicy + }{ + "NewRef": { + u: New(), + set: &p, + want: &p, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + tc.u.SetCompositionUpdatePolicy(tc.set) + got := tc.u.GetCompositionUpdatePolicy() + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("\nu.GetCompositionUpdatePolicy(): -want, +got:\n%s", diff) + } + }) + } +} + func TestResourceReference(t *testing.T) { ref := &corev1.ObjectReference{Namespace: "ns", Name: "cool"} cases := map[string]struct { diff --git a/pkg/resource/unstructured/composite/composite.go b/pkg/resource/unstructured/composite/composite.go index d4a0ffbca..9c95d8c03 100644 --- a/pkg/resource/unstructured/composite/composite.go +++ b/pkg/resource/unstructured/composite/composite.go @@ -93,6 +93,35 @@ func (c *Unstructured) SetCompositionReference(ref *corev1.ObjectReference) { _ = fieldpath.Pave(c.Object).SetValue("spec.compositionRef", ref) } +// GetCompositionRevisionReference of this Composite resource. +func (c *Unstructured) GetCompositionRevisionReference() *corev1.ObjectReference { + out := &corev1.ObjectReference{} + if err := fieldpath.Pave(c.Object).GetValueInto("spec.compositionRevisionRef", out); err != nil { + return nil + } + return out +} + +// SetCompositionRevisionReference of this Composite resource. +func (c *Unstructured) SetCompositionRevisionReference(ref *corev1.ObjectReference) { + _ = fieldpath.Pave(c.Object).SetValue("spec.compositionRevisionRef", ref) +} + +// SetCompositionUpdatePolicy of this Composite resource. +func (c *Unstructured) SetCompositionUpdatePolicy(p *xpv1.UpdatePolicy) { + _ = fieldpath.Pave(c.Object).SetValue("spec.compositionUpdatePolicy", p) +} + +// GetCompositionUpdatePolicy of this Composite resource. +func (c *Unstructured) GetCompositionUpdatePolicy() *xpv1.UpdatePolicy { + p, err := fieldpath.Pave(c.Object).GetString("spec.compositionUpdatePolicy") + if err != nil { + return nil + } + out := xpv1.UpdatePolicy(p) + return &out +} + // GetClaimReference of this Composite resource. func (c *Unstructured) GetClaimReference() *corev1.ObjectReference { out := &corev1.ObjectReference{} diff --git a/pkg/resource/unstructured/composite/composite_test.go b/pkg/resource/unstructured/composite/composite_test.go index 15b701e2c..0ce369caf 100644 --- a/pkg/resource/unstructured/composite/composite_test.go +++ b/pkg/resource/unstructured/composite/composite_test.go @@ -165,6 +165,56 @@ func TestCompositionReference(t *testing.T) { } } +func TestCompositionRevisionReference(t *testing.T) { + ref := &corev1.ObjectReference{Namespace: "ns", Name: "cool"} + cases := map[string]struct { + u *Unstructured + set *corev1.ObjectReference + want *corev1.ObjectReference + }{ + "NewRef": { + u: New(), + set: ref, + want: ref, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + tc.u.SetCompositionRevisionReference(tc.set) + got := tc.u.GetCompositionRevisionReference() + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("\nu.GetCompositionRevisionReference(): -want, +got:\n%s", diff) + } + }) + } +} + +func TestCompositionUpdatePolicy(t *testing.T) { + p := xpv1.UpdateManual + cases := map[string]struct { + u *Unstructured + set *xpv1.UpdatePolicy + want *xpv1.UpdatePolicy + }{ + "NewRef": { + u: New(), + set: &p, + want: &p, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + tc.u.SetCompositionUpdatePolicy(tc.set) + got := tc.u.GetCompositionUpdatePolicy() + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("\nu.GetCompositionUpdatePolicy(): -want, +got:\n%s", diff) + } + }) + } +} + func TestClaimReference(t *testing.T) { ref := &corev1.ObjectReference{Namespace: "ns", Name: "cool"} cases := map[string]struct { @@ -192,7 +242,6 @@ func TestClaimReference(t *testing.T) { func TestResourceReferences(t *testing.T) { ref := corev1.ObjectReference{Namespace: "ns", Name: "cool"} - t.Log(ref.String()) cases := map[string]struct { u *Unstructured set []corev1.ObjectReference