Run golangci-lint run --fix

This commit is entirely generated by earthly +reviewable

Signed-off-by: Nic Cope <nicc@rk0n.org>
This commit is contained in:
Nic Cope 2025-07-03 12:51:13 -07:00
parent aad05b013a
commit 678177c524
85 changed files with 812 additions and 86 deletions

View File

@ -126,6 +126,7 @@ func IsSystemConditionType(t ConditionType) bool {
case TypeReady, TypeSynced, TypeHealthy:
return true
}
return false
}
@ -150,6 +151,7 @@ type ConditionedStatus struct {
func NewConditionedStatus(c ...Condition) *ConditionedStatus {
s := &ConditionedStatus{}
s.SetConditions(c...)
return s
}
@ -171,6 +173,7 @@ func (s *ConditionedStatus) GetCondition(ct ConditionType) Condition {
func (s *ConditionedStatus) SetConditions(c ...Condition) {
for _, cond := range c {
exists := false
for i, existing := range s.Conditions {
if existing.Type != cond.Type {
continue
@ -184,6 +187,7 @@ func (s *ConditionedStatus) SetConditions(c ...Condition) {
s.Conditions[i] = cond
exists = true
}
if !exists {
s.Conditions = append(s.Conditions, cond)
}

View File

@ -72,6 +72,7 @@ func (in *ConnectionSecretMetadata) SetOwnerUID(uid types.UID) {
if in.Labels == nil {
in.Labels = map[string]string{}
}
in.Labels[LabelKeyOwnerUID] = string(uid)
}
@ -80,6 +81,7 @@ func (in *ConnectionSecretMetadata) GetOwnerUID() string {
if u, ok := in.Labels[LabelKeyOwnerUID]; ok {
return u
}
return ""
}

View File

@ -40,9 +40,11 @@ func (mo *MergeOptions) MergoConfiguration() []func(*mergo.Config) {
if mo.KeepMapValues != nil && *mo.KeepMapValues {
config = config[:0]
}
if mo.AppendSlice != nil && *mo.AppendSlice {
config = append(config, mergo.WithAppendSlice)
}
return config
}

View File

@ -33,12 +33,15 @@ func (arr mergoOptArr) names() []string {
for i, opt := range arr {
names[i] = runtime.FuncForPC(reflect.ValueOf(opt).Pointer()).Name()
}
sort.Strings(names)
return names
}
func TestMergoConfiguration(t *testing.T) {
valTrue := true
tests := map[string]struct {
mo *MergeOptions
want mergoOptArr

View File

@ -101,6 +101,7 @@ func (p *Policy) IsResolutionPolicyOptional() bool {
if p == nil || p.Resolution == nil {
return false
}
return *p.Resolution == ResolutionPolicyOptional
}
@ -109,6 +110,7 @@ func (p *Policy) IsResolvePolicyAlways() bool {
if p == nil || p.Resolve == nil {
return false
}
return *p.Resolve == ResolvePolicyAlways
}

View File

@ -36,12 +36,14 @@ const (
func LoadMTLSConfig(caPath, certPath, keyPath string, isServer bool) (*tls.Config, error) {
tlsCertFilePath := filepath.Clean(certPath)
tlsKeyFilePath := filepath.Clean(keyPath)
certificate, err := tls.LoadX509KeyPair(tlsCertFilePath, tlsKeyFilePath)
if err != nil {
return nil, errors.Wrap(err, errLoadCert)
}
caCertFilePath := filepath.Clean(caPath)
ca, err := os.ReadFile(caCertFilePath)
if err != nil {
return nil, errors.Wrap(err, errLoadCA)

View File

@ -27,10 +27,12 @@ func TestLoad(t *testing.T) {
certsFolderPath string
requireClientValidation bool
}
type want struct {
err error
out *tls.Config
}
cases := map[string]struct {
reason string
args
@ -92,16 +94,16 @@ func TestLoad(t *testing.T) {
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
certsFolderPath := tc.args.certsFolderPath
requireClient := tc.args.requireClientValidation
certsFolderPath := tc.certsFolderPath
requireClient := tc.requireClientValidation
cfg, err := LoadMTLSConfig(filepath.Join(certsFolderPath, caCertFileName), filepath.Join(certsFolderPath, tlsCertFileName), filepath.Join(certsFolderPath, tlsKeyFileName), requireClient)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nLoad(...): -want error, +got error:\n%s", tc.reason, diff)
}
if requireClient {
if diff := cmp.Diff(tc.want.out.ClientAuth, cfg.ClientAuth); diff != "" {
if diff := cmp.Diff(tc.out.ClientAuth, cfg.ClientAuth); diff != "" {
t.Errorf("\n%s\nLoad(...): -want, +got:\n%s", tc.reason, diff)
}
}

View File

@ -68,5 +68,6 @@ func (c *observedGenerationPropagationConditionSet) MarkConditions(condition ...
for i := range condition {
condition[i].ObservedGeneration = c.o.GetGeneration()
}
c.o.SetConditions(condition...)
}

View File

@ -80,6 +80,7 @@ func TestOGConditionSetMark(t *testing.T) {
ut := newManaged(42, tt.start...)
c := manager.For(ut)
c.MarkConditions(tt.mark...)
if diff := cmp.Diff(tt.want, ut.Conditions, test.EquateConditions(), cmpopts.EquateApproxTime(1*time.Second)); diff != "" {
t.Errorf("\nReason: %s\n-want, +got:\n%s", tt.reason, diff)
}
@ -129,5 +130,6 @@ func newManaged(generation int64, conditions ...xpv1.Condition) *fake.Managed {
mg := &fake.Managed{}
mg.Generation = generation
mg.SetConditions(conditions...)
return mg
}

View File

@ -74,10 +74,13 @@ func (s *StoreConfig) GetObjectKind() schema.ObjectKind {
// DeepCopyObject returns a copy of the object as runtime.Object.
func (s *StoreConfig) DeepCopyObject() runtime.Object {
out := &StoreConfig{}
j, err := json.Marshal(s)
if err != nil {
panic(err)
}
_ = json.Unmarshal(j, out)
return out
}

View File

@ -115,6 +115,7 @@ func (m *DetailsManager) PublishConnection(ctx context.Context, so resource.Conn
}
changed, err := ss.WriteKeyValues(ctx, store.NewSecret(so, store.KeyValues(conn)), SecretToWriteMustBeOwnedBy(so))
return changed, errors.Wrap(err, errWriteStore)
}
@ -149,6 +150,7 @@ func (m *DetailsManager) FetchConnection(ctx context.Context, so resource.Connec
}
s := &store.Secret{}
return managed.ConnectionDetails(s.Data), errors.Wrap(ss.ReadKeyValues(ctx, store.ScopedName{Name: p.Name, Scope: so.GetNamespace()}, s), errReadStore)
}
@ -185,6 +187,7 @@ func (m *DetailsManager) PropagateConnection(ctx context.Context, to resource.Lo
}
changed, err := ssTo.WriteKeyValues(ctx, store.NewSecret(to, sFrom.Data), SecretToWriteMustBeOwnedBy(to))
return changed, errors.Wrap(err, errWriteStore)
}
@ -217,5 +220,6 @@ func secretMustBeOwnedBy(so metav1.Object, secret *store.Secret) error {
if secret.Metadata == nil || secret.Metadata.GetOwnerUID() != string(so.GetUID()) {
return errors.Errorf(errFmtNotOwnedBy, string(so.GetUID()))
}
return nil
}

View File

@ -144,10 +144,10 @@ func TestManagerConnectStore(t *testing.T) {
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
m := NewDetailsManager(tc.args.c, resourcefake.GVK(&fake.StoreConfig{}), WithStoreBuilder(tc.args.sb))
m := NewDetailsManager(tc.c, resourcefake.GVK(&fake.StoreConfig{}), WithStoreBuilder(tc.sb))
_, err := m.connectStore(context.Background(), tc.args.p)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
_, err := m.connectStore(context.Background(), tc.p)
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\nReason: %s\nm.connectStore(...): -want error, +got error:\n%s", tc.reason, diff)
}
})
@ -289,13 +289,14 @@ func TestManagerPublishConnection(t *testing.T) {
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
m := NewDetailsManager(tc.args.c, resourcefake.GVK(&fake.StoreConfig{}), WithStoreBuilder(tc.args.sb))
m := NewDetailsManager(tc.c, resourcefake.GVK(&fake.StoreConfig{}), WithStoreBuilder(tc.sb))
published, err := m.PublishConnection(context.Background(), tc.args.so, tc.args.conn)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
published, err := m.PublishConnection(context.Background(), tc.so, tc.conn)
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\nReason: %s\nm.publishConnection(...): -want error, +got error:\n%s", tc.reason, diff)
}
if diff := cmp.Diff(tc.want.published, published); diff != "" {
if diff := cmp.Diff(tc.published, published); diff != "" {
t.Errorf("\nReason: %s\nm.publishConnection(...): -want published, +got published:\n%s", tc.reason, diff)
}
})
@ -489,10 +490,10 @@ func TestManagerUnpublishConnection(t *testing.T) {
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
m := NewDetailsManager(tc.args.c, resourcefake.GVK(&fake.StoreConfig{}), WithStoreBuilder(tc.args.sb))
m := NewDetailsManager(tc.c, resourcefake.GVK(&fake.StoreConfig{}), WithStoreBuilder(tc.sb))
err := m.UnpublishConnection(context.Background(), tc.args.so, tc.args.conn)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
err := m.UnpublishConnection(context.Background(), tc.so, tc.conn)
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\nReason: %s\nm.unpublishConnection(...): -want error, +got error:\n%s", tc.reason, diff)
}
})
@ -632,13 +633,14 @@ func TestManagerFetchConnection(t *testing.T) {
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
m := NewDetailsManager(tc.args.c, resourcefake.GVK(&fake.StoreConfig{}), WithStoreBuilder(tc.args.sb))
m := NewDetailsManager(tc.c, resourcefake.GVK(&fake.StoreConfig{}), WithStoreBuilder(tc.sb))
got, err := m.FetchConnection(context.Background(), tc.args.so)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
got, err := m.FetchConnection(context.Background(), tc.so)
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\nReason: %s\nm.FetchConnection(...): -want error, +got error:\n%s", tc.reason, diff)
}
if diff := cmp.Diff(tc.want.conn, got); diff != "" {
if diff := cmp.Diff(tc.conn, got); diff != "" {
t.Errorf("\nReason: %s\nm.FetchConnection(...): -want connDetails, +got connDetails:\n%s", tc.reason, diff)
}
})
@ -1213,13 +1215,14 @@ func TestManagerPropagateConnection(t *testing.T) {
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
m := NewDetailsManager(tc.args.c, resourcefake.GVK(&fake.StoreConfig{}), WithStoreBuilder(tc.args.sb))
m := NewDetailsManager(tc.c, resourcefake.GVK(&fake.StoreConfig{}), WithStoreBuilder(tc.sb))
got, err := m.PropagateConnection(context.Background(), tc.args.to, tc.args.from)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
got, err := m.PropagateConnection(context.Background(), tc.to, tc.from)
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\nReason: %s\nm.PropagateConnection(...): -want error, +got error:\n%s", tc.reason, diff)
}
if diff := cmp.Diff(tc.want.propagated, got); diff != "" {
if diff := cmp.Diff(tc.propagated, got); diff != "" {
t.Errorf("\nReason: %s\nm.PropagateConnection(...): -want propagated, +got propagated:\n%s", tc.reason, diff)
}
})
@ -1231,6 +1234,7 @@ func fakeStoreBuilderFn(ss fake.SecretStore) StoreBuilderFn {
if *cfg.Type == fakeStore {
return &ss, nil
}
return nil, errors.Errorf(errFmtUnknownSecretStore, *cfg.Type)
}
}

View File

@ -83,10 +83,12 @@ func buildClient(ctx context.Context, local client.Client, cfg v1.SecretStoreCon
if err != nil {
return nil, errors.Wrap(err, errExtractKubernetesAuthCreds)
}
config, err := clientcmd.RESTConfigFromKubeConfig(kfg)
if err != nil {
return nil, errors.Wrap(err, errBuildRestConfig)
}
return client.New(config, client.Options{})
}
@ -96,12 +98,14 @@ func (ss *SecretStore) ReadKeyValues(ctx context.Context, n store.ScopedName, s
if err := ss.client.Get(ctx, types.NamespacedName{Name: n.Name, Namespace: ss.namespaceForSecret(n)}, ks); resource.IgnoreNotFound(err) != nil {
return errors.Wrap(err, errGetSecret)
}
s.Data = ks.Data
s.Metadata = &v1.ConnectionSecretMetadata{
Labels: ks.Labels,
Annotations: ks.Annotations,
Type: &ks.Type,
}
return nil
}
@ -118,6 +122,7 @@ func (ss *SecretStore) WriteKeyValues(ctx context.Context, s *store.Secret, wo .
if s.Metadata != nil {
ks.Labels = s.Metadata.Labels
ks.Annotations = s.Metadata.Annotations
if s.Metadata.Type != nil {
ks.Type = *s.Metadata.Type
@ -136,9 +141,11 @@ func (ss *SecretStore) WriteKeyValues(ctx context.Context, s *store.Secret, wo .
// The update was not allowed because it was a no-op.
return false, nil
}
if err != nil {
return false, errors.Wrap(err, errApplySecret)
}
return true, nil
}
@ -156,11 +163,13 @@ func (ss *SecretStore) DeleteKeyValues(ctx context.Context, s *store.Secret, do
// deletion, I opted for unifying both instead of adding conditional logic
// like add owner references if not remote and not call delete etc.
ks := &corev1.Secret{}
err := ss.client.Get(ctx, types.NamespacedName{Name: s.Name, Namespace: ss.namespaceForSecret(s.ScopedName)}, ks)
if kerrors.IsNotFound(err) {
// Secret already deleted, nothing to do.
return nil
}
if err != nil {
return errors.Wrap(err, errGetSecret)
}
@ -175,6 +184,7 @@ func (ss *SecretStore) DeleteKeyValues(ctx context.Context, s *store.Secret, do
for k := range s.Data {
delete(ks.Data, k)
}
if len(s.Data) == 0 || len(ks.Data) == 0 {
// Secret is deleted only if:
// - No kv to delete specified as input
@ -189,6 +199,7 @@ func (ss *SecretStore) namespaceForSecret(n store.ScopedName) string {
if n.Scope == "" {
return ss.defaultNamespace
}
return n.Scope
}
@ -244,6 +255,7 @@ func applyOptions(wo ...store.WriteOption) []resource.ApplyOption {
desiredSecret.Data = ds.Data
desiredSecret.Labels = ds.Metadata.Labels
desiredSecret.Annotations = ds.Metadata.Annotations
if ds.Metadata.Type != nil {
desiredSecret.Type = *ds.Metadata.Type
@ -252,5 +264,6 @@ func applyOptions(wo ...store.WriteOption) []resource.ApplyOption {
return nil
}
}
return ao
}

View File

@ -71,6 +71,7 @@ func TestSecretStoreReadKeyValues(t *testing.T) {
client resource.ClientApplicator
n store.ScopedName
}
type want struct {
result store.KeyValues
err error
@ -139,17 +140,18 @@ func TestSecretStoreReadKeyValues(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
ss := &SecretStore{
client: tc.args.client,
client: tc.client,
}
s := &store.Secret{}
s.ScopedName = tc.args.n
err := ss.ReadKeyValues(context.Background(), tc.args.n, s)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
s.ScopedName = tc.n
err := ss.ReadKeyValues(context.Background(), tc.n, s)
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nss.ReadKeyValues(...): -want error, +got error:\n%s", tc.reason, diff)
}
if diff := cmp.Diff(tc.want.result, s.Data); diff != "" {
if diff := cmp.Diff(tc.result, s.Data); diff != "" {
t.Errorf("\n%s\nss.ReadKeyValues(...): -want, +got:\n%s", tc.reason, diff)
}
})
@ -158,6 +160,7 @@ func TestSecretStoreReadKeyValues(t *testing.T) {
func TestSecretStoreWriteKeyValues(t *testing.T) {
secretTypeOpaque := corev1.SecretTypeOpaque
type args struct {
client resource.ClientApplicator
defaultNamespace string
@ -165,6 +168,7 @@ func TestSecretStoreWriteKeyValues(t *testing.T) {
wo []store.WriteOption
}
type want struct {
changed bool
err error
@ -465,14 +469,16 @@ func TestSecretStoreWriteKeyValues(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
ss := &SecretStore{
client: tc.args.client,
defaultNamespace: tc.args.defaultNamespace,
client: tc.client,
defaultNamespace: tc.defaultNamespace,
}
changed, err := ss.WriteKeyValues(context.Background(), tc.args.secret, tc.args.wo...)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
changed, err := ss.WriteKeyValues(context.Background(), tc.secret, tc.wo...)
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nss.WriteKeyValues(...): -want error, +got error:\n%s", tc.reason, diff)
}
if diff := cmp.Diff(tc.want.changed, changed); diff != "" {
if diff := cmp.Diff(tc.changed, changed); diff != "" {
t.Errorf("\n%s\nss.WriteKeyValues(...): -want changed, +got changed:\n%s", tc.reason, diff)
}
})
@ -487,6 +493,7 @@ func TestSecretStoreDeleteKeyValues(t *testing.T) {
do []store.DeleteOption
}
type want struct {
err error
}
@ -655,11 +662,12 @@ func TestSecretStoreDeleteKeyValues(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
ss := &SecretStore{
client: tc.args.client,
defaultNamespace: tc.args.defaultNamespace,
client: tc.client,
defaultNamespace: tc.defaultNamespace,
}
err := ss.DeleteKeyValues(context.Background(), tc.args.secret, tc.args.do...)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
err := ss.DeleteKeyValues(context.Background(), tc.secret, tc.do...)
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nss.DeleteKeyValues(...): -want error, +got error:\n%s", tc.reason, diff)
}
})
@ -671,6 +679,7 @@ func TestNewSecretStore(t *testing.T) {
client resource.ClientApplicator
cfg v1.SecretStoreConfig
}
type want struct {
err error
}
@ -836,8 +845,8 @@ users:
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
_, err := NewSecretStore(context.Background(), tc.args.client, nil, tc.args.cfg)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
_, err := NewSecretStore(context.Background(), tc.client, nil, tc.cfg)
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nNewSecretStore(...): -want error, +got error:\n%s", tc.reason, diff)
}
})

View File

@ -53,6 +53,7 @@ type SecretStore struct {
// NewSecretStore returns a new External SecretStore.
func NewSecretStore(_ context.Context, kube client.Client, tcfg *tls.Config, cfg v1.SecretStoreConfig) (*SecretStore, error) {
creds := credentials.NewTLS(tcfg)
conn, err := grpc.NewClient(cfg.Plugin.Endpoint, grpc.WithTransportCredentials(creds))
if err != nil {
return nil, errors.Wrapf(err, errFmtCannotDial, cfg.Plugin.Endpoint)
@ -81,6 +82,7 @@ func (ss *SecretStore) ReadKeyValues(ctx context.Context, n store.ScopedName, s
}
respSecretData := respSecret.GetData()
s.Data = make(map[string][]byte, len(respSecretData))
for d := range respSecretData {
s.Data[d] = respSecretData[d]
@ -89,6 +91,7 @@ func (ss *SecretStore) ReadKeyValues(ctx context.Context, n store.ScopedName, s
respSecretMetadata := respSecret.GetMetadata()
if len(respSecretMetadata) != 0 {
s.Metadata = new(v1.ConnectionSecretMetadata)
s.Metadata.Labels = make(map[string]string, len(respSecretMetadata))
for k, v := range respSecretMetadata {
s.Metadata.Labels[k] = v
@ -102,6 +105,7 @@ func (ss *SecretStore) ReadKeyValues(ctx context.Context, n store.ScopedName, s
func (ss *SecretStore) WriteKeyValues(ctx context.Context, s *store.Secret, _ ...store.WriteOption) (changed bool, err error) {
sec := &essproto.Secret{}
sec.ScopedName = ss.getScopedName(s.ScopedName)
sec.Data = make(map[string][]byte, len(s.Data))
for k, v := range s.Data {
sec.Data[k] = v
@ -141,5 +145,6 @@ func (ss *SecretStore) getScopedName(n store.ScopedName) string {
if n.Scope == "" {
n.Scope = ss.defaultScope
}
return filepath.Join(n.Scope, n.Name)
}

View File

@ -44,10 +44,12 @@ func TestReadKeyValues(t *testing.T) {
sn store.ScopedName
client ess.ExternalSecretStorePluginServiceClient
}
type want struct {
out *store.Secret
err error
}
cases := map[string]struct {
reason string
args
@ -123,7 +125,7 @@ func TestReadKeyValues(t *testing.T) {
t.Run(name, func(t *testing.T) {
ctx := context.Background()
ss := &SecretStore{
client: tc.args.client,
client: tc.client,
config: &v1.Config{
APIVersion: "v1alpha1",
Kind: "VaultConfig",
@ -132,13 +134,12 @@ func TestReadKeyValues(t *testing.T) {
}
s := &store.Secret{}
err := ss.ReadKeyValues(ctx, tc.args.sn, s)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
err := ss.ReadKeyValues(ctx, tc.sn, s)
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nss.ReadKeyValues(...): -want error, +got error:\n%s", tc.reason, diff)
}
if diff := cmp.Diff(tc.want.out, s); diff != "" {
if diff := cmp.Diff(tc.out, s); diff != "" {
t.Errorf("\n%s\nss.ReadKeyValues(...): -want, +got:\n%s", tc.reason, diff)
}
})
@ -149,10 +150,12 @@ func TestWriteKeyValues(t *testing.T) {
type args struct {
client ess.ExternalSecretStorePluginServiceClient
}
type want struct {
isChanged bool
err error
}
cases := map[string]struct {
reason string
args
@ -195,7 +198,7 @@ func TestWriteKeyValues(t *testing.T) {
t.Run(name, func(t *testing.T) {
ctx := context.Background()
ss := &SecretStore{
client: tc.args.client,
client: tc.client,
config: &v1.Config{
APIVersion: "v1alpha1",
Kind: "VaultConfig",
@ -205,12 +208,11 @@ func TestWriteKeyValues(t *testing.T) {
s := &store.Secret{}
isChanged, err := ss.WriteKeyValues(ctx, s)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nss.WriteKeyValues(...): -want error, +got error:\n%s", tc.reason, diff)
}
if diff := cmp.Diff(tc.want.isChanged, isChanged); diff != "" {
if diff := cmp.Diff(tc.isChanged, isChanged); diff != "" {
t.Errorf("\n%s\nss.WriteKeyValues(...): -want, +got:\n%s", tc.reason, diff)
}
})
@ -221,9 +223,11 @@ func TestDeleteKeyValues(t *testing.T) {
type args struct {
client ess.ExternalSecretStorePluginServiceClient
}
type want struct {
err error
}
cases := map[string]struct {
reason string
args
@ -260,7 +264,7 @@ func TestDeleteKeyValues(t *testing.T) {
t.Run(name, func(t *testing.T) {
ctx := context.Background()
ss := &SecretStore{
client: tc.args.client,
client: tc.client,
config: &v1.Config{
APIVersion: "v1alpha1",
Kind: "VaultConfig",
@ -270,8 +274,7 @@ func TestDeleteKeyValues(t *testing.T) {
s := &store.Secret{}
err := ss.DeleteKeyValues(ctx, s)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nss.DeletKeyValues(...): -want error, +got error:\n%s", tc.reason, diff)
}
})

View File

@ -43,6 +43,7 @@ type ScopedName struct {
// A Secret is an entity representing a set of sensitive Key Values.
type Secret struct {
ScopedName
Metadata *v1.ConnectionSecretMetadata
Data KeyValues
}
@ -53,11 +54,14 @@ func NewSecret(so SecretOwner, data KeyValues) *Secret {
if so.GetPublishConnectionDetailsTo() == nil {
return nil
}
p := so.GetPublishConnectionDetailsTo()
if p.Metadata == nil {
p.Metadata = &v1.ConnectionSecretMetadata{}
}
p.Metadata.SetOwnerUID(so.GetUID())
return &Secret{
ScopedName: ScopedName{
Name: p.Name,
@ -73,6 +77,7 @@ func (s *Secret) GetOwner() string {
if s.Metadata == nil {
return ""
}
return s.Metadata.GetOwnerUID()
}
@ -81,6 +86,7 @@ func (s *Secret) GetLabels() map[string]string {
if s.Metadata == nil {
return nil
}
return s.Metadata.Labels
}

View File

@ -43,5 +43,6 @@ func RuntimeStoreBuilder(ctx context.Context, local client.Client, tcfg *tls.Con
case v1.SecretStorePlugin:
return plugin.NewSecretStore(ctx, local, tcfg, cfg)
}
return nil, errors.Errorf(errFmtUnknownSecretStore, *cfg.Type)
}

View File

@ -85,6 +85,7 @@ func WithMessage(err error, message string) error {
if err == nil {
return nil
}
return fmt.Errorf("%s: %w", message, err)
}
@ -94,6 +95,7 @@ func WithMessagef(err error, format string, args ...any) error {
if err == nil {
return nil
}
return fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), err)
}
@ -120,6 +122,7 @@ func Cause(err error) error {
if !ok {
return err
}
err = w.Unwrap()
}
@ -146,6 +149,7 @@ func Join(errs ...error) MultiError {
if err == nil {
return nil
}
return multiError{aggregate: err}
}

View File

@ -29,6 +29,7 @@ func TestWrap(t *testing.T) {
err error
message string
}
cases := map[string]struct {
args args
want error
@ -65,6 +66,7 @@ func TestWrapf(t *testing.T) {
message string
args []any
}
cases := map[string]struct {
args args
want error

View File

@ -30,6 +30,7 @@ func SilentlyRequeueOnConflict(result reconcile.Result, err error) (reconcile.Re
if kerrors.IsConflict(Cause(err)) {
return reconcile.Result{Requeue: true}, nil
}
return result, err
}

View File

@ -33,10 +33,12 @@ func TestSilentlyRequeueOnConflict(t *testing.T) {
result reconcile.Result
err error
}
type want struct {
result reconcile.Result
err error
}
tests := []struct {
reason string
args args
@ -91,6 +93,7 @@ func TestSilentlyRequeueOnConflict(t *testing.T) {
if diff := cmp.Diff(tt.want.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nIgnoreConflict(...): -want error, +got error:\n%s", tt.reason, diff)
}
if diff := cmp.Diff(tt.want.result, got); diff != "" {
t.Errorf("\n%s\nIgnoreConflict(...): -want result, +got result:\n%s", tt.reason, diff)
}

View File

@ -52,6 +52,7 @@ func Normal(r Reason, message string, keysAndValues ...string) Event {
Annotations: map[string]string{},
}
sliceMap(keysAndValues, e.Annotations)
return e
}
@ -64,6 +65,7 @@ func Warning(r Reason, err error, keysAndValues ...string) Event {
Annotations: map[string]string{},
}
sliceMap(keysAndValues, e.Annotations)
return e
}
@ -97,7 +99,9 @@ func (r *APIRecorder) WithAnnotations(keysAndValues ...string) Recorder {
for k, v := range r.annotations {
ar.annotations[k] = v
}
sliceMap(keysAndValues, ar.annotations)
return ar
}

View File

@ -28,6 +28,7 @@ func TestSliceMap(t *testing.T) {
from []string
to map[string]string
}
cases := map[string]struct {
reason string
args args

View File

@ -33,9 +33,11 @@ type Flags struct {
// Enable a feature flag.
func (fs *Flags) Enable(f Flag) {
fs.m.Lock()
if fs.enabled == nil {
fs.enabled = make(map[Flag]bool)
}
fs.enabled[f] = true
fs.m.Unlock()
}
@ -45,7 +47,9 @@ func (fs *Flags) Enabled(f Flag) bool {
if fs == nil {
return false
}
fs.m.RLock()
defer fs.m.RUnlock()
return fs.enabled[f]
}

View File

@ -82,6 +82,7 @@ func (sg Segments) String() string {
b.WriteString(fmt.Sprintf("[%s]", s.Field))
continue
}
b.WriteString(fmt.Sprintf(".%s", s.Field))
case SegmentIndex:
b.WriteString(fmt.Sprintf("[%d]", s.Index))
@ -120,6 +121,7 @@ func Parse(path string) (Segments, error) {
go l.run()
segments := make(Segments, 0, 1)
for i := range l.items {
switch i.typ { //nolint:exhaustive // We're only worried about names, not separators.
case itemField:
@ -130,6 +132,7 @@ func Parse(path string) (Segments, error) {
return nil, errors.Errorf("%s at position %d", i.val, i.pos)
}
}
return segments, nil
}
@ -174,6 +177,7 @@ func (l *lexer) run() {
for state := lexField; state != nil; {
state = state(l)
}
close(l.items)
}
@ -182,7 +186,9 @@ func (l *lexer) emit(t itemType) {
if l.pos <= l.start {
return
}
l.items <- item{typ: t, pos: l.start, val: l.input[l.start:l.pos]}
l.start = l.pos
}
@ -202,12 +208,14 @@ func lexField(l *lexer) stateFn {
case leftBracket:
l.pos += i
l.emit(itemField)
return lexLeftBracket
// A period indicates the end of the field name.
case period:
l.pos += i
l.emit(itemField)
return lexPeriod
}
}
@ -216,6 +224,7 @@ func lexField(l *lexer) stateFn {
l.pos = len(l.input)
l.emit(itemField)
l.emit(itemEOL)
return nil
}
@ -234,6 +243,7 @@ func lexPeriod(l *lexer) stateFn {
if r == period {
return l.errorf(l.pos, "unexpected %q", period)
}
if r == leftBracket {
return l.errorf(l.pos, "unexpected %q", leftBracket)
}
@ -249,6 +259,7 @@ func lexLeftBracket(l *lexer) stateFn {
l.pos += utf8.RuneLen(leftBracket)
l.emit(itemLeftBracket)
return lexFieldOrIndex
}
@ -272,11 +283,13 @@ func lexFieldOrIndex(l *lexer) stateFn {
// Periods are not considered field separators when we're inside brackets.
l.pos += rbi
l.emit(itemFieldOrIndex)
return lexRightBracket
}
func lexRightBracket(l *lexer) stateFn {
l.pos += utf8.RuneLen(rightBracket)
l.emit(itemRightBracket)
return lexField
}

View File

@ -299,6 +299,7 @@ func TestParse(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\nParse(%s): %s: -want error, +got error:\n%s", tc.path, tc.reason, diff)
}
if diff := cmp.Diff(tc.want.s, got); diff != "" {
t.Errorf("\nParse(%s): %s: -want, +got:\n%s", tc.path, tc.reason, diff)
}

View File

@ -57,6 +57,7 @@ func merge(dst, src any, mergeOptions *xpv1.MergeOptions) (any, error) {
// because mergo currently supports merging only maps or structs,
// we wrap the argument to be passed to mergo.Merge in a map.
const keyArg = "arg"
argWrap := func(arg any) map[string]any {
return map[string]any{
keyArg: arg,
@ -77,6 +78,7 @@ func merge(dst, src any, mergeOptions *xpv1.MergeOptions) (any, error) {
if err := mergo.Merge(&mDst, argWrap(src), mergeOptions.MergoConfiguration()...); err != nil {
return nil, errors.Wrap(err, errInvalidMerge)
}
return mDst[keyArg], nil
}
@ -85,9 +87,11 @@ func removeSourceDuplicates(dst, src any) any {
if sliceDst.Kind() == reflect.Ptr {
sliceDst = sliceDst.Elem()
}
if sliceSrc.Kind() == reflect.Ptr {
sliceSrc = sliceSrc.Elem()
}
if sliceDst.Kind() != reflect.Slice || sliceSrc.Kind() != reflect.Slice {
return src
}
@ -95,6 +99,7 @@ func removeSourceDuplicates(dst, src any) any {
result := reflect.New(sliceSrc.Type()).Elem() // we will not modify src
for i := range sliceSrc.Len() {
itemSrc := sliceSrc.Index(i)
found := false
for j := 0; j < sliceDst.Len() && !found; j++ {
// if src item is found in the dst array
@ -102,10 +107,12 @@ func removeSourceDuplicates(dst, src any) any {
found = true
}
}
if !found {
// then put src item into result
result = reflect.Append(result, itemSrc)
}
}
return result.Interface()
}

View File

@ -36,6 +36,7 @@ func TestMergeValue(t *testing.T) {
valSrc2 = "e1-from-source-2"
valDst = "e1-from-destination"
)
formatArr := func(arr []string) string {
return fmt.Sprintf(`{"%s": ["%s"]}`, pathTest, strings.Join(arr, `", "`))
}
@ -59,15 +60,18 @@ func TestMergeValue(t *testing.T) {
type fields struct {
object map[string]any
}
type args struct {
path string
value any
mo *xpv1.MergeOptions
}
type want struct {
serialized string
err error
}
tests := map[string]struct {
reason string
fields fields
@ -199,11 +203,13 @@ func TestMergeValue(t *testing.T) {
p := &Paved{
object: tc.fields.object,
}
err := p.MergeValue(tc.args.path, tc.args.value, tc.args.mo)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\np.MergeValue(%s, %v): %s: -want error, +got error:\n%s",
tc.args.path, tc.args.value, tc.reason, diff)
}
if diff := cmp.Diff(want, p.object); diff != "" {
t.Fatalf("\np.MergeValue(%s, %v): %s: -want, +got:\n%s",
tc.args.path, tc.args.value, tc.reason, diff)

View File

@ -44,6 +44,7 @@ func IsNotFound(err error) bool {
_, ok := cause.(interface {
IsNotFound() bool
})
return ok
}
@ -100,6 +101,7 @@ func (p *Paved) UnstructuredContent() map[string]any {
if p.object == nil {
return make(map[string]any)
}
return p.object
}
@ -115,18 +117,22 @@ func (p *Paved) getValue(s Segments) (any, error) {
func getValueFromInterface(it any, s Segments) (any, error) {
for i, current := range s {
final := i == len(s)-1
switch current.Type {
case SegmentIndex:
array, ok := it.([]any)
if !ok {
return nil, errors.Errorf("%s: not an array", s[:i])
}
if current.Index >= uint(len(array)) {
return nil, notFoundError{errors.Errorf("%s: no such element", s[:i+1])}
}
if final {
return array[current.Index], nil
}
it = array[current.Index]
case SegmentField:
switch object := it.(type) {
@ -135,9 +141,11 @@ func getValueFromInterface(it any, s Segments) (any, error) {
if !ok {
return nil, notFoundError{errors.Errorf("%s: no such field", s[:i+1])}
}
if final {
return v, nil
}
it = object[current.Field]
case nil:
return nil, notFoundError{errors.Errorf("%s: expected map, got nil", s[:i])}
@ -165,14 +173,17 @@ func (p *Paved) ExpandWildcards(path string) ([]string, error) {
if err != nil {
return nil, errors.Wrapf(err, "cannot parse path %q", path)
}
segmentsArray, err := expandWildcards(p.object, segments)
if err != nil {
return nil, errors.Wrapf(err, "cannot expand wildcards for segments: %q", segments)
}
paths := make([]string, len(segmentsArray))
for i, s := range segmentsArray {
paths[i] = s.String()
}
return paths, nil
}
@ -180,7 +191,9 @@ func expandWildcards(data any, segments Segments) ([]Segments, error) { //nolint
// Even complexity turns out to be high, it is mostly because we have duplicate
// logic for arrays and maps and a couple of error handling.
var res []Segments
it := data
for i, current := range segments {
// wildcards are regular fields with "*" as string
if current.Type == SegmentField && current.Field == wildcard {
@ -190,10 +203,12 @@ func expandWildcards(data any, segments Segments) ([]Segments, error) { //nolint
expanded := make(Segments, len(segments))
copy(expanded, segments)
expanded = append(append(expanded[:i], FieldOrIndex(strconv.Itoa(ix))), expanded[i+1:]...)
r, err := expandWildcards(data, expanded)
if err != nil {
return nil, errors.Wrapf(err, "%q: cannot expand wildcards", expanded)
}
res = append(res, r...)
}
case map[string]any:
@ -201,10 +216,12 @@ func expandWildcards(data any, segments Segments) ([]Segments, error) { //nolint
expanded := make(Segments, len(segments))
copy(expanded, segments)
expanded = append(append(expanded[:i], Field(k)), expanded[i+1:]...)
r, err := expandWildcards(data, expanded)
if err != nil {
return nil, errors.Wrapf(err, "%q: cannot expand wildcards", expanded)
}
res = append(res, r...)
}
case nil:
@ -212,17 +229,22 @@ func expandWildcards(data any, segments Segments) ([]Segments, error) { //nolint
default:
return nil, errors.Errorf("%q: unexpected wildcard usage", segments[:i])
}
return res, nil
}
var err error
it, err = getValueFromInterface(data, segments[:i+1])
if IsNotFound(err) {
return nil, nil
}
if err != nil {
return nil, err
}
}
return append(res, segments), nil
}
@ -242,10 +264,12 @@ func (p *Paved) GetValueInto(path string, out any) error {
if err != nil {
return err
}
js, err := json.Marshal(val)
if err != nil {
return errors.Wrap(err, "cannot marshal value to JSON")
}
return errors.Wrap(json.Unmarshal(js, out), "cannot unmarshal value from JSON")
}
@ -260,6 +284,7 @@ func (p *Paved) GetString(path string) (string, error) {
if !ok {
return "", errors.Errorf("%s: not a string", path)
}
return s, nil
}
@ -281,6 +306,7 @@ func (p *Paved) GetStringArray(path string) ([]string, error) {
if !ok {
return nil, errors.Errorf("%s: not an array of strings", path)
}
sa[i] = s
}
@ -305,6 +331,7 @@ func (p *Paved) GetStringObject(path string) (map[string]string, error) {
if !ok {
return nil, errors.Errorf("%s: not an object with string field values", path)
}
so[k] = s
}
@ -322,6 +349,7 @@ func (p *Paved) GetBool(path string) (bool, error) {
if !ok {
return false, errors.Errorf("%s: not a bool", path)
}
return b, nil
}
@ -336,6 +364,7 @@ func (p *Paved) GetInteger(path string) (int64, error) {
if !ok {
return 0, errors.Errorf("%s: not a (int64) number", path)
}
return f, nil
}
@ -354,6 +383,7 @@ func (p *Paved) setValue(s Segments, value any) error {
}
var in any = p.object
for i, current := range s {
final := i == len(s)-1
@ -393,13 +423,16 @@ func (p *Paved) setValue(s Segments, value any) error {
func toValidJSON(value any) (any, error) {
var v any
j, err := json.Marshal(value)
if err != nil {
return nil, errors.Wrap(err, "cannot marshal value to JSON")
}
if err := json.Unmarshal(j, &v); err != nil {
return nil, errors.Wrap(err, "cannot unmarshal value from JSON")
}
return v, nil
}
@ -413,6 +446,7 @@ func prepareElement(array []any, current, next Segment) {
case SegmentField:
array[current.Index] = make(map[string]any)
}
return
}
@ -444,6 +478,7 @@ func prepareField(object map[string]any, current, next Segment) {
case SegmentField:
object[current.Field] = make(map[string]any)
}
return
}
@ -471,6 +506,7 @@ func (p *Paved) SetValue(path string, value any) error {
if err != nil {
return errors.Wrapf(err, "cannot parse path %q", path)
}
return p.setValue(segments, value)
}
@ -478,11 +514,13 @@ func (p *Paved) validateSegments(s Segments) error {
if !p.maxFieldPathIndexEnabled() {
return nil
}
for _, segment := range s {
if segment.Type == SegmentIndex && segment.Index > p.maxFieldPathIndex {
return errors.Errorf("index %v is greater than max allowed index %d", segment.Index, p.maxFieldPathIndex)
}
}
return nil
}
@ -511,6 +549,7 @@ func (p *Paved) DeleteField(path string) error {
if err != nil {
return errors.Wrapf(err, "cannot parse path %q", path)
}
return p.delete(segments)
}
@ -522,10 +561,14 @@ func (p *Paved) delete(segments Segments) error { //nolint:gocognit // See note
if err != nil {
return errors.Wrapf(err, "cannot delete %s", segments)
}
p.object = o.(map[string]any) //nolint:forcetypeassert // We're deleting from the root of the paved object, which is always a map[string]any.
return nil
}
var in any = p.object
for i, current := range segments {
// beforeLast is true for the element before the last one because
// slices cannot be changed in place and Go does not allow
@ -535,6 +578,7 @@ func (p *Paved) delete(segments Segments) error { //nolint:gocognit // See note
// until the element before the last one as opposed to
// Set/Get functions in this file.
beforeLast := i == len(segments)-2
switch current.Type {
case SegmentIndex:
array, ok := in.([]any)
@ -552,7 +596,9 @@ func (p *Paved) delete(segments Segments) error { //nolint:gocognit // See note
if err != nil {
return errors.Wrapf(err, "cannot delete %s", segments)
}
array[current.Index] = o
return nil
}
@ -573,13 +619,16 @@ func (p *Paved) delete(segments Segments) error { //nolint:gocognit // See note
if err != nil {
return errors.Wrapf(err, "cannot delete %s", segments)
}
object[current.Field] = o
return nil
}
in = object[current.Field]
}
}
return nil
}
@ -593,20 +642,26 @@ func deleteField(obj any, s Segment) (any, error) {
if !ok {
return nil, errors.New("not an array")
}
if len(array) == 0 || uint(len(array)) <= s.Index {
return array, nil
}
for i := s.Index; i < uint(len(array))-1; i++ {
array[i] = array[i+1]
}
return array[:len(array)-1], nil
case SegmentField:
object, ok := obj.(map[string]any)
if !ok {
return nil, errors.New("not an object")
}
delete(object, s.Field)
return object, nil
}
return nil, nil
}

View File

@ -68,6 +68,7 @@ func TestGetValue(t *testing.T) {
value any
err error
}
cases := map[string]struct {
reason string
path string
@ -181,6 +182,7 @@ func TestGetValue(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\np.GetValue(%s): %s: -want error, +got error:\n%s", tc.path, tc.reason, diff)
}
if diff := cmp.Diff(tc.want.value, got); diff != "" {
t.Errorf("\np.GetValue(%s): %s: -want, +got:\n%s", tc.path, tc.reason, diff)
}
@ -201,10 +203,12 @@ func TestGetValueInto(t *testing.T) {
path string
out any
}
type want struct {
out any
err error
}
cases := map[string]struct {
reason string
data []byte
@ -257,6 +261,7 @@ func TestGetValueInto(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\np.GetValueInto(%s): %s: -want error, +got error:\n%s", tc.args.path, tc.reason, diff)
}
if diff := cmp.Diff(tc.want.out, tc.args.out); diff != "" {
t.Errorf("\np.GetValueInto(%s): %s: -want, +got:\n%s", tc.args.path, tc.reason, diff)
}
@ -269,6 +274,7 @@ func TestGetString(t *testing.T) {
value string
err error
}
cases := map[string]struct {
reason string
path string
@ -310,6 +316,7 @@ func TestGetString(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\np.GetString(%s): %s: -want error, +got error:\n%s", tc.path, tc.reason, diff)
}
if diff := cmp.Diff(tc.want.value, got); diff != "" {
t.Errorf("\np.GetString(%s): %s: -want, +got:\n%s", tc.path, tc.reason, diff)
}
@ -322,6 +329,7 @@ func TestGetStringArray(t *testing.T) {
value []string
err error
}
cases := map[string]struct {
reason string
path string
@ -371,6 +379,7 @@ func TestGetStringArray(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\np.GetStringArray(%s): %s: -want error, +got error:\n%s", tc.path, tc.reason, diff)
}
if diff := cmp.Diff(tc.want.value, got); diff != "" {
t.Errorf("\np.GetStringArray(%s): %s: -want, +got:\n%s", tc.path, tc.reason, diff)
}
@ -383,6 +392,7 @@ func TestGetStringObject(t *testing.T) {
value map[string]string
err error
}
cases := map[string]struct {
reason string
path string
@ -432,6 +442,7 @@ func TestGetStringObject(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\np.GetStringObject(%s): %s: -want error, +got error:\n%s", tc.path, tc.reason, diff)
}
if diff := cmp.Diff(tc.want.value, got); diff != "" {
t.Errorf("\np.GetStringObject(%s): %s: -want, +got:\n%s", tc.path, tc.reason, diff)
}
@ -444,6 +455,7 @@ func TestGetBool(t *testing.T) {
value bool
err error
}
cases := map[string]struct {
reason string
path string
@ -485,6 +497,7 @@ func TestGetBool(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\np.GetBool(%s): %s: -want error, +got error:\n%s", tc.path, tc.reason, diff)
}
if diff := cmp.Diff(tc.want.value, got); diff != "" {
t.Errorf("\np.GetBool(%s): %s: -want, +got:\n%s", tc.path, tc.reason, diff)
}
@ -497,6 +510,7 @@ func TestGetInteger(t *testing.T) {
value int64
err error
}
cases := map[string]struct {
reason string
path string
@ -538,6 +552,7 @@ func TestGetInteger(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\np.GetNumber(%s): %s: -want error, +got error:\n%s", tc.path, tc.reason, diff)
}
if diff := cmp.Diff(tc.want.value, got); diff != "" {
t.Errorf("\np.GetNumber(%s): %s: -want, +got:\n%s", tc.path, tc.reason, diff)
}
@ -551,10 +566,12 @@ func TestSetValue(t *testing.T) {
value any
opts []PavedOption
}
type want struct {
object map[string]any
err error
}
cases := map[string]struct {
reason string
data []byte
@ -814,6 +831,7 @@ func TestSetValue(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\np.SetValue(%s, %v): %s: -want error, +got error:\n%s", tc.args.path, tc.args.value, tc.reason, diff)
}
if diff := cmp.Diff(tc.want.object, p.object); diff != "" {
t.Fatalf("\np.SetValue(%s, %v): %s: -want, +got:\n%s", tc.args.path, tc.args.value, tc.reason, diff)
}
@ -826,6 +844,7 @@ func TestExpandWildcards(t *testing.T) {
expanded []string
err error
}
cases := map[string]struct {
reason string
path string
@ -979,6 +998,7 @@ func TestExpandWildcards(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\np.ExpandWildcards(%s): %s: -want error, +got error:\n%s", tc.path, tc.reason, diff)
}
if diff := cmp.Diff(tc.want.expanded, got, cmpopts.SortSlices(func(x, y string) bool {
return x < y
})); diff != "" {
@ -992,10 +1012,12 @@ func TestDeleteField(t *testing.T) {
type args struct {
path string
}
type want struct {
object map[string]any
err error
}
cases := map[string]struct {
reason string
data []byte
@ -1267,6 +1289,7 @@ func TestDeleteField(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\np.DeleteField(%s): %s: -want error, +got error:\n%s", tc.args.path, tc.reason, diff)
}
if diff := cmp.Diff(tc.want.object, p.object); diff != "" {
t.Fatalf("\np.DeleteField(%s): %s: -want, +got:\n%s", tc.args.path, tc.reason, diff)
}

View File

@ -49,6 +49,7 @@ func (l *requestThrottlingFilter) klogToLogrLevel(klogLvl int) int {
if klogLvl >= 3 {
return klogLvl - 3
}
return 0
}

View File

@ -70,6 +70,7 @@ const (
// See https://github.com/crossplane/crossplane-runtime/issues/49
func ReferenceTo(o metav1.Object, of schema.GroupVersionKind) *corev1.ObjectReference {
v, k := of.ToAPIVersionAndKind()
return &corev1.ObjectReference{
APIVersion: v,
Kind: k,
@ -83,6 +84,7 @@ func ReferenceTo(o metav1.Object, of schema.GroupVersionKind) *corev1.ObjectRefe
// presumed to be of the supplied group, version, and kind.
func TypedReferenceTo(o metav1.Object, of schema.GroupVersionKind) *xpv1.TypedReference {
v, k := of.ToAPIVersionAndKind()
return &xpv1.TypedReference{
APIVersion: v,
Kind: k,
@ -108,6 +110,7 @@ func AsController(r *xpv1.TypedReference) metav1.OwnerReference {
ref := AsOwner(r)
ref.Controller = &t
ref.BlockOwnerDeletion = &t
return ref
}
@ -139,9 +142,11 @@ func AddOwnerReference(o metav1.Object, r metav1.OwnerReference) {
if refs[i].UID == r.UID {
refs[i] = r
o.SetOwnerReferences(refs)
return
}
}
o.SetOwnerReferences(append(refs, r))
}
@ -154,6 +159,7 @@ func AddControllerReference(o metav1.Object, r metav1.OwnerReference) error {
}
AddOwnerReference(o, r)
return nil
}
@ -165,6 +171,7 @@ func AddFinalizer(o metav1.Object, finalizer string) {
return
}
}
o.SetFinalizers(append(f, finalizer))
}
@ -176,6 +183,7 @@ func RemoveFinalizer(o metav1.Object, finalizer string) {
f = append(f[:i], f[i+1:]...)
}
}
o.SetFinalizers(f)
}
@ -187,6 +195,7 @@ func FinalizerExists(o metav1.Object, finalizer string) bool {
return true
}
}
return false
}
@ -197,9 +206,11 @@ func AddLabels(o metav1.Object, labels map[string]string) {
o.SetLabels(labels)
return
}
for k, v := range labels {
l[k] = v
}
o.SetLabels(l)
}
@ -209,9 +220,11 @@ func RemoveLabels(o metav1.Object, labels ...string) {
if l == nil {
return
}
for _, k := range labels {
delete(l, k)
}
o.SetLabels(l)
}
@ -222,9 +235,11 @@ func AddAnnotations(o metav1.Object, annotations map[string]string) {
o.SetAnnotations(annotations)
return
}
for k, v := range annotations {
a[k] = v
}
o.SetAnnotations(a)
}
@ -234,9 +249,11 @@ func RemoveAnnotations(o metav1.Object, annotations ...string) {
if a == nil {
return
}
for _, k := range annotations {
delete(a, k)
}
o.SetAnnotations(a)
}
@ -267,10 +284,12 @@ func SetExternalName(o metav1.Object, name string) {
// was most recently pending creation.
func GetExternalCreatePending(o metav1.Object) time.Time {
a := o.GetAnnotations()[AnnotationKeyExternalCreatePending]
t, err := time.Parse(time.RFC3339, a)
if err != nil {
return time.Time{}
}
return t
}
@ -284,10 +303,12 @@ func SetExternalCreatePending(o metav1.Object, t time.Time) {
// was most recently created.
func GetExternalCreateSucceeded(o metav1.Object) time.Time {
a := o.GetAnnotations()[AnnotationKeyExternalCreateSucceeded]
t, err := time.Parse(time.RFC3339, a)
if err != nil {
return time.Time{}
}
return t
}
@ -301,10 +322,12 @@ func SetExternalCreateSucceeded(o metav1.Object, t time.Time) {
// recently failed to create.
func GetExternalCreateFailed(o metav1.Object) time.Time {
a := o.GetAnnotations()[AnnotationKeyExternalCreateFailed]
t, err := time.Parse(time.RFC3339, a)
if err != nil {
return time.Time{}
}
return t
}
@ -344,6 +367,7 @@ func ExternalCreateSucceededDuring(o metav1.Object, d time.Duration) bool {
if t.IsZero() {
return false
}
return time.Since(t) < d
}

View File

@ -46,6 +46,7 @@ func TestReferenceTo(t *testing.T) {
o metav1.Object
of schema.GroupVersionKind
}
tests := map[string]struct {
args
want *corev1.ObjectReference
@ -77,7 +78,7 @@ func TestReferenceTo(t *testing.T) {
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
got := ReferenceTo(tc.args.o, tc.args.of)
got := ReferenceTo(tc.o, tc.of)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("ReferenceTo(): -want, +got:\n%s", diff)
}
@ -90,6 +91,7 @@ func TestTypedReferenceTo(t *testing.T) {
o metav1.Object
of schema.GroupVersionKind
}
tests := map[string]struct {
args
want *xpv1.TypedReference
@ -120,7 +122,7 @@ func TestTypedReferenceTo(t *testing.T) {
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
got := TypedReferenceTo(tc.args.o, tc.args.of)
got := TypedReferenceTo(tc.o, tc.of)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("TypedReferenceTo(): -want, +got:\n%s", diff)
}
@ -895,6 +897,7 @@ func TestSetExternalName(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
SetExternalName(tc.o, tc.name)
if diff := cmp.Diff(tc.want, tc.o); diff != "" {
t.Errorf("SetExternalName(...): -want, +got:\n%s", diff)
}
@ -947,6 +950,7 @@ func TestSetExternalCreatePending(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
SetExternalCreatePending(tc.o, tc.t)
if diff := cmp.Diff(tc.want, tc.o); diff != "" {
t.Errorf("SetExternalCreatePending(...): -want, +got:\n%s", diff)
}
@ -999,6 +1003,7 @@ func TestSetExternalCreateSucceeded(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
SetExternalCreateSucceeded(tc.o, tc.t)
if diff := cmp.Diff(tc.want, tc.o); diff != "" {
t.Errorf("SetExternalCreateSucceeded(...): -want, +got:\n%s", diff)
}
@ -1051,6 +1056,7 @@ func TestSetExternalCreateFailed(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
SetExternalCreateFailed(tc.o, tc.t)
if diff := cmp.Diff(tc.want, tc.o); diff != "" {
t.Errorf("SetExternalCreateFailed(...): -want, +got:\n%s", diff)
}

View File

@ -62,6 +62,7 @@ func SkipDirs() FilterFn {
if info.IsDir() {
return true, nil
}
return false, nil
}
}
@ -79,6 +80,7 @@ func SkipNotYAML() FilterFn {
if filepath.Ext(path) != ".yaml" && filepath.Ext(path) != ".yml" {
return true, nil
}
return false, nil
}
}
@ -92,18 +94,23 @@ func NewFsReadCloser(fs afero.Fs, dir string, fns ...FilterFn) (*FsReadCloser, e
if err != nil {
return err
}
for _, fn := range fns {
filter, err := fn(path, info)
if err != nil {
return err
}
if filter {
return nil
}
}
paths = append(paths, path)
return nil
})
return &FsReadCloser{
fs: fs,
dir: dir,
@ -121,24 +128,31 @@ func (r *FsReadCloser) Read(p []byte) (n int, err error) {
r.position = 0
r.wroteBreak = false
n = copy(p, "\n---\n")
return n, nil
}
if r.index == len(r.paths) {
return 0, io.EOF
}
if r.writeBreak {
n = copy(p, "\n...\n")
r.writeBreak = false
r.wroteBreak = true
return n, nil
}
b, err := afero.ReadFile(r.fs, r.paths[r.index])
n = copy(p, b[r.position:])
r.position += n
if errors.Is(err, io.EOF) || n == 0 {
r.writeBreak = true
err = nil
}
return n, err
}
@ -155,6 +169,7 @@ func (r *FsReadCloser) Annotate() any {
if index == len(r.paths) {
index--
}
return FsReadCloserAnnotation{
path: r.paths[index],
position: r.position,

View File

@ -78,6 +78,7 @@ func (l *PackageLinter) Lint(pkg Lintable) error {
return err
}
}
for _, o := range pkg.GetMeta() {
for _, fn := range l.perMeta {
if err := fn(o); err != nil {
@ -85,6 +86,7 @@ func (l *PackageLinter) Lint(pkg Lintable) error {
}
}
}
for _, o := range pkg.GetObjects() {
for _, fn := range l.perObject {
if err := fn(o); err != nil {
@ -92,6 +94,7 @@ func (l *PackageLinter) Lint(pkg Lintable) error {
}
}
}
return nil
}
@ -100,16 +103,20 @@ func (l *PackageLinter) Lint(pkg Lintable) error {
func Or(linters ...ObjectLinterFn) ObjectLinterFn {
return func(o runtime.Object) error {
var errs []string
for _, l := range linters {
if l == nil {
return errors.New(errNilLinterFn)
}
err := l(o)
if err == nil {
return nil
}
errs = append(errs, err.Error())
}
return errors.Errorf(errOrFmt, strings.Join(errs, ", "))
}
}

View File

@ -119,7 +119,6 @@ func TestLinter(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
err := tc.args.linter.Lint(tc.args.pkg)
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nl.Lint(...): -want error, +got error:\n%s", tc.reason, diff)
}
@ -175,7 +174,6 @@ func TestOr(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
err := Or(tc.args.one, tc.args.two)(crd)
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nOr(...): -want error, +got error:\n%s", tc.reason, diff)
}

View File

@ -105,21 +105,27 @@ func (p *PackageParser) Parse(_ context.Context, reader io.ReadCloser) (*Package
if reader == nil {
return pkg, nil
}
defer func() { _ = reader.Close() }()
yr := yaml.NewYAMLReader(bufio.NewReader(reader))
dm := json.NewSerializerWithOptions(json.DefaultMetaFactory, p.metaScheme, p.metaScheme, json.SerializerOptions{Yaml: true})
do := json.NewSerializerWithOptions(json.DefaultMetaFactory, p.objScheme, p.objScheme, json.SerializerOptions{Yaml: true})
for {
content, err := yr.Read()
if err != nil && !errors.Is(err, io.EOF) {
return pkg, err
}
if errors.Is(err, io.EOF) {
break
}
if isEmptyYAML(content) {
continue
}
m, _, err := dm.Decode(content, nil, nil)
if err != nil {
// NOTE(hasheddan): we only try to decode with object scheme if the
@ -127,15 +133,20 @@ func (p *PackageParser) Parse(_ context.Context, reader io.ReadCloser) (*Package
if !runtime.IsNotRegisteredError(err) {
return pkg, annotateErr(err, reader)
}
o, _, err := do.Decode(content, nil, nil)
if err != nil {
return pkg, annotateErr(err, reader)
}
pkg.objects = append(pkg.objects, o)
continue
}
pkg.meta = append(pkg.meta, m)
}
return pkg, nil
}
@ -151,6 +162,7 @@ func isEmptyYAML(y []byte) bool {
return false
}
}
return true
}
@ -159,6 +171,7 @@ func annotateErr(err error, reader io.ReadCloser) error {
if anno, ok := reader.(AnnotatedReadCloser); ok {
return errors.Wrapf(err, "%+v", anno.Annotate())
}
return err
}
@ -184,6 +197,7 @@ func NewPodLogBackend(bo ...BackendOption) *PodLogBackend {
for _, o := range bo {
o(p)
}
return p
}
@ -192,11 +206,14 @@ func (p *PodLogBackend) Init(ctx context.Context, bo ...BackendOption) (io.ReadC
for _, o := range bo {
o(p)
}
logs := p.client.CoreV1().Pods(p.namespace).GetLogs(p.name, &corev1.PodLogOptions{})
reader, err := logs.Stream(ctx)
if err != nil {
return nil, err
}
return reader, nil
}
@ -207,6 +224,7 @@ func PodName(name string) BackendOption {
if !ok {
return
}
pl.name = name
}
}
@ -218,6 +236,7 @@ func PodNamespace(namespace string) BackendOption {
if !ok {
return
}
pl.namespace = namespace
}
}
@ -229,6 +248,7 @@ func PodClient(client kubernetes.Interface) BackendOption {
if !ok {
return
}
pl.client = client
}
}
@ -261,6 +281,7 @@ func NewFsBackend(fs afero.Fs, bo ...BackendOption) *FsBackend {
for _, o := range bo {
o(f)
}
return f
}
@ -269,6 +290,7 @@ func (p *FsBackend) Init(_ context.Context, bo ...BackendOption) (io.ReadCloser,
for _, o := range bo {
o(p)
}
return NewFsReadCloser(p.fs, p.dir, p.skips...)
}
@ -279,6 +301,7 @@ func FsDir(dir string) BackendOption {
if !ok {
return
}
f.dir = dir
}
}
@ -290,6 +313,7 @@ func FsFilters(skips ...FilterFn) BackendOption {
if !ok {
return
}
f.skips = skips
}
}
@ -311,5 +335,6 @@ func (p *EchoBackend) Init(_ context.Context, bo ...BackendOption) (io.ReadClose
for _, o := range bo {
o(p)
}
return io.NopCloser(strings.NewReader(p.echo)), nil
}

View File

@ -195,18 +195,22 @@ func TestParser(t *testing.T) {
if err != nil {
t.Errorf("backend.Init(...): unexpected error: %s", err)
}
pkg, err := tc.parser.Parse(context.TODO(), r)
if err != nil && !tc.wantErr {
t.Errorf("parser.Parse(...): unexpected error: %s", err)
}
if tc.wantErr {
return
}
if diff := cmp.Diff(tc.pkg.GetObjects(), pkg.GetObjects(), cmpopts.SortSlices(func(i, j runtime.Object) bool {
return i.GetObjectKind().GroupVersionKind().String() > j.GetObjectKind().GroupVersionKind().String()
})); diff != "" {
t.Errorf("Objects: -want, +got:\n%s", diff)
}
if diff := cmp.Diff(tc.pkg.GetMeta(), pkg.GetMeta(), cmpopts.SortSlices(func(i, j runtime.Object) bool {
return i.GetObjectKind().GroupVersionKind().String() > j.GetObjectKind().GroupVersionKind().String()
})); diff != "" {
@ -220,9 +224,11 @@ func TestCleanYAML(t *testing.T) {
type args struct {
in []byte
}
type want struct {
out bool
}
cases := map[string]struct {
reason string
args args

View File

@ -53,7 +53,9 @@ func (s Settings) Generate() (string, error) {
if err != nil {
return "", err
}
pw[i] = s.CharacterSet[n.Int64()]
}
return string(pw), nil
}

View File

@ -8,12 +8,13 @@ import (
func TestGenerate(t *testing.T) {
// ¯\_(ツ)_/¯
want := "aaa"
got, err := Settings{CharacterSet: "a", Length: 3}.Generate()
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("Generate(): -want, +got:\n%s", diff)
}
if err != nil {
t.Errorf("Generate: %s\n", err)
}

View File

@ -52,5 +52,6 @@ func LimitRESTConfig(cfg *rest.Config, rps int) *rest.Config {
out := rest.CopyConfig(cfg)
out.QPS = float32(rps * 5)
out.Burst = rps * 10
return out
}

View File

@ -56,7 +56,9 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco
if d := r.when(req); d > 0 {
return reconcile.Result{RequeueAfter: d}, nil
}
r.limit.Forget(item)
return r.inner.Reconcile(ctx, req)
}
@ -78,6 +80,7 @@ func (r *Reconciler) when(req reconcile.Request) time.Duration {
r.limitedL.Lock()
delete(r.limited, item)
r.limitedL.Unlock()
return 0
}

View File

@ -41,6 +41,7 @@ func TestReconcile(t *testing.T) {
ctx context.Context
req reconcile.Request
}
type want struct {
res reconcile.Result
err error
@ -101,6 +102,7 @@ func TestReconcile(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Errorf("%s\nr.Reconcile(...): -want, +got error:\n%s", tc.reason, diff)
}
if diff := cmp.Diff(tc.want.res, got); diff != "" {
t.Errorf("%s\nr.Reconcile(...): -want, +got result:\n%s", tc.reason, diff)
}

View File

@ -70,7 +70,9 @@ func (a *NameAsExternalName) Initialize(ctx context.Context, mg resource.Managed
if meta.GetExternalName(mg) != "" {
return nil
}
meta.SetExternalName(mg, mg.GetName())
return errors.Wrap(a.client.Update(ctx, mg), errUpdateManaged)
}
@ -103,6 +105,7 @@ func (a *APISecretPublisher) PublishConnection(ctx context.Context, o resource.C
s := resource.ConnectionSecretFor(o, resource.MustGetKind(o, a.typer))
s.Data = c
err := a.secret.Apply(ctx, s,
resource.ConnectionSecretMustBeControllableBy(o.GetUID()),
resource.AllowUpdateIf(func(current, desired runtime.Object) bool {
@ -116,6 +119,7 @@ func (a *APISecretPublisher) PublishConnection(ctx context.Context, o resource.C
// The update was not allowed because it was a no-op.
return false, nil
}
if err != nil {
return false, errors.Wrap(err, errCreateOrUpdateSecret)
}
@ -153,15 +157,19 @@ func prepareJSONMerge(existing, resolved runtime.Object) ([]byte, error) {
// in the first place, instead of an unmarshal/marshal from the prepared
// patch []byte later.
existing.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{})
eBuff, err := json.Marshal(existing)
if err != nil {
return nil, errors.Wrap(err, errMarshalExisting)
}
rBuff, err := json.Marshal(resolved)
if err != nil {
return nil, errors.Wrap(err, errMarshalResolved)
}
patch, err := jsonpatch.CreateMergePatch(eBuff, rBuff)
return patch, errors.Wrap(err, errPreparePatch)
}
@ -177,6 +185,7 @@ func (a *APISimpleReferenceResolver) ResolveReferences(ctx context.Context, mg r
}
existing := mg.DeepCopyObject()
if err := rr.ResolveReferences(ctx, a.client); err != nil {
return errors.Wrap(err, errResolveReferences)
}
@ -190,6 +199,7 @@ func (a *APISimpleReferenceResolver) ResolveReferences(ctx context.Context, mg r
if err != nil {
return err
}
return errors.Wrap(a.client.Patch(ctx, mg, client.RawPatch(types.ApplyPatchType, patch), client.FieldOwner(fieldOwnerAPISimpleRefResolver), client.ForceOwnership), errPatchManaged)
}
@ -221,9 +231,12 @@ func (u *RetryingCriticalAnnotationUpdater) UpdateCriticalAnnotations(ctx contex
if getErr := u.client.Get(ctx, client.ObjectKeyFromObject(o), o); getErr != nil {
return getErr
}
meta.AddAnnotations(o, a)
}
return err
})
return errors.Wrap(err, errUpdateCriticalAnnotations)
}

View File

@ -106,10 +106,12 @@ func TestNameAsExternalName(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
api := NewNameAsExternalName(tc.client)
err := api.Initialize(tc.args.ctx, tc.args.mg)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Errorf("api.Initialize(...): -want error, +got error:\n%s", diff)
}
if diff := cmp.Diff(tc.want.mg, tc.args.mg, test.EquateConditions()); diff != "" {
t.Errorf("api.Initialize(...) Managed: -want, +got:\n%s", diff)
}
@ -144,6 +146,7 @@ func TestAPISecretPublisher(t *testing.T) {
err error
published bool
}
cases := map[string]struct {
reason string
fields fields
@ -223,10 +226,12 @@ func TestAPISecretPublisher(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
a := &APISecretPublisher{tc.fields.secret, tc.fields.typer}
got, gotErr := a.PublishConnection(tc.args.ctx, tc.args.mg, tc.args.c)
if diff := cmp.Diff(tc.want.err, gotErr, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nPublish(...): -wantErr, +gotErr:\n%s", tc.reason, diff)
}
if diff := cmp.Diff(tc.want.published, got); diff != "" {
t.Errorf("\n%s\nPublish(...): -wantPublished, +gotPublished:\n%s", tc.reason, diff)
}
@ -347,6 +352,7 @@ func TestResolveReferences(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
r := NewAPISimpleReferenceResolver(tc.c)
got := r.ResolveReferences(tc.args.ctx, tc.args.mg)
if diff := cmp.Diff(tc.want, got, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nr.ResolveReferences(...): -want, +got:\n%s", tc.reason, diff)
@ -360,6 +366,7 @@ func TestPrepareJSONMerge(t *testing.T) {
existing runtime.Object
resolved runtime.Object
}
type want struct {
patch string
err error
@ -392,6 +399,7 @@ func TestPrepareJSONMerge(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nprepareJSONMerge(...): -wantErr, +gotErr:\n%s", tc.reason, diff)
}
if diff := cmp.Diff(tc.want.patch, string(patch)); diff != "" {
t.Errorf("\n%s\nprepareJSONMerge(...): -want, +got:\n%s", tc.reason, diff)
}
@ -406,6 +414,7 @@ func TestRetryingCriticalAnnotationUpdater(t *testing.T) {
ctx context.Context
o client.Object
}
type want struct {
err error
o client.Object
@ -494,10 +503,12 @@ func TestRetryingCriticalAnnotationUpdater(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
u := NewRetryingCriticalAnnotationUpdater(tc.c)
got := u.UpdateCriticalAnnotations(tc.args.ctx, tc.args.o)
if diff := cmp.Diff(tc.want.err, got, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nu.UpdateCriticalAnnotations(...): -want, +got:\n%s", tc.reason, diff)
}
if diff := cmp.Diff(tc.want.o, tc.args.o); diff != "" {
t.Errorf("\n%s\nu.UpdateCriticalAnnotations(...): -want, +got:\n%s", tc.reason, diff)
}

View File

@ -119,6 +119,7 @@ func (g *GRPCChangeLogger) Log(ctx context.Context, managed resource.Managed, op
// send everything we've got to the change log service
_, err = g.client.SendChangeLog(sendCtx, &v1alpha1.SendChangeLogRequest{Entry: entry}, grpc.WaitForReady(true))
return errors.Wrap(err, "cannot send change log entry")
}

View File

@ -52,6 +52,7 @@ func (c *changeLogServiceClient) SendChangeLog(ctx context.Context, in *v1alpha1
if c.sendFn != nil {
return c.sendFn(ctx, in, opts...)
}
return nil, nil
}
@ -167,6 +168,7 @@ func mustObjectAsProtobufStruct(o runtime.Object) *structpb.Struct {
if err != nil {
panic(err)
}
return s
}
@ -183,6 +185,7 @@ func equateApproxTimepb(margin time.Duration) []cmp.Option {
a, b := p.Last().Values()
return msgIsTimestamp(a) && msgIsTimestamp(b)
}
return false
},
cmp.Transformer("timestamppb", func(t protocmp.Message) time.Time {

View File

@ -116,10 +116,12 @@ func (r *MRMetricRecorder) recordFirstTimeReconciled(managed resource.Managed) {
func (r *MRMetricRecorder) recordDrift(managed resource.Managed) {
name := managed.GetName()
last, ok := r.lastObservation.Load(name)
if !ok {
return
}
lt, ok := last.(time.Time)
if !ok {
return
@ -142,6 +144,7 @@ func (r *MRMetricRecorder) recordFirstTimeReady(managed resource.Managed) {
if !ok {
return
}
r.mrFirstTimeReady.With(getLabels(managed)).Observe(time.Since(managed.GetCreationTimestamp().Time).Seconds())
r.firstObservation.Delete(managed.GetName())
}

View File

@ -139,6 +139,7 @@ func (m *ManagementPoliciesResolver) Validate() error {
return nil
}
}
return fmt.Errorf(errFmtManagementPolicyNotSupported, m.managementPolicies.UnsortedList())
}
@ -148,6 +149,7 @@ func (m *ManagementPoliciesResolver) IsPaused() bool {
if !m.enabled {
return false
}
return m.managementPolicies.Len() == 0
}
@ -157,6 +159,7 @@ func (m *ManagementPoliciesResolver) ShouldCreate() bool {
if !m.enabled {
return true
}
return m.managementPolicies.HasAny(xpv1.ManagementActionCreate, xpv1.ManagementActionAll)
}
@ -166,6 +169,7 @@ func (m *ManagementPoliciesResolver) ShouldUpdate() bool {
if !m.enabled {
return true
}
return m.managementPolicies.HasAny(xpv1.ManagementActionUpdate, xpv1.ManagementActionAll)
}
@ -175,6 +179,7 @@ func (m *ManagementPoliciesResolver) ShouldLateInitialize() bool {
if !m.enabled {
return true
}
return m.managementPolicies.HasAny(xpv1.ManagementActionLateInitialize, xpv1.ManagementActionAll)
}
@ -185,6 +190,7 @@ func (m *ManagementPoliciesResolver) ShouldOnlyObserve() bool {
if !m.enabled {
return false
}
return m.managementPolicies.Equal(sets.New[xpv1.ManagementAction](xpv1.ManagementActionObserve))
}

View File

@ -32,15 +32,18 @@ type PublisherChain []ConnectionPublisher
// encounters, if any.
func (pc PublisherChain) PublishConnection(ctx context.Context, o resource.ConnectionSecretOwner, c ConnectionDetails) (bool, error) {
published := false
for _, p := range pc {
pb, err := p.PublishConnection(ctx, o, c)
if err != nil {
return published, err
}
if pb {
published = true
}
}
return published, nil
}
@ -52,6 +55,7 @@ func (pc PublisherChain) UnpublishConnection(ctx context.Context, o resource.Con
return err
}
}
return nil
}
@ -65,6 +69,7 @@ func (m *DisabledSecretStoreManager) PublishConnection(_ context.Context, so res
if so.GetPublishConnectionDetailsTo() != nil {
return false, errors.New(errSecretStoreDisabled)
}
return false, nil
}
@ -74,5 +79,6 @@ func (m *DisabledSecretStoreManager) UnpublishConnection(_ context.Context, so r
if so.GetPublishConnectionDetailsTo() != nil {
return errors.New(errSecretStoreDisabled)
}
return nil
}

View File

@ -109,6 +109,7 @@ func TestPublisherChain(t *testing.T) {
if diff := cmp.Diff(tc.want.err, gotErr, test.EquateErrors()); diff != "" {
t.Errorf("Publish(...): -want, +got:\n%s", diff)
}
if diff := cmp.Diff(tc.want.published, got); diff != "" {
t.Errorf("Publish(...): -wantPublished, +gotPublished:\n%s", diff)
}
@ -120,6 +121,7 @@ func TestDisabledSecretStorePublish(t *testing.T) {
type args struct {
mg resource.Managed
}
type want struct {
published bool
err error
@ -151,10 +153,12 @@ func TestDisabledSecretStorePublish(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
ss := &DisabledSecretStoreManager{}
got, gotErr := ss.PublishConnection(context.Background(), tc.args.mg, nil)
if diff := cmp.Diff(tc.want.err, gotErr, test.EquateErrors()); diff != "" {
t.Errorf("Publish(...): -want, +got:\n%s", diff)
}
if diff := cmp.Diff(tc.want.published, got); diff != "" {
t.Errorf("Publish(...): -wantPublished, +gotPublished:\n%s", diff)
}
@ -166,6 +170,7 @@ func TestDisabledSecretStoreUnpublish(t *testing.T) {
type args struct {
mg resource.Managed
}
type want struct {
err error
}
@ -196,6 +201,7 @@ func TestDisabledSecretStoreUnpublish(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
ss := &DisabledSecretStoreManager{}
gotErr := ss.UnpublishConnection(context.Background(), tc.args.mg, nil)
if diff := cmp.Diff(tc.want.err, gotErr, test.EquateErrors()); diff != "" {
t.Errorf("Publish(...): -want, +got:\n%s", diff)

View File

@ -199,6 +199,7 @@ func (cc InitializerChain) Initialize(ctx context.Context, mg resource.Managed)
return err
}
}
return nil
}
@ -823,7 +824,6 @@ func NewReconciler(m manager.Manager, of resource.ManagedKind, o ...ReconcilerOp
func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (result reconcile.Result, err error) { //nolint:gocognit // See note below.
// NOTE(negz): This method is a well over our cyclomatic complexity goal.
// Be wary of adding additional complexity.
defer func() { result, err = errors.SilentlyRequeueOnConflict(result, err) }()
log := r.log.WithValues("request", req)
@ -886,11 +886,14 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
// that is not supported by the controller.
if err := policy.Validate(); err != nil {
log.Debug(err.Error())
if kerrors.IsConflict(err) {
return reconcile.Result{Requeue: true}, nil
}
record.Event(managed, event.Warning(reasonManagementPolicyInvalid, err))
status.MarkConditions(xpv1.ReconcileError(err))
return reconcile.Result{}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
@ -911,23 +914,30 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
// condition. If not, we requeue explicitly, which will trigger
// backoff.
log.Debug("Cannot unpublish connection details", "error", err)
if kerrors.IsConflict(err) {
return reconcile.Result{Requeue: true}, nil
}
record.Event(managed, event.Warning(reasonCannotUnpublish, err))
status.MarkConditions(xpv1.Deleting(), xpv1.ReconcileError(err))
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
if err := r.managed.RemoveFinalizer(ctx, managed); err != nil {
// If this is the first time we encounter this issue we'll be
// requeued implicitly when we update our status with the new error
// condition. If not, we requeue explicitly, which will trigger
// backoff.
log.Debug("Cannot remove managed resource finalizer", "error", err)
if kerrors.IsConflict(err) {
return reconcile.Result{Requeue: true}, nil
}
status.MarkConditions(xpv1.Deleting(), xpv1.ReconcileError(err))
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
@ -937,6 +947,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
// longer exist and thus there is no point trying to update its status.
r.metricRecorder.recordDeleted(managed)
log.Debug("Successfully deleted managed resource")
return reconcile.Result{Requeue: false}, nil
}
@ -945,11 +956,14 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
// implicitly when we update our status with the new error condition. If
// not, we requeue explicitly, which will trigger backoff.
log.Debug("Cannot initialize managed resource", "error", err)
if kerrors.IsConflict(err) {
return reconcile.Result{Requeue: true}, nil
}
record.Event(managed, event.Warning(reasonCannotInitialize, err))
status.MarkConditions(xpv1.ReconcileError(err))
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
@ -963,8 +977,10 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
log.Debug(errCreateIncomplete)
record.Event(managed, event.Warning(reasonCannotInitialize, errors.New(errCreateIncomplete)))
status.MarkConditions(xpv1.Creating(), xpv1.ReconcileError(errors.New(errCreateIncomplete)))
return reconcile.Result{Requeue: false}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
log.Debug("Cannot determine creation result, but proceeding due to deterministic external name")
}
@ -985,11 +1001,14 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
// requeued implicitly due to the status update. If not, we want
// requeue explicitly, which will trigger backoff.
log.Debug("Cannot resolve managed resource references", "error", err)
if kerrors.IsConflict(err) {
return reconcile.Result{Requeue: true}, nil
}
record.Event(managed, event.Warning(reasonCannotResolveRefs, err))
status.MarkConditions(xpv1.ReconcileError(err))
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
}
@ -1002,13 +1021,17 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
// condition. If not, we requeue explicitly, which will trigger
// backoff.
log.Debug("Cannot connect to provider", "error", err)
if kerrors.IsConflict(err) {
return reconcile.Result{Requeue: true}, nil
}
record.Event(managed, event.Warning(reasonCannotConnect, err))
status.MarkConditions(xpv1.ReconcileError(errors.Wrap(err, errReconcileConnect)))
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
defer func() {
if err := r.external.Disconnect(ctx); err != nil {
log.Debug("Cannot disconnect from provider", "error", err)
@ -1030,11 +1053,14 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
// error condition. If not, we requeue explicitly, which will
// trigger backoff.
log.Debug("Cannot observe external resource", "error", err)
if kerrors.IsConflict(err) {
return reconcile.Result{Requeue: true}, nil
}
record.Event(managed, event.Warning(reasonCannotObserve, err))
status.MarkConditions(xpv1.ReconcileError(errors.Wrap(err, errReconcileObserve)))
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
@ -1043,6 +1069,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
if !observation.ResourceExists && policy.ShouldOnlyObserve() {
record.Event(managed, event.Warning(reasonCannotObserve, errors.New(errExternalResourceNotExist)))
status.MarkConditions(xpv1.ReconcileError(errors.Wrap(errors.New(errExternalResourceNotExist), errReconcileObserve)))
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
@ -1054,6 +1081,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
if !observation.ResourceExists && meta.ExternalCreateSucceededDuring(managed, r.creationGracePeriod) {
log.Debug("Waiting for external resource existence to be confirmed")
record.Event(managed, event.Normal(reasonPending, "Waiting for external resource existence to be confirmed"))
return reconcile.Result{Requeue: true}, nil
}
@ -1076,11 +1104,14 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
// status with the new error condition. If not, we want requeue
// explicitly, which will trigger backoff.
log.Debug("Cannot delete external resource", "error", err)
if err := r.change.Log(ctx, managedPreOp, v1alpha1.OperationType_OPERATION_TYPE_DELETE, err, deletion.AdditionalDetails); err != nil {
log.Info(errRecordChangeLog, "error", err)
}
record.Event(managed, event.Warning(reasonCannotDelete, err))
status.MarkConditions(xpv1.Deleting(), xpv1.ReconcileError(errors.Wrap(err, errReconcileDelete)))
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
@ -1092,36 +1123,47 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
// unpublish and finalize. If it still exists we'll re-enter this
// block and try again.
log.Debug("Successfully requested deletion of external resource")
if err := r.change.Log(ctx, managedPreOp, v1alpha1.OperationType_OPERATION_TYPE_DELETE, nil, deletion.AdditionalDetails); err != nil {
log.Info(errRecordChangeLog, "error", err)
}
record.Event(managed, event.Normal(reasonDeleted, "Successfully requested deletion of external resource"))
status.MarkConditions(xpv1.Deleting(), xpv1.ReconcileSuccess())
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
if err := r.managed.UnpublishConnection(ctx, managed, observation.ConnectionDetails); err != nil {
// If this is the first time we encounter this issue we'll be
// requeued implicitly when we update our status with the new error
// condition. If not, we requeue explicitly, which will trigger
// backoff.
log.Debug("Cannot unpublish connection details", "error", err)
if kerrors.IsConflict(err) {
return reconcile.Result{Requeue: true}, nil
}
record.Event(managed, event.Warning(reasonCannotUnpublish, err))
status.MarkConditions(xpv1.Deleting(), xpv1.ReconcileError(err))
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
if err := r.managed.RemoveFinalizer(ctx, managed); err != nil {
// If this is the first time we encounter this issue we'll be
// requeued implicitly when we update our status with the new error
// condition. If not, we requeue explicitly, which will trigger
// backoff.
log.Debug("Cannot remove managed resource finalizer", "error", err)
if kerrors.IsConflict(err) {
return reconcile.Result{Requeue: true}, nil
}
status.MarkConditions(xpv1.Deleting(), xpv1.ReconcileError(err))
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
@ -1131,6 +1173,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
// thus there is no point trying to update its status.
r.metricRecorder.recordDeleted(managed)
log.Debug("Successfully deleted managed resource")
return reconcile.Result{Requeue: false}, nil
}
@ -1139,11 +1182,14 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
// implicitly when we update our status with the new error condition. If
// not, we requeue explicitly, which will trigger backoff.
log.Debug("Cannot publish connection details", "error", err)
if kerrors.IsConflict(err) {
return reconcile.Result{Requeue: true}, nil
}
record.Event(managed, event.Warning(reasonCannotPublish, err))
status.MarkConditions(xpv1.ReconcileError(err))
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
@ -1152,10 +1198,13 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
// implicitly when we update our status with the new error condition. If
// not, we requeue explicitly, which will trigger backoff.
log.Debug("Cannot add finalizer", "error", err)
if kerrors.IsConflict(err) {
return reconcile.Result{Requeue: true}, nil
}
status.MarkConditions(xpv1.ReconcileError(err))
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
@ -1168,13 +1217,17 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
// don't use the CriticalAnnotationUpdater because we _want_ the
// update to fail if we get a 409 due to a stale version.
meta.SetExternalCreatePending(managed, time.Now())
if err := r.client.Update(ctx, managed); err != nil {
log.Debug(errUpdateManaged, "error", err)
if kerrors.IsConflict(err) {
return reconcile.Result{Requeue: true}, nil
}
record.Event(managed, event.Warning(reasonCannotUpdateManaged, errors.Wrap(err, errUpdateManaged)))
status.MarkConditions(xpv1.Creating(), xpv1.ReconcileError(errors.Wrap(err, errUpdateManaged)))
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
@ -1186,6 +1239,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
// issue we'll be requeued implicitly when we update our status with
// the new error condition. If not, we requeue explicitly, which will trigger backoff.
log.Debug("Cannot create external resource", "error", err)
if !kerrors.IsConflict(err) {
record.Event(managed, event.Warning(reasonCannotCreate, err))
}
@ -1197,6 +1251,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
// won't know whether or not it created an external
// resource.
meta.SetExternalCreateFailed(managed, time.Now())
if err := r.managed.UpdateCriticalAnnotations(ctx, managed); err != nil {
log.Debug(errUpdateManagedAnnotations, "error", err)
record.Event(managed, event.Warning(reasonCannotUpdateManaged, errors.Wrap(err, errUpdateManagedAnnotations)))
@ -1211,7 +1266,9 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
if err := r.change.Log(ctx, managedPreOp, v1alpha1.OperationType_OPERATION_TYPE_CREATE, err, creation.AdditionalDetails); err != nil {
log.Info(errRecordChangeLog, "error", err)
}
status.MarkConditions(xpv1.Creating(), xpv1.ReconcileError(errors.Wrap(err, errReconcileCreate)))
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
@ -1234,13 +1291,17 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
// Create implementations are advised not to alter status, but
// we may revisit this in future.
meta.SetExternalCreateSucceeded(managed, time.Now())
if err := r.managed.UpdateCriticalAnnotations(ctx, managed); err != nil {
log.Debug(errUpdateManagedAnnotations, "error", err)
if kerrors.IsConflict(err) {
return reconcile.Result{Requeue: true}, nil
}
record.Event(managed, event.Warning(reasonCannotUpdateManaged, errors.Wrap(err, errUpdateManagedAnnotations)))
status.MarkConditions(xpv1.Creating(), xpv1.ReconcileError(errors.Wrap(err, errUpdateManagedAnnotations)))
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
@ -1249,11 +1310,14 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
// requeued implicitly when we update our status with the new error
// condition. If not, we requeue explicitly, which will trigger backoff.
log.Debug("Cannot publish connection details", "error", err)
if kerrors.IsConflict(err) {
return reconcile.Result{Requeue: true}, nil
}
record.Event(managed, event.Warning(reasonCannotPublish, err))
status.MarkConditions(xpv1.Creating(), xpv1.ReconcileError(err))
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
@ -1264,6 +1328,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
log.Debug("Successfully requested creation of external resource")
record.Event(managed, event.Normal(reasonCreated, "Successfully requested creation of external resource"))
status.MarkConditions(xpv1.Creating(), xpv1.ReconcileSuccess())
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
@ -1279,6 +1344,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
log.Debug(errUpdateManaged, "error", err)
record.Event(managed, event.Warning(reasonCannotUpdateManaged, err))
status.MarkConditions(xpv1.ReconcileError(errors.Wrap(err, errUpdateManaged)))
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
}
@ -1313,6 +1379,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
reconcileAfter := r.pollIntervalHook(managed, r.pollInterval)
log.Debug("Skipping update due to managementPolicies. Reconciliation succeeded", "requeue-after", time.Now().Add(reconcileAfter))
status.MarkConditions(xpv1.ReconcileSuccess())
return reconcile.Result{RequeueAfter: reconcileAfter}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
@ -1324,16 +1391,20 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
// requeued implicitly when we update our status with the new error
// condition. If not, we requeue explicitly, which will trigger backoff.
log.Debug("Cannot update external resource")
if err := r.change.Log(ctx, managedPreOp, v1alpha1.OperationType_OPERATION_TYPE_UPDATE, err, update.AdditionalDetails); err != nil {
log.Info(errRecordChangeLog, "error", err)
}
record.Event(managed, event.Warning(reasonCannotUpdate, err))
status.MarkConditions(xpv1.ReconcileError(errors.Wrap(err, errReconcileUpdate)))
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
// record the drift after the successful update.
r.metricRecorder.recordDrift(managed)
if err := r.change.Log(ctx, managedPreOp, v1alpha1.OperationType_OPERATION_TYPE_UPDATE, nil, update.AdditionalDetails); err != nil {
log.Info(errRecordChangeLog, "error", err)
}
@ -1345,6 +1416,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
log.Debug("Cannot publish connection details", "error", err)
record.Event(managed, event.Warning(reasonCannotPublish, err))
status.MarkConditions(xpv1.ReconcileError(err))
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}
@ -1357,5 +1429,6 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
log.Debug("Successfully requested update of external resource", "requeue-after", time.Now().Add(reconcileAfter))
record.Event(managed, event.Normal(reasonUpdated, "Successfully requested update of external resource"))
status.MarkConditions(xpv1.ReconcileSuccess())
return reconcile.Result{RequeueAfter: reconcileAfter}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
}

View File

@ -2020,8 +2020,8 @@ func TestReconciler(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
r := NewReconciler(tc.args.m, tc.args.mg, tc.args.o...)
got, err := r.Reconcile(context.Background(), reconcile.Request{})
got, err := r.Reconcile(context.Background(), reconcile.Request{})
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\nReason: %s\nr.Reconcile(...): -want error, +got error:\n%s", tc.reason, diff)
}
@ -2038,6 +2038,7 @@ func TestTestManagementPoliciesResolverIsPaused(t *testing.T) {
enabled bool
policy xpv1.ManagementPolicies
}
cases := map[string]struct {
reason string
args args
@ -2083,6 +2084,7 @@ func TestManagementPoliciesResolverValidate(t *testing.T) {
enabled bool
policy xpv1.ManagementPolicies
}
cases := map[string]struct {
reason string
args args
@ -2144,6 +2146,7 @@ func TestManagementPoliciesResolverShouldCreate(t *testing.T) {
managementPoliciesEnabled bool
policy xpv1.ManagementPolicies
}
cases := map[string]struct {
reason string
args args
@ -2196,6 +2199,7 @@ func TestManagementPoliciesResolverShouldUpdate(t *testing.T) {
managementPoliciesEnabled bool
policy xpv1.ManagementPolicies
}
cases := map[string]struct {
reason string
args args
@ -2248,6 +2252,7 @@ func TestManagementPoliciesResolverShouldLateInitialize(t *testing.T) {
managementPoliciesEnabled bool
policy xpv1.ManagementPolicies
}
cases := map[string]struct {
reason string
args args
@ -2300,6 +2305,7 @@ func TestManagementPoliciesResolverOnlyObserve(t *testing.T) {
managementPoliciesEnabled bool
policy xpv1.ManagementPolicies
}
cases := map[string]struct {
reason string
args args
@ -2344,9 +2350,11 @@ func TestShouldDelete(t *testing.T) {
managementPoliciesEnabled bool
managed resource.Managed
}
type want struct {
delete bool
}
cases := map[string]struct {
reason string
args args
@ -2747,12 +2755,14 @@ func TestReconcilerChangeLogs(t *testing.T) {
func asManaged(obj client.Object, generation int64) *fake.Managed {
mg := obj.(*fake.Managed)
mg.Generation = generation
return mg
}
func newManaged(generation int64) *fake.Managed {
mg := &fake.Managed{}
mg.Generation = generation
return mg
}

View File

@ -20,10 +20,12 @@ func (c *typedExternalConnectDisconnectorWrapper[managed]) Connect(ctx context.C
if !ok {
return nil, errors.Errorf(errFmtUnexpectedObjectType, mg)
}
external, err := c.c.Connect(ctx, cr)
if err != nil {
return nil, err
}
return &typedExternalClientWrapper[managed]{c: external}, nil
}
@ -42,6 +44,7 @@ func (c *typedExternalClientWrapper[managed]) Observe(ctx context.Context, mg re
if !ok {
return ExternalObservation{}, errors.Errorf(errFmtUnexpectedObjectType, mg)
}
return c.c.Observe(ctx, cr)
}
@ -50,6 +53,7 @@ func (c *typedExternalClientWrapper[managed]) Create(ctx context.Context, mg res
if !ok {
return ExternalCreation{}, errors.Errorf(errFmtUnexpectedObjectType, mg)
}
return c.c.Create(ctx, cr)
}
@ -58,6 +62,7 @@ func (c *typedExternalClientWrapper[managed]) Update(ctx context.Context, mg res
if !ok {
return ExternalUpdate{}, errors.Errorf(errFmtUnexpectedObjectType, mg)
}
return c.c.Update(ctx, cr)
}
@ -66,6 +71,7 @@ func (c *typedExternalClientWrapper[managed]) Delete(ctx context.Context, mg res
if !ok {
return ExternalDelete{}, errors.Errorf(errFmtUnexpectedObjectType, mg)
}
return c.c.Delete(ctx, cr)
}

View File

@ -168,6 +168,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco
if err := r.client.List(ctx, l, client.MatchingLabels{xpv1.LabelKeyProviderName: pc.GetName()}); err != nil {
log.Debug(errListPCUs, "error", err)
r.record.Event(pc, event.Warning(reasonAccount, errors.Wrap(err, errListPCUs)))
return reconcile.Result{RequeueAfter: shortWait}, nil
}
@ -181,11 +182,14 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco
if err := r.client.Delete(ctx, pcu); resource.IgnoreNotFound(err) != nil {
log.Debug(errDeletePCU, "error", err)
r.record.Event(pc, event.Warning(reasonAccount, errors.Wrap(err, errDeletePCU)))
return reconcile.Result{RequeueAfter: shortWait}, nil
}
users--
}
}
log = log.WithValues("usages", users)
if meta.WasDeleted(pc) {
@ -198,10 +202,12 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco
// We're watching our usages, so we'll be requeued when they go.
pc.SetUsers(users)
pc.SetConditions(Terminating().WithMessage(msg))
return reconcile.Result{Requeue: false}, errors.Wrap(r.client.Status().Update(ctx, pc), errUpdateStatus)
}
meta.RemoveFinalizer(pc, finalizer)
if err := r.client.Update(ctx, pc); err != nil {
r.log.Debug(errUpdate, "error", err)
return reconcile.Result{RequeueAfter: shortWait}, nil
@ -212,6 +218,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco
}
meta.AddFinalizer(pc, finalizer)
if err := r.client.Update(ctx, pc); err != nil {
r.log.Debug(errUpdate, "error", err)
return reconcile.Result{RequeueAfter: shortWait}, nil
@ -219,5 +226,6 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco
// There's no need to requeue explicitly - we're watching all PCs.
pc.SetUsers(users)
return reconcile.Result{Requeue: false}, errors.Wrap(r.client.Status().Update(ctx, pc), errUpdateStatus)
}

View File

@ -50,11 +50,14 @@ func (p *ProviderConfigUsageList) GetObjectKind() schema.ObjectKind {
func (p *ProviderConfigUsageList) DeepCopyObject() runtime.Object {
out := &ProviderConfigUsageList{}
j, err := json.Marshal(p) //nolint:musttag // We're just using this to round-trip convert.
if err != nil {
panic(err)
}
_ = json.Unmarshal(j, out) //nolint:musttag // We're just using this to round-trip convert.
return out
}
@ -320,8 +323,8 @@ func TestReconciler(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
r := NewReconciler(tc.args.m, tc.args.of)
got, err := r.Reconcile(context.Background(), reconcile.Request{})
got, err := r.Reconcile(context.Background(), reconcile.Request{})
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nr.Reconcile(...): -want error, +got error:\n%s", tc.reason, diff)
}

View File

@ -51,6 +51,7 @@ func FromPtrValue(v *string) string {
if v == nil {
return ""
}
return *v
}
@ -59,6 +60,7 @@ func FromFloatPtrValue(v *float64) string {
if v == nil {
return ""
}
return strconv.FormatFloat(*v, 'f', 0, 64)
}
@ -67,6 +69,7 @@ func FromIntPtrValue(v *int64) string {
if v == nil {
return ""
}
return strconv.FormatInt(*v, 10)
}
@ -75,6 +78,7 @@ func ToPtrValue(v string) *string {
if v == "" {
return nil
}
return &v
}
@ -83,10 +87,12 @@ func ToFloatPtrValue(v string) *float64 {
if v == "" {
return nil
}
vParsed, err := strconv.ParseFloat(v, 64)
if err != nil {
return nil
}
return &vParsed
}
@ -95,10 +101,12 @@ func ToIntPtrValue(v string) *int64 {
if v == "" {
return nil
}
vParsed, err := strconv.ParseInt(v, 10, 64)
if err != nil {
return nil
}
return &vParsed
}
@ -112,6 +120,7 @@ func FromPtrValues(v []*string) []string {
for i := range v {
res[i] = FromPtrValue(v[i])
}
return res
}
@ -121,6 +130,7 @@ func FromFloatPtrValues(v []*float64) []string {
for i := range v {
res[i] = FromFloatPtrValue(v[i])
}
return res
}
@ -130,6 +140,7 @@ func FromIntPtrValues(v []*int64) []string {
for i := range v {
res[i] = FromIntPtrValue(v[i])
}
return res
}
@ -143,6 +154,7 @@ func ToPtrValues(v []string) []*string {
for i := range v {
res[i] = ToPtrValue(v[i])
}
return res
}
@ -152,6 +164,7 @@ func ToFloatPtrValues(v []string) []*float64 {
for i := range v {
res[i] = ToFloatPtrValue(v[i])
}
return res
}
@ -161,6 +174,7 @@ func ToIntPtrValues(v []string) []*int64 {
for i := range v {
res[i] = ToIntPtrValue(v[i])
}
return res
}
@ -197,6 +211,7 @@ type ResolutionRequest struct {
// processed.
func (rr *ResolutionRequest) IsNoOp() bool {
isAlways := false
if rr.Selector != nil {
if rr.Selector.Policy.IsResolvePolicyAlways() {
rr.Reference = nil
@ -252,6 +267,7 @@ type MultiResolutionRequest struct {
// not be processed.
func (rr *MultiResolutionRequest) IsNoOp() bool {
isAlways := false
if rr.Selector != nil {
if rr.Selector.Policy.IsResolvePolicyAlways() {
rr.References = nil
@ -331,10 +347,12 @@ func (r *APIResolver) Resolve(ctx context.Context, req ResolutionRequest) (Resol
if kerrors.IsNotFound(err) {
return ResolutionResponse{}, getResolutionError(req.Reference.Policy, errors.Wrap(err, errGetManaged))
}
return ResolutionResponse{}, errors.Wrap(err, errGetManaged)
}
rsp := ResolutionResponse{ResolvedValue: req.Extract(req.To.Managed), ResolvedReference: req.Reference}
return rsp, getResolutionError(req.Reference.Policy, rsp.Validate())
}
@ -350,6 +368,7 @@ func (r *APIResolver) Resolve(ctx context.Context, req ResolutionRequest) (Resol
}
rsp := ResolutionResponse{ResolvedValue: req.Extract(to), ResolvedReference: &xpv1.Reference{Name: to.GetName()}}
return rsp, getResolutionError(req.Selector.Policy, rsp.Validate())
}
@ -375,14 +394,17 @@ func (r *APIResolver) ResolveMultiple(ctx context.Context, req MultiResolutionRe
if kerrors.IsNotFound(err) {
return MultiResolutionResponse{}, getResolutionError(req.References[i].Policy, errors.Wrap(err, errGetManaged))
}
return MultiResolutionResponse{}, errors.Wrap(err, errGetManaged)
}
valueMap[req.Extract(req.To.Managed)] = req.References[i]
}
sortedKeys, sortedRefs := sortMapByKeys(valueMap)
rsp := MultiResolutionResponse{ResolvedValues: sortedKeys, ResolvedReferences: sortedRefs}
return rsp, rsp.Validate()
}
@ -403,6 +425,7 @@ func (r *APIResolver) ResolveMultiple(ctx context.Context, req MultiResolutionRe
sortedKeys, sortedRefs := sortMapByKeys(valueMap)
rsp := MultiResolutionResponse{ResolvedValues: sortedKeys, ResolvedReferences: sortedRefs}
return rsp, getResolutionError(req.Selector.Policy, rsp.Validate())
}
@ -410,15 +433,18 @@ func getResolutionError(p *xpv1.Policy, err error) error {
if !p.IsResolutionPolicyOptional() {
return err
}
return nil
}
func sortMapByKeys(m map[string]xpv1.Reference) ([]string, []xpv1.Reference) {
keys := slices.Sorted(maps.Keys(m))
values := make([]xpv1.Reference, 0, len(keys))
for _, k := range keys {
values = append(values, m[k])
}
return keys, values
}
@ -429,5 +455,6 @@ func ControllersMustMatch(s *xpv1.Selector) bool {
if s == nil {
return false
}
return s.MatchControllerRef != nil && *s.MatchControllerRef
}

View File

@ -157,10 +157,12 @@ func TestResolve(t *testing.T) {
ctx context.Context
req ResolutionRequest
}
type want struct {
rsp ResolutionResponse
err error
}
cases := map[string]struct {
reason string
c client.Reader
@ -494,10 +496,12 @@ func TestResolve(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
r := NewAPIResolver(tc.c, tc.from)
got, err := r.Resolve(tc.args.ctx, tc.args.req)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nControllersMustMatch(...): -want error, +got error:\n%s", tc.reason, diff)
}
if diff := cmp.Diff(tc.want.rsp, got); diff != "" {
t.Errorf("\n%s\nControllersMustMatch(...): -want, +got:\n%s", tc.reason, diff)
}
@ -530,10 +534,12 @@ func TestResolveMultiple(t *testing.T) {
ctx context.Context
req MultiResolutionRequest
}
type want struct {
rsp MultiResolutionResponse
err error
}
cases := map[string]struct {
reason string
c client.Reader
@ -899,10 +905,12 @@ func TestResolveMultiple(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
r := NewAPIResolver(tc.c, tc.from)
got, err := r.ResolveMultiple(tc.args.ctx, tc.args.req)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nControllersMustMatch(...): -want error, +got error:\n%s", tc.reason, diff)
}
if diff := cmp.Diff(tc.want.rsp, got, cmpopts.EquateEmpty()); diff != "" {
t.Errorf("\n%s\nControllersMustMatch(...): -want, +got:\n%s", tc.reason, diff)
}

View File

@ -67,6 +67,7 @@ func (a *APIPatchingApplicator) Apply(ctx context.Context, o client.Object, ao .
// TODO(negz): Apply ApplyOptions here too?
return errors.Wrap(a.client.Create(ctx, o), "cannot create object")
}
if err != nil {
return errors.Wrap(err, "cannot get object")
}
@ -118,6 +119,7 @@ func (a *APIUpdatingApplicator) Apply(ctx context.Context, o client.Object, ao .
// TODO(negz): Apply ApplyOptions here too?
return errors.Wrap(a.client.Create(ctx, m), "cannot create object")
}
if err != nil {
return errors.Wrap(err, "cannot get object")
}
@ -131,6 +133,7 @@ func (a *APIUpdatingApplicator) Apply(ctx context.Context, o client.Object, ao .
// NOTE(hasheddan): we must set the resource version of the desired object
// to that of the current or the update will always fail.
m.SetResourceVersion(current.GetResourceVersion())
return errors.Wrap(a.client.Update(ctx, m), "cannot update object")
}
@ -163,7 +166,9 @@ func (a *APIFinalizer) AddFinalizer(ctx context.Context, obj Object) error {
if meta.FinalizerExists(obj, a.finalizer) {
return nil
}
meta.AddFinalizer(obj, a.finalizer)
return errors.Wrap(a.client.Update(ctx, obj), errUpdateObject)
}
@ -172,7 +177,9 @@ func (a *APIFinalizer) RemoveFinalizer(ctx context.Context, obj Object) error {
if !meta.FinalizerExists(obj, a.finalizer) {
return nil
}
meta.RemoveFinalizer(obj, a.finalizer)
return errors.Wrap(IgnoreNotFound(a.client.Update(ctx, obj)), errUpdateObject)
}

View File

@ -142,10 +142,12 @@ func TestAPIPatchingApplicator(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
a := NewAPIPatchingApplicator(tc.c)
err := a.Apply(tc.args.ctx, tc.args.o, tc.args.ao...)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nApply(...): -want error, +got error\n%s\n", tc.reason, diff)
}
if diff := cmp.Diff(tc.want.o, tc.args.o); diff != "" {
t.Errorf("\n%s\nApply(...): -want, +got\n%s\n", tc.reason, diff)
}
@ -157,6 +159,7 @@ func TestAPIUpdatingApplicator(t *testing.T) {
errBoom := errors.New("boom")
desired := &object{}
desired.SetName("desired")
current := &object{}
current.SetName("current")
@ -270,10 +273,12 @@ func TestAPIUpdatingApplicator(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
a := NewAPIUpdatingApplicator(tc.c)
err := a.Apply(tc.args.ctx, tc.args.o, tc.args.ao...)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nApply(...): -want error, +got error\n%s\n", tc.reason, diff)
}
if diff := cmp.Diff(tc.want.o, tc.args.o); diff != "" {
t.Errorf("\n%s\nApply(...): -want, +got\n%s\n", tc.reason, diff)
}
@ -328,10 +333,12 @@ func TestManagedRemoveFinalizer(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
api := NewAPIFinalizer(tc.client, finalizer)
err := api.RemoveFinalizer(tc.args.ctx, tc.args.obj)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Errorf("api.RemoveFinalizer(...): -want error, +got error:\n%s", diff)
}
if diff := cmp.Diff(tc.want.obj, tc.args.obj, test.EquateConditions()); diff != "" {
t.Errorf("api.RemoveFinalizer(...) Managed: -want, +got:\n%s", diff)
}
@ -386,10 +393,12 @@ func TestAPIFinalizerAdder(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
api := NewAPIFinalizer(tc.client, finalizer)
err := api.AddFinalizer(tc.args.ctx, tc.args.obj)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Errorf("api.Initialize(...): -want error, +got error:\n%s", diff)
}
if diff := cmp.Diff(tc.want.obj, tc.args.obj, test.EquateConditions()); diff != "" {
t.Errorf("api.Initialize(...) Managed: -want, +got:\n%s", diff)
}

View File

@ -315,11 +315,14 @@ func (o *Object) GetObjectKind() schema.ObjectKind {
// DeepCopyObject returns a copy of the object as runtime.Object.
func (o *Object) DeepCopyObject() runtime.Object {
out := &Object{}
j, err := json.Marshal(o)
if err != nil {
panic(err)
}
_ = json.Unmarshal(j, out)
return out
}
@ -342,11 +345,14 @@ func (m *Managed) GetObjectKind() schema.ObjectKind {
// DeepCopyObject returns a copy of the object as runtime.Object.
func (m *Managed) DeepCopyObject() runtime.Object {
out := &Managed{}
j, err := json.Marshal(m)
if err != nil {
panic(err)
}
_ = json.Unmarshal(j, out)
return out
}
@ -376,11 +382,14 @@ func (m *Composite) GetObjectKind() schema.ObjectKind {
// DeepCopyObject returns a copy of the object as runtime.Object.
func (m *Composite) DeepCopyObject() runtime.Object {
out := &Composite{}
j, err := json.Marshal(m)
if err != nil {
panic(err)
}
_ = json.Unmarshal(j, out)
return out
}
@ -400,11 +409,14 @@ func (m *Composed) GetObjectKind() schema.ObjectKind {
// DeepCopyObject returns a copy of the object as runtime.Object.
func (m *Composed) DeepCopyObject() runtime.Object {
out := &Composed{}
j, err := json.Marshal(m)
if err != nil {
panic(err)
}
_ = json.Unmarshal(j, out)
return out
}
@ -433,11 +445,14 @@ func (m *CompositeClaim) GetObjectKind() schema.ObjectKind {
// DeepCopyObject returns a copy of the object as runtime.Object.
func (m *CompositeClaim) DeepCopyObject() runtime.Object {
out := &CompositeClaim{}
j, err := json.Marshal(m)
if err != nil {
panic(err)
}
_ = json.Unmarshal(j, out)
return out
}
@ -457,6 +472,7 @@ type Manager struct {
func (m *Manager) Elected() <-chan struct{} {
e := make(chan struct{})
close(e)
return e
}
@ -490,6 +506,7 @@ func GVK(o runtime.Object) schema.GroupVersionKind {
func SchemeWith(o ...runtime.Object) *runtime.Scheme {
s := runtime.NewScheme()
s.AddKnownTypes(GV, o...)
return s
}
@ -531,11 +548,14 @@ func (m *MockConnectionSecretOwner) GetObjectKind() schema.ObjectKind {
// DeepCopyObject returns a copy of the object as runtime.Object.
func (m *MockConnectionSecretOwner) DeepCopyObject() runtime.Object {
out := &MockConnectionSecretOwner{}
j, err := json.Marshal(m)
if err != nil {
panic(err)
}
_ = json.Unmarshal(j, out)
return out
}
@ -577,11 +597,14 @@ func (m *MockLocalConnectionSecretOwner) GetObjectKind() schema.ObjectKind {
// DeepCopyObject returns a copy of the object as runtime.Object.
func (m *MockLocalConnectionSecretOwner) DeepCopyObject() runtime.Object {
out := &MockLocalConnectionSecretOwner{}
j, err := json.Marshal(m)
if err != nil {
panic(err)
}
_ = json.Unmarshal(j, out)
return out
}
@ -601,11 +624,14 @@ func (p *ProviderConfig) GetObjectKind() schema.ObjectKind {
// DeepCopyObject returns a copy of the object as runtime.Object.
func (p *ProviderConfig) DeepCopyObject() runtime.Object {
out := &ProviderConfig{}
j, err := json.Marshal(p)
if err != nil {
panic(err)
}
_ = json.Unmarshal(j, out)
return out
}
@ -626,10 +652,13 @@ func (p *ProviderConfigUsage) GetObjectKind() schema.ObjectKind {
// DeepCopyObject returns a copy of the object as runtime.Object.
func (p *ProviderConfigUsage) DeepCopyObject() runtime.Object {
out := &ProviderConfigUsage{}
j, err := json.Marshal(p)
if err != nil {
panic(err)
}
_ = json.Unmarshal(j, out)
return out
}

View File

@ -52,7 +52,9 @@ func (li *LateInitializer) LateInitializeStringPtr(org *string, from *string) *s
if org != nil || from == nil {
return org
}
li.SetChanged()
return from
}
@ -61,7 +63,9 @@ func (li *LateInitializer) LateInitializeInt64Ptr(org *int64, from *int64) *int6
if org != nil || from == nil {
return org
}
li.SetChanged()
return from
}
@ -70,7 +74,9 @@ func (li *LateInitializer) LateInitializeBoolPtr(org *bool, from *bool) *bool {
if org != nil || from == nil {
return org
}
li.SetChanged()
return from
}
@ -80,7 +86,10 @@ func (li *LateInitializer) LateInitializeTimePtr(org *metav1.Time, from *time.Ti
if org != nil || from == nil {
return org
}
li.SetChanged()
t := metav1.NewTime(*from)
return &t
}

View File

@ -27,14 +27,17 @@ import (
func TestLateInitializeStringPtr(t *testing.T) {
s1 := "desired"
s2 := "observed"
type args struct {
org *string
from *string
}
type want struct {
result *string
changed bool
}
cases := map[string]struct {
args
want
@ -74,11 +77,13 @@ func TestLateInitializeStringPtr(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
li := NewLateInitializer()
got := li.LateInitializeStringPtr(tc.org, tc.from)
if diff := cmp.Diff(tc.want.result, got); diff != "" {
if diff := cmp.Diff(tc.result, got); diff != "" {
t.Errorf("LateInitializeStringPtr(...): -want, +got:\n%s", diff)
}
if diff := cmp.Diff(tc.want.changed, li.IsChanged()); diff != "" {
if diff := cmp.Diff(tc.changed, li.IsChanged()); diff != "" {
t.Errorf("IsChanged(...): -want, +got:\n%s", diff)
}
})
@ -88,14 +93,17 @@ func TestLateInitializeStringPtr(t *testing.T) {
func TestLateInitializeInt64Ptr(t *testing.T) {
i1 := int64(10)
i2 := int64(20)
type args struct {
org *int64
from *int64
}
type want struct {
result *int64
changed bool
}
cases := map[string]struct {
args
want
@ -135,11 +143,13 @@ func TestLateInitializeInt64Ptr(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
li := NewLateInitializer()
got := li.LateInitializeInt64Ptr(tc.org, tc.from)
if diff := cmp.Diff(tc.want.result, got); diff != "" {
if diff := cmp.Diff(tc.result, got); diff != "" {
t.Errorf("LateInitializeBoolPtr(...): -want, +got:\n%s", diff)
}
if diff := cmp.Diff(tc.want.changed, li.IsChanged()); diff != "" {
if diff := cmp.Diff(tc.changed, li.IsChanged()); diff != "" {
t.Errorf("IsChanged(...): -want, +got:\n%s", diff)
}
})
@ -149,14 +159,17 @@ func TestLateInitializeInt64Ptr(t *testing.T) {
func TestLateInitializeBoolPtr(t *testing.T) {
trueVal := true
falseVal := false
type args struct {
org *bool
from *bool
}
type want struct {
result *bool
changed bool
}
cases := map[string]struct {
args
want
@ -196,11 +209,13 @@ func TestLateInitializeBoolPtr(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
li := NewLateInitializer()
got := li.LateInitializeBoolPtr(tc.org, tc.from)
if diff := cmp.Diff(tc.want.result, got); diff != "" {
if diff := cmp.Diff(tc.result, got); diff != "" {
t.Errorf("LateInitializeBoolPtr(...): -want, +got:\n%s", diff)
}
if diff := cmp.Diff(tc.want.changed, li.IsChanged()); diff != "" {
if diff := cmp.Diff(tc.changed, li.IsChanged()); diff != "" {
t.Errorf("IsChanged(...): -want, +got:\n%s", diff)
}
})
@ -211,14 +226,17 @@ func TestLateInitializeTimePtr(t *testing.T) {
t1 := metav1.Now()
t2 := time.Now().Add(time.Minute)
t2m := metav1.NewTime(t2)
type args struct {
org *metav1.Time
from *time.Time
}
type want struct {
result *metav1.Time
changed bool
}
cases := map[string]struct {
args
want
@ -258,11 +276,13 @@ func TestLateInitializeTimePtr(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
li := NewLateInitializer()
got := li.LateInitializeTimePtr(tc.org, tc.from)
if diff := cmp.Diff(tc.want.result, got); diff != "" {
if diff := cmp.Diff(tc.result, got); diff != "" {
t.Errorf("LateInitializeTimePtr(...): -want, +got:\n%s", diff)
}
if diff := cmp.Diff(tc.want.changed, li.IsChanged()); diff != "" {
if diff := cmp.Diff(tc.changed, li.IsChanged()); diff != "" {
t.Errorf("IsChanged(...): -want, +got:\n%s", diff)
}
})

View File

@ -72,6 +72,7 @@ func DesiredStateChanged() predicate.Predicate {
// being able to ignore certain annotations.
type AnnotationChangedPredicate struct {
predicate.Funcs
ignored []string
}
@ -80,6 +81,7 @@ func copyAnnotations(an map[string]string) map[string]string {
for k, v := range an {
r[k] = v
}
return r
}
@ -89,6 +91,7 @@ func (a AnnotationChangedPredicate) Update(e event.UpdateEvent) bool {
// Update event has no old object to update
return false
}
if e.ObjectNew == nil {
// Update event has no new object for update
return false

View File

@ -34,9 +34,11 @@ func TestDesiredStateChanged(t *testing.T) {
old client.Object
new client.Object
}
type want struct {
desiredStateChanged bool
}
cases := map[string]struct {
args
want
@ -142,11 +144,11 @@ func TestDesiredStateChanged(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := DesiredStateChanged().Update(event.UpdateEvent{
ObjectOld: tc.args.old,
ObjectNew: tc.args.new,
ObjectOld: tc.old,
ObjectNew: tc.new,
})
if diff := cmp.Diff(tc.want.desiredStateChanged, got); diff != "" {
if diff := cmp.Diff(tc.desiredStateChanged, got); diff != "" {
t.Errorf("DesiredStateChanged(...): -want, +got:\n%s", diff)
}
})

View File

@ -52,6 +52,7 @@ func IsMissingReference(err error) bool {
_, ok := err.(interface {
MissingReference() bool
})
return ok
}
@ -63,6 +64,7 @@ func ExtractEnv(_ context.Context, e EnvLookupFn, s xpv1.CommonCredentialSelecto
if s.Env == nil {
return nil, errors.New(errExtractEnv)
}
return []byte(e(s.Env.Name)), nil
}
@ -71,6 +73,7 @@ func ExtractFs(_ context.Context, fs afero.Fs, s xpv1.CommonCredentialSelectors)
if s.Fs == nil {
return nil, errors.New(errExtractFs)
}
return afero.ReadFile(fs, s.Fs.Path)
}
@ -79,10 +82,12 @@ func ExtractSecret(ctx context.Context, client client.Client, s xpv1.CommonCrede
if s.SecretRef == nil {
return nil, errors.New(errExtractSecretKey)
}
secret := &corev1.Secret{}
if err := client.Get(ctx, types.NamespacedName{Namespace: s.SecretRef.Namespace, Name: s.SecretRef.Name}, secret); err != nil {
return nil, errors.Wrap(err, errGetCredentialsSecret)
}
return secret.Data[s.SecretRef.Key], nil
}
@ -141,6 +146,7 @@ func (u *ProviderConfigUsageTracker) Track(ctx context.Context, mg Managed) erro
//nolint:forcetypeassert // Will always be a PCU.
pcu := u.of.DeepCopyObject().(ProviderConfigUsage)
gvk := mg.GetObjectKind().GroupVersionKind()
ref := mg.GetProviderConfigReference()
if ref == nil {
return missingRefError{errors.New(errMissingPCRef)}
@ -163,5 +169,6 @@ func (u *ProviderConfigUsageTracker) Track(ctx context.Context, mg Managed) erro
return current.(ProviderConfigUsage).GetProviderConfigReference() != pcu.GetProviderConfigReference()
}),
)
return errors.Wrap(Ignore(IsNotAllowed, err), errApplyPCU)
}

View File

@ -79,6 +79,7 @@ func TestExtractEnv(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\npc.ExtractEnv(...): -want error, +got error:\n%s\n", tc.reason, diff)
}
if diff := cmp.Diff(tc.want.b, got); diff != "" {
t.Errorf("\n%s\npc.ExtractEnv(...): -want, +got:\n%s\n", tc.reason, diff)
}
@ -138,6 +139,7 @@ func TestExtractFs(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\npc.ExtractFs(...): -want error, +got error:\n%s\n", tc.reason, diff)
}
if diff := cmp.Diff(tc.want.b, got); diff != "" {
t.Errorf("\n%s\npc.ExtractFs(...): -want, +got:\n%s\n", tc.reason, diff)
}
@ -226,6 +228,7 @@ func TestExtractSecret(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\npc.ExtractSecret(...): -want error, +got error:\n%s\n", tc.reason, diff)
}
if diff := cmp.Diff(tc.want.b, got); diff != "" {
t.Errorf("\n%s\npc.ExtractSecret(...): -want, +got:\n%s\n", tc.reason, diff)
}
@ -318,6 +321,7 @@ func TestTrack(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
ut := &ProviderConfigUsageTracker{c: tc.fields.c, of: tc.fields.of}
got := ut.Track(tc.args.ctx, tc.args.mg)
if diff := cmp.Diff(tc.want, got, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nut.Track(...): -want error, +got error:\n%s\n", tc.reason, diff)

View File

@ -128,6 +128,7 @@ func MustCreateObject(kind schema.GroupVersionKind, oc runtime.ObjectCreater) ru
if err != nil {
panic(err)
}
return obj
}
@ -139,12 +140,15 @@ func GetKind(obj runtime.Object, ot runtime.ObjectTyper) (schema.GroupVersionKin
if err != nil {
return schema.GroupVersionKind{}, errors.Wrap(err, "cannot get kind of supplied object")
}
if unversioned {
return schema.GroupVersionKind{}, errors.New("supplied object is unversioned")
}
if len(kinds) != 1 {
return schema.GroupVersionKind{}, errors.New("supplied object does not have exactly one kind")
}
return kinds[0], nil
}
@ -156,6 +160,7 @@ func MustGetKind(obj runtime.Object, ot runtime.ObjectTyper) schema.GroupVersion
if err != nil {
panic(err)
}
return gvk
}
@ -168,6 +173,7 @@ func Ignore(is ErrorIs, err error) error {
if is(err) {
return nil
}
return err
}
@ -180,6 +186,7 @@ func IgnoreAny(err error, is ...ErrorIs) error {
return nil
}
}
return err
}
@ -215,6 +222,7 @@ type shouldRetryFunc func(error) bool
// An ApplicatorWithRetry applies changes to an object, retrying on transient failures.
type ApplicatorWithRetry struct {
Applicator
shouldRetry shouldRetryFunc
backoff wait.Backoff
}
@ -285,6 +293,7 @@ func IsNotControllable(err error) bool {
_, ok := err.(interface {
NotControllable() bool
})
return ok
}
@ -299,6 +308,7 @@ func MustBeControllableBy(u types.UID) ApplyOption {
if !ok {
return notControllableError{errors.Errorf("existing object is missing object metadata")}
}
c := metav1.GetControllerOf(mo)
if c == nil {
return nil
@ -307,6 +317,7 @@ func MustBeControllableBy(u types.UID) ApplyOption {
if c.UID != u {
return notControllableError{errors.Errorf("existing object is not controlled by UID %q", u)}
}
return nil
}
}
@ -329,6 +340,7 @@ func ConnectionSecretMustBeControllableBy(u types.UID) ApplyOption {
if !ok {
return errors.New("current resource is not a Secret")
}
c := metav1.GetControllerOf(s)
switch {
@ -361,6 +373,7 @@ func IsNotAllowed(err error) bool {
_, ok := err.(interface {
NotAllowed() bool
})
return ok
}
@ -373,6 +386,7 @@ func AllowUpdateIf(fn func(current, desired runtime.Object) bool) ApplyOption {
if fn(current, desired) {
return nil
}
return notAllowedError{errors.New("update not allowed")}
}
}
@ -386,7 +400,9 @@ func StoreCurrentRV(origRV *string) ApplyOption {
if !ok {
return errors.New("current resource is missing object metadata")
}
*origRV = mo.GetResourceVersion()
return nil
}
}
@ -402,6 +418,7 @@ func GetExternalTags(mg Managed) map[string]string {
if mg.GetProviderConfigReference() != nil && mg.GetProviderConfigReference().Name != "" {
tags[ExternalResourceTagKeyProvider] = mg.GetProviderConfigReference().Name
}
return tags
}
@ -416,12 +433,15 @@ func FirstNAndSomeMore(n int, names []string) string {
if n <= 0 {
return fmt.Sprintf("%d", len(names))
}
if len(names) > n {
return fmt.Sprintf("%s, and %d more", strings.Join(names[:n], ", "), len(names)-n)
}
if len(names) == n {
return fmt.Sprintf("%s, and %s", strings.Join(names[:n-1], ", "), names[n-1])
}
return strings.Join(names, ", ")
}
@ -431,6 +451,7 @@ func StableNAndSomeMore(n int, names []string) string {
cpy := make([]string, len(names))
copy(cpy, names)
sort.Strings(cpy)
return FirstNAndSomeMore(n, cpy)
}
@ -458,5 +479,6 @@ func AsProtobufStruct(o runtime.Object) (*structpb.Struct, error) {
}
s := &structpb.Struct{}
return s, errors.Wrap(s.UnmarshalJSON(b), errUnmarshalJSON)
}

View File

@ -181,6 +181,7 @@ func TestGetKind(t *testing.T) {
obj runtime.Object
ot runtime.ObjectTyper
}
type want struct {
kind schema.GroupVersionKind
err error
@ -243,6 +244,7 @@ func TestGetKind(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Errorf("GetKind(...): -want error, +got error:\n%s", diff)
}
if diff := cmp.Diff(tc.want.kind, got); diff != "" {
t.Errorf("GetKind(...): -want, +got:\n%s", diff)
}
@ -255,6 +257,7 @@ func TestMustCreateObject(t *testing.T) {
kind schema.GroupVersionKind
oc runtime.ObjectCreater
}
cases := map[string]struct {
args args
want runtime.Object
@ -285,6 +288,7 @@ func TestIgnore(t *testing.T) {
is ErrorIs
err error
}
cases := map[string]struct {
args args
want error
@ -322,6 +326,7 @@ func TestIgnoreAny(t *testing.T) {
is []ErrorIs
err error
}
cases := map[string]struct {
args args
want error
@ -401,7 +406,7 @@ type object struct {
}
func (o *object) DeepCopyObject() runtime.Object {
return &object{ObjectMeta: *o.ObjectMeta.DeepCopy()}
return &object{ObjectMeta: *o.DeepCopy()}
}
func TestIsNotControllable(t *testing.T) {
@ -486,8 +491,8 @@ func TestMustBeControllableBy(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
ao := MustBeControllableBy(tc.u)
err := ao(tc.args.ctx, tc.args.current, tc.args.desired)
err := ao(tc.args.ctx, tc.args.current, tc.args.desired)
if diff := cmp.Diff(tc.want, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nMustBeControllableBy(...)(...): -want error, +got error\n%s\n", tc.reason, diff)
}
@ -558,8 +563,8 @@ func TestConnectionSecretMustBeControllableBy(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
ao := ConnectionSecretMustBeControllableBy(tc.u)
err := ao(tc.args.ctx, tc.args.current, tc.args.desired)
err := ao(tc.args.ctx, tc.args.current, tc.args.desired)
if diff := cmp.Diff(tc.want, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nConnectionSecretMustBeControllableBy(...)(...): -want error, +got error\n%s\n", tc.reason, diff)
}
@ -600,8 +605,8 @@ func TestAllowUpdateIf(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
ao := AllowUpdateIf(tc.fn)
err := ao(tc.args.ctx, tc.args.current, tc.args.desired)
err := ao(tc.args.ctx, tc.args.current, tc.args.desired)
if diff := cmp.Diff(tc.want, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nAllowUpdateIf(...)(...): -want error, +got error\n%s\n", tc.reason, diff)
}
@ -645,7 +650,6 @@ func Test_notControllableError_NotControllable(t *testing.T) {
err := notControllableError{
errors.New("test-error"),
}
if !err.NotControllable() {
t.Errorf("NotControllable(): false")
}
@ -656,7 +660,6 @@ func Test_notAllowedError_NotAllowed(t *testing.T) {
err := notAllowedError{
errors.New("test-error"),
}
if !err.NotAllowed() {
t.Errorf("NotAllowed(): false")
}
@ -884,6 +887,7 @@ func TestFirstNAndSomeMore(t *testing.T) {
n int
names []string
}
tests := []struct {
name string
args args

View File

@ -53,6 +53,7 @@ func New(opts ...Option) *Unstructured {
for _, f := range opts {
f(c)
}
return c
}
@ -75,6 +76,7 @@ func (c *Unstructured) GetCompositionSelector() *metav1.LabelSelector {
if err := fieldpath.Pave(c.Object).GetValueInto("spec.compositionSelector", out); err != nil {
return nil
}
return out
}
@ -89,6 +91,7 @@ func (c *Unstructured) GetCompositionReference() *corev1.ObjectReference {
if err := fieldpath.Pave(c.Object).GetValueInto("spec.compositionRef", out); err != nil {
return nil
}
return out
}
@ -103,6 +106,7 @@ func (c *Unstructured) GetCompositionRevisionReference() *corev1.LocalObjectRefe
if err := fieldpath.Pave(c.Object).GetValueInto("spec.compositionRevisionRef", out); err != nil {
return nil
}
return out
}
@ -117,6 +121,7 @@ func (c *Unstructured) GetCompositionRevisionSelector() *metav1.LabelSelector {
if err := fieldpath.Pave(c.Object).GetValueInto("spec.compositionRevisionSelector", out); err != nil {
return nil
}
return out
}
@ -136,7 +141,9 @@ func (c *Unstructured) GetCompositionUpdatePolicy() *xpv1.UpdatePolicy {
if err != nil {
return nil
}
out := xpv1.UpdatePolicy(p)
return &out
}
@ -151,7 +158,9 @@ func (c *Unstructured) GetCompositeDeletePolicy() *xpv1.CompositeDeletePolicy {
if err != nil {
return nil
}
out := xpv1.CompositeDeletePolicy(p)
return &out
}
@ -161,6 +170,7 @@ func (c *Unstructured) GetResourceReference() *reference.Composite {
if err := fieldpath.Pave(c.Object).GetValueInto("spec.resourceRef", out); err != nil {
return nil
}
return out
}
@ -185,6 +195,7 @@ func (c *Unstructured) GetWriteConnectionSecretToReference() *xpv1.LocalSecretRe
if err := fieldpath.Pave(c.Object).GetValueInto("spec.writeConnectionSecretToRef", out); err != nil {
return nil
}
return out
}
@ -200,6 +211,7 @@ func (c *Unstructured) GetCondition(ct xpv1.ConditionType) xpv1.Condition {
if err := fieldpath.Pave(c.Object).GetValueInto("status", &conditioned); err != nil {
return xpv1.Condition{}
}
return conditioned.GetCondition(ct)
}
@ -218,6 +230,7 @@ func (c *Unstructured) GetConnectionDetailsLastPublishedTime() *metav1.Time {
if err := fieldpath.Pave(c.Object).GetValueInto("status.connectionDetails.lastPublishedTime", out); err != nil {
return nil
}
return out
}
@ -238,5 +251,6 @@ func (c *Unstructured) SetObservedGeneration(generation int64) {
func (c *Unstructured) GetObservedGeneration() int64 {
status := &xpv1.ObservedStatus{}
_ = fieldpath.Pave(c.Object).GetValueInto("status", status)
return status.GetObservedGeneration()
}

View File

@ -114,6 +114,7 @@ func TestConditions(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
tc.u.SetConditions(tc.set...)
got := tc.u.GetCondition(tc.get)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("\n%s\nu.GetCondition(%s): -want, +got:\n%s", tc.reason, tc.get, diff)
@ -139,6 +140,7 @@ func TestCompositionSelector(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
tc.u.SetCompositionSelector(tc.set)
got := tc.u.GetCompositionSelector()
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("\nu.GetCompositionSelector(): -want, +got:\n%s", diff)
@ -164,6 +166,7 @@ func TestCompositionReference(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
tc.u.SetCompositionReference(tc.set)
got := tc.u.GetCompositionReference()
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("\nu.GetCompositionReference(): -want, +got:\n%s", diff)
@ -189,6 +192,7 @@ func TestCompositionRevisionReference(t *testing.T) {
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)
@ -214,6 +218,7 @@ func TestCompositionRevisionSelector(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
tc.u.SetCompositionRevisionSelector(tc.set)
got := tc.u.GetCompositionRevisionSelector()
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("\nu.GetCompositionRevisionSelector(): -want, +got:\n%s", diff)
@ -239,6 +244,7 @@ func TestCompositionUpdatePolicy(t *testing.T) {
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)
@ -264,6 +270,7 @@ func TestCompositeDeletePolicy(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
tc.u.SetCompositeDeletePolicy(tc.set)
got := tc.u.GetCompositeDeletePolicy()
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("\nu.GetCompositeDeletePolicy(): -want, +got:\n%s", diff)
@ -289,6 +296,7 @@ func TestResourceReference(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
tc.u.SetResourceReference(tc.set)
got := tc.u.GetResourceReference()
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("\nu.GetResourceReference(): -want, +got:\n%s", diff)
@ -304,6 +312,7 @@ func TestClaimReference(t *testing.T) {
u.SetNamespace(ref.Namespace)
u.SetAPIVersion(ref.APIVersion)
u.SetKind(ref.Kind)
got := u.GetReference()
if diff := cmp.Diff(ref, got); diff != "" {
t.Errorf("\nu.GetClaimReference(): -want, +got:\n%s", diff)
@ -327,6 +336,7 @@ func TestWriteConnectionSecretToReference(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
tc.u.SetWriteConnectionSecretToReference(tc.set)
got := tc.u.GetWriteConnectionSecretToReference()
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("\nu.GetWriteConnectionSecretToReference(): -want, +got:\n%s", diff)
@ -344,6 +354,7 @@ func TestConnectionDetailsLastPublishedTime(t *testing.T) {
out := &metav1.Time{}
j, _ := json.Marshal(t) //nolint:errchkjson // No encoding issue in practice.
_ = json.Unmarshal(j, out)
return out
}
@ -362,6 +373,7 @@ func TestConnectionDetailsLastPublishedTime(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
tc.u.SetConnectionDetailsLastPublishedTime(tc.set)
got := tc.u.GetConnectionDetailsLastPublishedTime()
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("\nu.GetConnectionDetailsLastPublishedTime(): -want, +got:\n%s", diff)

View File

@ -59,6 +59,7 @@ func (c *WrapperClient) Get(ctx context.Context, key client.ObjectKey, obj clien
if u, ok := obj.(Wrapper); ok {
return c.kube.Get(ctx, key, u.GetUnstructured(), opts...)
}
return c.kube.Get(ctx, key, obj, opts...)
}
@ -69,6 +70,7 @@ func (c *WrapperClient) List(ctx context.Context, list client.ObjectList, opts .
if u, ok := list.(ListWrapper); ok {
return c.kube.List(ctx, u.GetUnstructuredList(), opts...)
}
return c.kube.List(ctx, list, opts...)
}
@ -77,6 +79,7 @@ func (c *WrapperClient) Create(ctx context.Context, obj client.Object, opts ...c
if u, ok := obj.(Wrapper); ok {
return c.kube.Create(ctx, u.GetUnstructured(), opts...)
}
return c.kube.Create(ctx, obj, opts...)
}
@ -85,6 +88,7 @@ func (c *WrapperClient) Delete(ctx context.Context, obj client.Object, opts ...c
if u, ok := obj.(Wrapper); ok {
return c.kube.Delete(ctx, u.GetUnstructured(), opts...)
}
return c.kube.Delete(ctx, obj, opts...)
}
@ -94,6 +98,7 @@ func (c *WrapperClient) Update(ctx context.Context, obj client.Object, opts ...c
if u, ok := obj.(Wrapper); ok {
return c.kube.Update(ctx, u.GetUnstructured(), opts...)
}
return c.kube.Update(ctx, obj, opts...)
}
@ -103,6 +108,7 @@ func (c *WrapperClient) Patch(ctx context.Context, obj client.Object, patch clie
if u, ok := obj.(Wrapper); ok {
return c.kube.Patch(ctx, u.GetUnstructured(), patch, opts...)
}
return c.kube.Patch(ctx, obj, patch, opts...)
}
@ -111,6 +117,7 @@ func (c *WrapperClient) DeleteAllOf(ctx context.Context, obj client.Object, opts
if u, ok := obj.(Wrapper); ok {
return c.kube.DeleteAllOf(ctx, u.GetUnstructured(), opts...)
}
return c.kube.DeleteAllOf(ctx, obj, opts...)
}
@ -142,6 +149,7 @@ func (c *WrapperClient) GroupVersionKindFor(obj runtime.Object) (schema.GroupVer
if u, ok := obj.(Wrapper); ok {
return c.kube.GroupVersionKindFor(u.GetUnstructured())
}
return c.kube.GroupVersionKindFor(obj)
}
@ -150,6 +158,7 @@ func (c *WrapperClient) IsObjectNamespaced(obj runtime.Object) (bool, error) {
if u, ok := obj.(Wrapper); ok {
return c.kube.IsObjectNamespaced(u.GetUnstructured())
}
return c.kube.IsObjectNamespaced(obj)
}
@ -165,6 +174,7 @@ func (c *wrapperStatusClient) Create(ctx context.Context, obj, subResource clien
if u, ok := obj.(Wrapper); ok {
return c.kube.Create(ctx, u.GetUnstructured(), subResource, opts...)
}
return c.kube.Create(ctx, obj, subResource, opts...)
}
@ -175,6 +185,7 @@ func (c *wrapperStatusClient) Update(ctx context.Context, obj client.Object, opt
if u, ok := obj.(Wrapper); ok {
return c.kube.Update(ctx, u.GetUnstructured(), opts...)
}
return c.kube.Update(ctx, obj, opts...)
}
@ -185,5 +196,6 @@ func (c *wrapperStatusClient) Patch(ctx context.Context, obj client.Object, patc
if u, ok := obj.(Wrapper); ok {
return c.kube.Patch(ctx, u.GetUnstructured(), patch, opts...)
}
return c.kube.Patch(ctx, obj, patch, opts...)
}

View File

@ -79,6 +79,7 @@ func TestGet(t *testing.T) {
key client.ObjectKey
obj client.Object
}
cases := map[string]struct {
c client.Client
args args
@ -107,6 +108,7 @@ func TestGet(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
c := NewClient(tc.c)
got := c.Get(tc.args.ctx, tc.args.key, tc.args.obj)
if diff := cmp.Diff(tc.want, got, test.EquateErrors()); diff != "" {
t.Errorf("\nc.Get(...): -want error, +got error:\n %s", diff)
@ -120,6 +122,7 @@ func TestList(t *testing.T) {
ctx context.Context
obj client.ObjectList
}
cases := map[string]struct {
c client.Client
args args
@ -150,6 +153,7 @@ func TestList(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
c := NewClient(tc.c)
got := c.List(tc.args.ctx, tc.args.obj)
if diff := cmp.Diff(tc.want, got, test.EquateErrors()); diff != "" {
t.Errorf("\nc.List(...): -want error, +got error:\n %s", diff)
@ -163,6 +167,7 @@ func TestCreate(t *testing.T) {
ctx context.Context
obj client.Object
}
cases := map[string]struct {
c client.Client
args args
@ -191,6 +196,7 @@ func TestCreate(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
c := NewClient(tc.c)
got := c.Create(tc.args.ctx, tc.args.obj)
if diff := cmp.Diff(tc.want, got, test.EquateErrors()); diff != "" {
t.Errorf("\nc.Create(...): -want error, +got error:\n %s", diff)
@ -204,6 +210,7 @@ func TestDelete(t *testing.T) {
ctx context.Context
obj client.Object
}
cases := map[string]struct {
c client.Client
args args
@ -232,6 +239,7 @@ func TestDelete(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
c := NewClient(tc.c)
got := c.Delete(tc.args.ctx, tc.args.obj)
if diff := cmp.Diff(tc.want, got, test.EquateErrors()); diff != "" {
t.Errorf("\nc.Delete(...): -want error, +got error:\n %s", diff)
@ -245,6 +253,7 @@ func TestUpdate(t *testing.T) {
ctx context.Context
obj client.Object
}
cases := map[string]struct {
c client.Client
args args
@ -273,6 +282,7 @@ func TestUpdate(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
c := NewClient(tc.c)
got := c.Update(tc.args.ctx, tc.args.obj)
if diff := cmp.Diff(tc.want, got, test.EquateErrors()); diff != "" {
t.Errorf("\nc.Update(...): -want error, +got error:\n %s", diff)
@ -287,6 +297,7 @@ func TestPatch(t *testing.T) {
obj client.Object
patch client.Patch
}
cases := map[string]struct {
c client.Client
args args
@ -315,6 +326,7 @@ func TestPatch(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
c := NewClient(tc.c)
got := c.Patch(tc.args.ctx, tc.args.obj, tc.args.patch)
if diff := cmp.Diff(tc.want, got, test.EquateErrors()); diff != "" {
t.Errorf("\nc.Patch(...): -want error, +got error:\n %s", diff)
@ -328,6 +340,7 @@ func TestDeleteAllOf(t *testing.T) {
ctx context.Context
obj client.Object
}
cases := map[string]struct {
c client.Client
args args
@ -356,6 +369,7 @@ func TestDeleteAllOf(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
c := NewClient(tc.c)
got := c.DeleteAllOf(tc.args.ctx, tc.args.obj)
if diff := cmp.Diff(tc.want, got, test.EquateErrors()); diff != "" {
t.Errorf("\nc.DeleteAllOf(...): -want error, +got error:\n %s", diff)
@ -370,6 +384,7 @@ func TestStatusCreate(t *testing.T) {
obj client.Object
sub client.Object
}
cases := map[string]struct {
c client.Client
args args
@ -398,6 +413,7 @@ func TestStatusCreate(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
c := NewClient(tc.c)
got := c.Status().Create(tc.args.ctx, tc.args.obj, tc.args.sub)
if diff := cmp.Diff(tc.want, got, test.EquateErrors()); diff != "" {
t.Errorf("\nc.Status().Create(...): -want error, +got error:\n %s", diff)
@ -411,6 +427,7 @@ func TestStatusUpdate(t *testing.T) {
ctx context.Context
obj client.Object
}
cases := map[string]struct {
c client.Client
args args
@ -439,6 +456,7 @@ func TestStatusUpdate(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
c := NewClient(tc.c)
got := c.Status().Update(tc.args.ctx, tc.args.obj)
if diff := cmp.Diff(tc.want, got, test.EquateErrors()); diff != "" {
t.Errorf("\nc.Status().Update(...): -want error, +got error:\n %s", diff)
@ -453,6 +471,7 @@ func TestStatusPatch(t *testing.T) {
obj client.Object
patch client.Patch
}
cases := map[string]struct {
c client.Client
args args
@ -481,6 +500,7 @@ func TestStatusPatch(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
c := NewClient(tc.c)
got := c.Status().Patch(tc.args.ctx, tc.args.obj, tc.args.patch)
if diff := cmp.Diff(tc.want, got, test.EquateErrors()); diff != "" {
t.Errorf("\nc.StatusPatch(...): -want error, +got error:\n %s", diff)

View File

@ -54,6 +54,7 @@ func New(opts ...Option) *Unstructured {
for _, f := range opts {
f(cr)
}
return cr
}
@ -77,6 +78,7 @@ func (cr *Unstructured) GetCondition(ct xpv1.ConditionType) xpv1.Condition {
if err := fieldpath.Pave(cr.Object).GetValueInto("status", &conditioned); err != nil {
return xpv1.Condition{}
}
return conditioned.GetCondition(ct)
}
@ -95,6 +97,7 @@ func (cr *Unstructured) GetWriteConnectionSecretToReference() *xpv1.SecretRefere
if err := fieldpath.Pave(cr.Object).GetValueInto("spec.writeConnectionSecretToRef", out); err != nil {
return nil
}
return out
}
@ -110,6 +113,7 @@ func (cr *Unstructured) OwnedBy(u types.UID) bool {
return true
}
}
return false
}
@ -142,6 +146,7 @@ func NewList(opts ...ListOption) *UnstructuredList {
for _, f := range opts {
f(cr)
}
return cr
}
@ -167,5 +172,6 @@ func (cr *Unstructured) SetObservedGeneration(generation int64) {
func (cr *Unstructured) GetObservedGeneration() int64 {
status := &xpv1.ObservedStatus{}
_ = fieldpath.Pave(cr.Object).GetValueInto("status", status)
return status.GetObservedGeneration()
}

View File

@ -114,6 +114,7 @@ func TestConditions(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
tc.u.SetConditions(tc.set...)
got := tc.u.GetCondition(tc.get)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("\n%s\nu.GetCondition(%s): -want, +got:\n%s", tc.reason, tc.get, diff)
@ -139,6 +140,7 @@ func TestWriteConnectionSecretToReference(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
tc.u.SetWriteConnectionSecretToReference(tc.set)
got := tc.u.GetWriteConnectionSecretToReference()
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("\nu.GetWriteConnectionSecretToReference(): -want, +got:\n%s", diff)

View File

@ -76,6 +76,7 @@ func New(opts ...Option) *Unstructured {
for _, f := range opts {
f(c)
}
return c
}
@ -105,6 +106,7 @@ func (c *Unstructured) GetCompositionSelector() *metav1.LabelSelector {
if err := fieldpath.Pave(c.Object).GetValueInto(path, out); err != nil {
return nil
}
return out
}
@ -129,6 +131,7 @@ func (c *Unstructured) GetCompositionReference() *corev1.ObjectReference {
if err := fieldpath.Pave(c.Object).GetValueInto(path, out); err != nil {
return nil
}
return out
}
@ -153,6 +156,7 @@ func (c *Unstructured) GetCompositionRevisionReference() *corev1.LocalObjectRefe
if err := fieldpath.Pave(c.Object).GetValueInto(path, out); err != nil {
return nil
}
return out
}
@ -177,6 +181,7 @@ func (c *Unstructured) GetCompositionRevisionSelector() *metav1.LabelSelector {
if err := fieldpath.Pave(c.Object).GetValueInto(path, out); err != nil {
return nil
}
return out
}
@ -211,7 +216,9 @@ func (c *Unstructured) GetCompositionUpdatePolicy() *xpv1.UpdatePolicy {
if err != nil {
return nil
}
out := xpv1.UpdatePolicy(p)
return &out
}
@ -226,6 +233,7 @@ func (c *Unstructured) GetClaimReference() *reference.Claim {
if err := fieldpath.Pave(c.Object).GetValueInto("spec.claimRef", out); err != nil {
return nil
}
return out
}
@ -248,6 +256,7 @@ func (c *Unstructured) GetResourceReferences() []corev1.ObjectReference {
out := &[]corev1.ObjectReference{}
_ = fieldpath.Pave(c.Object).GetValueInto(path, out)
return *out
}
@ -259,6 +268,7 @@ func (c *Unstructured) SetResourceReferences(refs []corev1.ObjectReference) {
}
empty := corev1.ObjectReference{}
filtered := make([]corev1.ObjectReference, 0, len(refs))
for _, ref := range refs {
// TODO(negz): Ask muvaf to explain what this is working around. :)
@ -266,8 +276,10 @@ func (c *Unstructured) SetResourceReferences(refs []corev1.ObjectReference) {
if ref.String() == empty.String() {
continue
}
filtered = append(filtered, ref)
}
_ = fieldpath.Pave(c.Object).SetValue(path, filtered)
}
@ -301,6 +313,7 @@ func (c *Unstructured) GetWriteConnectionSecretToReference() *xpv1.SecretReferen
if err := fieldpath.Pave(c.Object).GetValueInto("spec.writeConnectionSecretToRef", out); err != nil {
return nil
}
return out
}
@ -321,6 +334,7 @@ func (c *Unstructured) GetCondition(ct xpv1.ConditionType) xpv1.Condition {
if err := fieldpath.Pave(c.Object).GetValueInto("status", &conditioned); err != nil {
return xpv1.Condition{}
}
return conditioned.GetCondition(ct)
}
@ -338,6 +352,7 @@ func (c *Unstructured) GetConditions() []xpv1.Condition {
conditioned := xpv1.ConditionedStatus{}
// The path is directly `status` because conditions are inline.
_ = fieldpath.Pave(c.Object).GetValueInto("status", &conditioned)
return conditioned.Conditions
}
@ -352,6 +367,7 @@ func (c *Unstructured) GetConnectionDetailsLastPublishedTime() *metav1.Time {
if err := fieldpath.Pave(c.Object).GetValueInto(path, out); err != nil {
return nil
}
return out
}
@ -377,6 +393,7 @@ func (c *Unstructured) SetObservedGeneration(generation int64) {
func (c *Unstructured) GetObservedGeneration() int64 {
status := &xpv1.ObservedStatus{}
_ = fieldpath.Pave(c.Object).GetValueInto("status", status)
return status.GetObservedGeneration()
}
@ -387,7 +404,9 @@ func (c *Unstructured) SetClaimConditionTypes(in ...xpv1.ConditionType) error {
if c.Schema != SchemaLegacy {
return nil
}
ts := c.GetClaimConditionTypes()
m := make(map[xpv1.ConditionType]bool, len(ts))
for _, t := range ts {
m[t] = true
@ -397,13 +416,17 @@ func (c *Unstructured) SetClaimConditionTypes(in ...xpv1.ConditionType) error {
if xpv1.IsSystemConditionType(t) {
return errors.Errorf("cannot set system condition %s as a claim condition", t)
}
if m[t] {
continue
}
m[t] = true
ts = append(ts, t)
}
_ = fieldpath.Pave(c.Object).SetValue("status.claimConditionTypes", ts)
return nil
}
@ -413,7 +436,9 @@ func (c *Unstructured) GetClaimConditionTypes() []xpv1.ConditionType {
if c.Schema != SchemaLegacy {
return nil
}
cs := []xpv1.ConditionType{}
_ = fieldpath.Pave(c.Object).GetValueInto("status.claimConditionTypes", &cs)
return cs
}

View File

@ -231,6 +231,7 @@ func TestCompositionSelector(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
tc.u.SetCompositionSelector(tc.set)
got := tc.u.GetCompositionSelector()
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("\nu.GetCompositionSelector(): -want, +got:\n%s", diff)
@ -256,6 +257,7 @@ func TestCompositionReference(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
tc.u.SetCompositionReference(tc.set)
got := tc.u.GetCompositionReference()
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("\nu.GetCompositionReference(): -want, +got:\n%s", diff)
@ -281,6 +283,7 @@ func TestCompositionRevisionReference(t *testing.T) {
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)
@ -306,6 +309,7 @@ func TestCompositionRevisionSelector(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
tc.u.SetCompositionRevisionSelector(tc.set)
got := tc.u.GetCompositionRevisionSelector()
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("\nu.GetCompositionRevisionSelector(): -want, +got:\n%s", diff)
@ -331,6 +335,7 @@ func TestCompositionUpdatePolicy(t *testing.T) {
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)
@ -356,6 +361,7 @@ func TestClaimReference(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
tc.u.SetClaimReference(tc.set)
got := tc.u.GetClaimReference()
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("\nu.GetClaimReference(): -want, +got:\n%s", diff)
@ -381,6 +387,7 @@ func TestResourceReferences(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
tc.u.SetResourceReferences(tc.set)
got := tc.u.GetResourceReferences()
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("\nu.GetResourceReferences(): -want, +got:\n%s", diff)
@ -406,6 +413,7 @@ func TestWriteConnectionSecretToReference(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
tc.u.SetWriteConnectionSecretToReference(tc.set)
got := tc.u.GetWriteConnectionSecretToReference()
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("\nu.GetWriteConnectionSecretToReference(): -want, +got:\n%s", diff)
@ -423,6 +431,7 @@ func TestConnectionDetailsLastPublishedTime(t *testing.T) {
out := &metav1.Time{}
j, _ := json.Marshal(t) //nolint:errchkjson // No encoding error in practice.
_ = json.Unmarshal(j, out)
return out
}
@ -441,6 +450,7 @@ func TestConnectionDetailsLastPublishedTime(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
tc.u.SetConnectionDetailsLastPublishedTime(tc.set)
got := tc.u.GetConnectionDetailsLastPublishedTime()
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("\nu.GetConnectionDetailsLastPublishedTime(): -want, +got:\n%s", diff)

View File

@ -114,6 +114,7 @@ func (r *MRStateRecorder) Record(ctx context.Context) error {
r.metrics.Exists.With(labels).Set(float64(len(mrs)))
var numReady, numSynced float64 = 0, 0
for _, o := range mrs {
if o.GetCondition(xpv1.TypeReady).Status == corev1.ConditionTrue {
numReady++
@ -133,6 +134,7 @@ func (r *MRStateRecorder) Record(ctx context.Context) error {
// Start records state of managed resources with given interval.
func (r *MRStateRecorder) Start(ctx context.Context) error {
ticker := time.NewTicker(r.interval)
for {
select {
case <-ticker.C:

View File

@ -40,6 +40,7 @@ func EquateErrors() cmp.Option {
}
av := reflect.ValueOf(a)
bv := reflect.ValueOf(b)
if av.Type() != bv.Type() {
return false

View File

@ -89,6 +89,7 @@ func NewMockGetFn(err error, ofn ...ObjectFn) MockGetFn {
return err
}
}
return err
}
}
@ -101,6 +102,7 @@ func NewMockListFn(err error, ofn ...ObjectListFn) MockListFn {
return err
}
}
return err
}
}
@ -113,6 +115,7 @@ func NewMockCreateFn(err error, ofn ...ObjectFn) MockCreateFn {
return err
}
}
return err
}
}
@ -125,6 +128,7 @@ func NewMockDeleteFn(err error, ofn ...ObjectFn) MockDeleteFn {
return err
}
}
return err
}
}
@ -137,6 +141,7 @@ func NewMockDeleteAllOfFn(err error, ofn ...ObjectFn) MockDeleteAllOfFn {
return err
}
}
return err
}
}
@ -149,6 +154,7 @@ func NewMockUpdateFn(err error, ofn ...ObjectFn) MockUpdateFn {
return err
}
}
return err
}
}
@ -161,6 +167,7 @@ func NewMockPatchFn(err error, ofn ...ObjectFn) MockPatchFn {
return err
}
}
return err
}
}
@ -173,6 +180,7 @@ func NewMockSubResourceCreateFn(err error, ofn ...ObjectFn) MockSubResourceCreat
return err
}
}
return err
}
}
@ -185,6 +193,7 @@ func NewMockSubResourceUpdateFn(err error, ofn ...ObjectFn) MockSubResourceUpdat
return err
}
}
return err
}
}
@ -197,6 +206,7 @@ func NewMockSubResourcePatchFn(err error, ofn ...ObjectFn) MockSubResourcePatchF
return err
}
}
return err
}
}
@ -216,6 +226,7 @@ func NewMockGroupVersionKindForFn(err error, gvk schema.GroupVersionKind, rofn .
return gvk, err
}
}
return gvk, err
}
}
@ -228,6 +239,7 @@ func NewMockIsObjectNamespacedFn(err error, isNamespaced bool, rofn ...RuntimeOb
return isNamespaced, err
}
}
return isNamespaced, err
}
}

View File

@ -45,6 +45,7 @@ func NewMutator(opts ...MutatorOption) *Mutator {
for _, f := range opts {
f(m)
}
return m
}
@ -62,5 +63,6 @@ func (m *Mutator) Default(ctx context.Context, obj runtime.Object) error {
return err
}
}
return nil
}

View File

@ -36,9 +36,11 @@ func TestDefault(t *testing.T) {
obj runtime.Object
fns []MutateFn
}
type want struct {
err error
}
cases := map[string]struct {
reason string
args
@ -71,8 +73,9 @@ func TestDefault(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
v := NewMutator(WithMutationFns(tc.fns...))
err := v.Default(context.TODO(), tc.args.obj)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
err := v.Default(context.TODO(), tc.obj)
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nDefault(...): -want, +got\n%s\n", tc.reason, diff)
}
})

View File

@ -69,6 +69,7 @@ func NewValidator(opts ...ValidatorOption) *Validator {
for _, f := range opts {
f(vc)
}
return vc
}
@ -82,38 +83,47 @@ type Validator struct {
// ValidateCreate runs functions in creation chain in order.
func (vc *Validator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
warnings := []string{}
for _, f := range vc.CreationChain {
warns, err := f(ctx, obj)
if err != nil {
return append(warnings, warns...), err
}
warnings = append(warnings, warns...)
}
return warnings, nil
}
// ValidateUpdate runs functions in update chain in order.
func (vc *Validator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
warnings := []string{}
for _, f := range vc.UpdateChain {
warns, err := f(ctx, oldObj, newObj)
if err != nil {
return append(warnings, warns...), err
}
warnings = append(warnings, warns...)
}
return warnings, nil
}
// ValidateDelete runs functions in deletion chain in order.
func (vc *Validator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
warnings := []string{}
for _, f := range vc.DeletionChain {
warns, err := f(ctx, obj)
if err != nil {
return append(warnings, warns...), err
}
warnings = append(warnings, warns...)
}
return warnings, nil
}

View File

@ -44,10 +44,12 @@ func TestValidateCreate(t *testing.T) {
obj runtime.Object
fns []ValidateCreateFn
}
type want struct {
err error
warnings admission.Warnings
}
cases := map[string]struct {
reason string
args
@ -107,11 +109,13 @@ func TestValidateCreate(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
v := NewValidator(WithValidateCreationFns(tc.fns...))
warn, err := v.ValidateCreate(context.TODO(), tc.args.obj)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
warn, err := v.ValidateCreate(context.TODO(), tc.obj)
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nValidateCreate(...): -want error, +got error\n%s\n", tc.reason, diff)
}
if diff := cmp.Diff(tc.want.warnings, warn, cmpopts.EquateEmpty()); diff != "" {
if diff := cmp.Diff(tc.warnings, warn, cmpopts.EquateEmpty()); diff != "" {
t.Errorf("\n%s\nValidateCreate(...): -want warnings, +got warnings\n%s\n", tc.reason, diff)
}
})
@ -124,10 +128,12 @@ func TestValidateUpdate(t *testing.T) {
newObj runtime.Object
fns []ValidateUpdateFn
}
type want struct {
err error
warnings admission.Warnings
}
cases := map[string]struct {
reason string
args
@ -187,11 +193,13 @@ func TestValidateUpdate(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
v := NewValidator(WithValidateUpdateFns(tc.fns...))
warn, err := v.ValidateUpdate(context.TODO(), tc.args.oldObj, tc.args.newObj)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
warn, err := v.ValidateUpdate(context.TODO(), tc.oldObj, tc.newObj)
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nValidateUpdate(...): -want error, +got error\n%s\n", tc.reason, diff)
}
if diff := cmp.Diff(tc.want.warnings, warn, cmpopts.EquateEmpty()); diff != "" {
if diff := cmp.Diff(tc.warnings, warn, cmpopts.EquateEmpty()); diff != "" {
t.Errorf("\n%s\nValidateUpdate(...): -want warnings, +got warnings\n%s\n", tc.reason, diff)
}
})
@ -203,10 +211,12 @@ func TestValidateDelete(t *testing.T) {
obj runtime.Object
fns []ValidateDeleteFn
}
type want struct {
err error
warnings admission.Warnings
}
cases := map[string]struct {
reason string
args
@ -266,11 +276,13 @@ func TestValidateDelete(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
v := NewValidator(WithValidateDeletionFns(tc.fns...))
warn, err := v.ValidateDelete(context.TODO(), tc.args.obj)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
warn, err := v.ValidateDelete(context.TODO(), tc.obj)
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nValidateDelete(...): -want error, +got error\n%s\n", tc.reason, diff)
}
if diff := cmp.Diff(tc.want.warnings, warn, cmpopts.EquateEmpty()); diff != "" {
if diff := cmp.Diff(tc.warnings, warn, cmpopts.EquateEmpty()); diff != "" {
t.Errorf("\n%s\nValidateDelete(...): -want warnings, +got warnings\n%s\n", tc.reason, diff)
}
})