Compare commits
34 Commits
v1.20.0-rc
...
main
Author | SHA1 | Date |
---|---|---|
|
0d81d3f7c2 | |
|
794eae126b | |
|
2b288ff362 | |
|
0063d2988c | |
|
dd27392560 | |
|
28c1851bf5 | |
|
6120cd37b6 | |
|
27a394364d | |
|
d48e582450 | |
|
fcbcd1a315 | |
|
43879203d3 | |
|
27adbc5d9e | |
|
e41983dddc | |
|
739f7236b8 | |
|
da72350d65 | |
|
334eed1791 | |
|
386b31235c | |
|
604c58f9eb | |
|
fb7b837275 | |
|
532a1c432f | |
|
15b6a5540c | |
|
fa083bc2b6 | |
|
0002011004 | |
|
c3c1a2262b | |
|
0812f329d5 | |
|
3178304167 | |
|
54effc73f9 | |
|
dd5c50cbf1 | |
|
bbe80d8327 | |
|
6ac64baa77 | |
|
0c53fc3e34 | |
|
daf7264750 | |
|
521fee3cbb | |
|
a123ea42e5 |
|
@ -14,9 +14,9 @@
|
|||
// PLEASE UPDATE THIS WHEN RELEASING.
|
||||
"baseBranches": [
|
||||
'main',
|
||||
'release-1.17',
|
||||
'release-1.18',
|
||||
'release-1.19',
|
||||
'release-1.20',
|
||||
],
|
||||
"ignorePaths": [
|
||||
"design/**",
|
||||
|
|
|
@ -33,13 +33,13 @@ jobs:
|
|||
|
||||
- name: Get token
|
||||
id: get-github-app-token
|
||||
uses: actions/create-github-app-token@67e27a7eb7db372a1c61a7f9bdab8699e9ee57f7 # v1
|
||||
uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1
|
||||
with:
|
||||
app-id: ${{ secrets.RENOVATE_GITHUB_APP_ID }}
|
||||
private-key: ${{ secrets.RENOVATE_GITHUB_APP_PRIVATE_KEY }}
|
||||
|
||||
- name: Self-hosted Renovate
|
||||
uses: renovatebot/github-action@063e0c946b9c1af35ef3450efc44114925d6e8e6 # v40.1.11
|
||||
uses: renovatebot/github-action@0984fb80fc633b17e57f3e8b6c007fe0dc3e0d62 # v40.3.6
|
||||
env:
|
||||
RENOVATE_REPOSITORIES: ${{ github.repository }}
|
||||
# Use GitHub API to create commits
|
||||
|
|
6
go.mod
6
go.mod
|
@ -8,7 +8,7 @@ require (
|
|||
dario.cat/mergo v1.0.1
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible
|
||||
github.com/go-logr/logr v1.4.2
|
||||
github.com/google/go-cmp v0.6.0
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/prometheus/client_golang v1.19.1
|
||||
github.com/spf13/afero v1.11.0
|
||||
golang.org/x/time v0.5.0
|
||||
|
@ -61,8 +61,8 @@ require (
|
|||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.55.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/spf13/cobra v1.8.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/cobra v1.9.1 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||
|
|
14
go.sum
14
go.sum
|
@ -6,7 +6,7 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM
|
|||
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
@ -48,8 +48,8 @@ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6
|
|||
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
|
||||
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
|
@ -114,10 +114,10 @@ github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99
|
|||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
|
|
|
@ -87,7 +87,7 @@ func NewAPIRecorder(r record.EventRecorder) *APIRecorder {
|
|||
|
||||
// Event records the supplied event.
|
||||
func (r *APIRecorder) Event(obj runtime.Object, e Event) {
|
||||
r.kube.AnnotatedEventf(obj, r.annotations, string(e.Type), string(e.Reason), e.Message)
|
||||
r.kube.AnnotatedEventf(obj, r.annotations, string(e.Type), string(e.Reason), "%s", e.Message)
|
||||
}
|
||||
|
||||
// WithAnnotations returns a new *APIRecorder that includes the supplied
|
||||
|
|
|
@ -229,76 +229,67 @@ func (m ReferenceResolverFn) ResolveReferences(ctx context.Context, mg resource.
|
|||
return m(ctx, mg)
|
||||
}
|
||||
|
||||
// An ExternalConnecter produces a new ExternalClient given the supplied
|
||||
// An ExternalConnector produces a new ExternalClient given the supplied
|
||||
// Managed resource.
|
||||
type ExternalConnecter = TypedExternalConnecter[resource.Managed]
|
||||
type ExternalConnector = TypedExternalConnector[resource.Managed]
|
||||
|
||||
// A TypedExternalConnecter produces a new ExternalClient given the supplied
|
||||
// A TypedExternalConnector produces a new ExternalClient given the supplied
|
||||
// Managed resource.
|
||||
type TypedExternalConnecter[managed resource.Managed] interface {
|
||||
type TypedExternalConnector[managed resource.Managed] interface {
|
||||
// Connect to the provider specified by the supplied managed resource and
|
||||
// produce an ExternalClient.
|
||||
Connect(ctx context.Context, mg managed) (TypedExternalClient[managed], error)
|
||||
}
|
||||
|
||||
// An ExternalDisconnecter disconnects from a provider.
|
||||
//
|
||||
// Deprecated: Please use Disconnect() on the ExternalClient for disconnecting
|
||||
// from the provider.
|
||||
type ExternalDisconnecter interface {
|
||||
// Disconnect from the provider and close the ExternalClient.
|
||||
Disconnect(ctx context.Context) error
|
||||
// A NopDisconnector converts an ExternalConnector into an
|
||||
// ExternalConnectDisconnector with a no-op Disconnect method.
|
||||
type NopDisconnector = TypedNopDisconnector[resource.Managed]
|
||||
|
||||
// A TypedNopDisconnector converts an ExternalConnector into an
|
||||
// ExternalConnectDisconnector with a no-op Disconnect method.
|
||||
type TypedNopDisconnector[managed resource.Managed] struct {
|
||||
c TypedExternalConnector[managed]
|
||||
}
|
||||
|
||||
// A NopDisconnecter converts an ExternalConnecter into an
|
||||
// ExternalConnectDisconnecter with a no-op Disconnect method.
|
||||
type NopDisconnecter = TypedNopDisconnecter[resource.Managed]
|
||||
|
||||
// A TypedNopDisconnecter converts an ExternalConnecter into an
|
||||
// ExternalConnectDisconnecter with a no-op Disconnect method.
|
||||
type TypedNopDisconnecter[managed resource.Managed] struct {
|
||||
c TypedExternalConnecter[managed]
|
||||
}
|
||||
|
||||
// Connect calls the underlying ExternalConnecter's Connect method.
|
||||
func (c *TypedNopDisconnecter[managed]) Connect(ctx context.Context, mg managed) (TypedExternalClient[managed], error) {
|
||||
// Connect calls the underlying ExternalConnector's Connect method.
|
||||
func (c *TypedNopDisconnector[managed]) Connect(ctx context.Context, mg managed) (TypedExternalClient[managed], error) {
|
||||
return c.c.Connect(ctx, mg)
|
||||
}
|
||||
|
||||
// Disconnect does nothing. It never returns an error.
|
||||
func (c *TypedNopDisconnecter[managed]) Disconnect(_ context.Context) error {
|
||||
func (c *TypedNopDisconnector[managed]) Disconnect(_ context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewNopDisconnecter converts an ExternalConnecter into an
|
||||
// ExternalConnectDisconnecter with a no-op Disconnect method.
|
||||
func NewNopDisconnecter(c ExternalConnecter) ExternalConnectDisconnecter {
|
||||
return NewTypedNopDisconnecter(c)
|
||||
// NewNopDisconnector converts an ExternalConnector into an
|
||||
// ExternalConnectDisconnector with a no-op Disconnect method.
|
||||
func NewNopDisconnector(c ExternalConnector) ExternalConnectDisconnector {
|
||||
return NewTypedNopDisconnector(c)
|
||||
}
|
||||
|
||||
// NewTypedNopDisconnecter converts an TypedExternalConnecter into an
|
||||
// ExternalConnectDisconnecter with a no-op Disconnect method.
|
||||
func NewTypedNopDisconnecter[managed resource.Managed](c TypedExternalConnecter[managed]) TypedExternalConnectDisconnecter[managed] {
|
||||
return &TypedNopDisconnecter[managed]{c}
|
||||
// NewTypedNopDisconnector converts an TypedExternalConnector into an
|
||||
// ExternalConnectDisconnector with a no-op Disconnect method.
|
||||
func NewTypedNopDisconnector[managed resource.Managed](c TypedExternalConnector[managed]) TypedExternalConnectDisconnector[managed] {
|
||||
return &TypedNopDisconnector[managed]{c}
|
||||
}
|
||||
|
||||
// An ExternalConnectDisconnecter produces a new ExternalClient given the supplied
|
||||
// An ExternalConnectDisconnector produces a new ExternalClient given the supplied
|
||||
// Managed resource.
|
||||
type ExternalConnectDisconnecter = TypedExternalConnectDisconnecter[resource.Managed]
|
||||
type ExternalConnectDisconnector = TypedExternalConnectDisconnector[resource.Managed]
|
||||
|
||||
// A TypedExternalConnectDisconnecter produces a new ExternalClient given the supplied
|
||||
// A TypedExternalConnectDisconnector produces a new ExternalClient given the supplied
|
||||
// Managed resource.
|
||||
type TypedExternalConnectDisconnecter[managed resource.Managed] interface {
|
||||
TypedExternalConnecter[managed]
|
||||
ExternalDisconnecter
|
||||
type TypedExternalConnectDisconnector[managed resource.Managed] interface {
|
||||
TypedExternalConnector[managed]
|
||||
ExternalDisconnector
|
||||
}
|
||||
|
||||
// An ExternalConnectorFn is a function that satisfies the ExternalConnecter
|
||||
// An ExternalConnectorFn is a function that satisfies the ExternalConnector
|
||||
// interface.
|
||||
type ExternalConnectorFn = TypedExternalConnectorFn[resource.Managed]
|
||||
|
||||
// An TypedExternalConnectorFn is a function that satisfies the
|
||||
// TypedExternalConnecter interface.
|
||||
// TypedExternalConnector interface.
|
||||
type TypedExternalConnectorFn[managed resource.Managed] func(ctx context.Context, mg managed) (TypedExternalClient[managed], error)
|
||||
|
||||
// Connect to the provider specified by the supplied managed resource and
|
||||
|
@ -307,7 +298,7 @@ func (ec TypedExternalConnectorFn[managed]) Connect(ctx context.Context, mg mana
|
|||
return ec(ctx, mg)
|
||||
}
|
||||
|
||||
// An ExternalDisconnectorFn is a function that satisfies the ExternalConnecter
|
||||
// An ExternalDisconnectorFn is a function that satisfies the ExternalConnector
|
||||
// interface.
|
||||
type ExternalDisconnectorFn func(ctx context.Context) error
|
||||
|
||||
|
@ -316,25 +307,25 @@ func (ed ExternalDisconnectorFn) Disconnect(ctx context.Context) error {
|
|||
return ed(ctx)
|
||||
}
|
||||
|
||||
// ExternalConnectDisconnecterFns are functions that satisfy the
|
||||
// ExternalConnectDisconnecter interface.
|
||||
type ExternalConnectDisconnecterFns = TypedExternalConnectDisconnecterFns[resource.Managed]
|
||||
// ExternalConnectDisconnectorFns are functions that satisfy the
|
||||
// ExternalConnectDisconnector interface.
|
||||
type ExternalConnectDisconnectorFns = TypedExternalConnectDisconnectorFns[resource.Managed]
|
||||
|
||||
// TypedExternalConnectDisconnecterFns are functions that satisfy the
|
||||
// TypedExternalConnectDisconnecter interface.
|
||||
type TypedExternalConnectDisconnecterFns[managed resource.Managed] struct {
|
||||
// TypedExternalConnectDisconnectorFns are functions that satisfy the
|
||||
// TypedExternalConnectDisconnector interface.
|
||||
type TypedExternalConnectDisconnectorFns[managed resource.Managed] struct {
|
||||
ConnectFn func(ctx context.Context, mg managed) (TypedExternalClient[managed], error)
|
||||
DisconnectFn func(ctx context.Context) error
|
||||
}
|
||||
|
||||
// Connect to the provider specified by the supplied managed resource and
|
||||
// produce an ExternalClient.
|
||||
func (fns TypedExternalConnectDisconnecterFns[managed]) Connect(ctx context.Context, mg managed) (TypedExternalClient[managed], error) {
|
||||
func (fns TypedExternalConnectDisconnectorFns[managed]) Connect(ctx context.Context, mg managed) (TypedExternalClient[managed], error) {
|
||||
return fns.ConnectFn(ctx, mg)
|
||||
}
|
||||
|
||||
// Disconnect from the provider and close the ExternalClient.
|
||||
func (fns TypedExternalConnectDisconnecterFns[managed]) Disconnect(ctx context.Context) error {
|
||||
func (fns TypedExternalConnectDisconnectorFns[managed]) Disconnect(ctx context.Context) error {
|
||||
return fns.DisconnectFn(ctx)
|
||||
}
|
||||
|
||||
|
@ -425,11 +416,11 @@ func (e TypedExternalClientFns[managed]) Disconnect(ctx context.Context) error {
|
|||
return e.DisconnectFn(ctx)
|
||||
}
|
||||
|
||||
// A NopConnecter does nothing.
|
||||
type NopConnecter struct{}
|
||||
// A NopConnector does nothing.
|
||||
type NopConnector struct{}
|
||||
|
||||
// Connect returns a NopClient. It never returns an error.
|
||||
func (c *NopConnecter) Connect(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
func (c *NopConnector) Connect(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
return &NopClient{}, nil
|
||||
}
|
||||
|
||||
|
@ -567,10 +558,11 @@ type Reconciler struct {
|
|||
|
||||
supportedManagementPolicies []sets.Set[xpv1.ManagementAction]
|
||||
|
||||
log logging.Logger
|
||||
record event.Recorder
|
||||
metricRecorder MetricRecorder
|
||||
change ChangeLogger
|
||||
log logging.Logger
|
||||
record event.Recorder
|
||||
metricRecorder MetricRecorder
|
||||
change ChangeLogger
|
||||
deterministicExternalName bool
|
||||
}
|
||||
|
||||
type mrManaged struct {
|
||||
|
@ -595,12 +587,12 @@ func defaultMRManaged(m manager.Manager) mrManaged {
|
|||
}
|
||||
|
||||
type mrExternal struct {
|
||||
ExternalConnectDisconnecter
|
||||
ExternalConnectDisconnector
|
||||
}
|
||||
|
||||
func defaultMRExternal() mrExternal {
|
||||
return mrExternal{
|
||||
ExternalConnectDisconnecter: NewNopDisconnecter(&NopConnecter{}),
|
||||
ExternalConnectDisconnector: NewNopDisconnector(&NopConnector{}),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -676,44 +668,24 @@ func WithCreationGracePeriod(d time.Duration) ReconcilerOption {
|
|||
}
|
||||
}
|
||||
|
||||
// WithExternalConnecter specifies how the Reconciler should connect to the API
|
||||
// WithExternalConnector specifies how the Reconciler should connect to the API
|
||||
// used to sync and delete external resources.
|
||||
func WithExternalConnecter(c ExternalConnecter) ReconcilerOption {
|
||||
func WithExternalConnector(c ExternalConnector) ReconcilerOption {
|
||||
return func(r *Reconciler) {
|
||||
r.external.ExternalConnectDisconnecter = NewNopDisconnecter(c)
|
||||
r.external.ExternalConnectDisconnector = NewNopDisconnector(c)
|
||||
}
|
||||
}
|
||||
|
||||
// WithTypedExternalConnector specifies how the Reconciler should connect to the API
|
||||
// used to sync and delete external resources.
|
||||
func WithTypedExternalConnector[managed resource.Managed](c TypedExternalConnecter[managed]) ReconcilerOption {
|
||||
func WithTypedExternalConnector[managed resource.Managed](c TypedExternalConnector[managed]) ReconcilerOption {
|
||||
return func(r *Reconciler) {
|
||||
r.external.ExternalConnectDisconnecter = &typedExternalConnectDisconnecterWrapper[managed]{
|
||||
c: NewTypedNopDisconnecter(c),
|
||||
r.external.ExternalConnectDisconnector = &typedExternalConnectDisconnectorWrapper[managed]{
|
||||
c: NewTypedNopDisconnector(c),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithExternalConnectDisconnecter specifies how the Reconciler should connect and disconnect to the API
|
||||
// used to sync and delete external resources.
|
||||
//
|
||||
// Deprecated: Please use Disconnect() on the ExternalClient for disconnecting from the provider.
|
||||
func WithExternalConnectDisconnecter(c ExternalConnectDisconnecter) ReconcilerOption {
|
||||
return func(r *Reconciler) {
|
||||
r.external.ExternalConnectDisconnecter = c
|
||||
}
|
||||
}
|
||||
|
||||
// WithTypedExternalConnectDisconnecter specifies how the Reconciler should connect and disconnect to the API
|
||||
// used to sync and delete external resources.
|
||||
//
|
||||
// Deprecated: Please use Disconnect() on the ExternalClient for disconnecting from the provider.
|
||||
func WithTypedExternalConnectDisconnecter[managed resource.Managed](c TypedExternalConnectDisconnecter[managed]) ReconcilerOption {
|
||||
return func(r *Reconciler) {
|
||||
r.external.ExternalConnectDisconnecter = &typedExternalConnectDisconnecterWrapper[managed]{c}
|
||||
}
|
||||
}
|
||||
|
||||
// WithCriticalAnnotationUpdater specifies how the Reconciler should update a
|
||||
// managed resource's critical annotations. Implementations typically contain
|
||||
// some kind of retry logic to increase the likelihood that critical annotations
|
||||
|
@ -793,6 +765,19 @@ func WithChangeLogger(c ChangeLogger) ReconcilerOption {
|
|||
}
|
||||
}
|
||||
|
||||
// WithDeterministicExternalName specifies that the external name of the MR is
|
||||
// deterministic. If this value is not "true", the provider will not re-queue the
|
||||
// managed resource in scenarios where creation is deemed incomplete. This behaviour
|
||||
// is a safeguard to avoid a leaked resource due to a non-deterministic name generated
|
||||
// by the external system. Conversely, if this value is "true", signifying that the
|
||||
// managed resources is deterministically named by the external system, then this
|
||||
// safeguard is ignored as it is safe to re-queue a deterministically named resource.
|
||||
func WithDeterministicExternalName(b bool) ReconcilerOption {
|
||||
return func(r *Reconciler) {
|
||||
r.deterministicExternalName = b
|
||||
}
|
||||
}
|
||||
|
||||
// NewReconciler returns a Reconciler that reconciles managed resources of the
|
||||
// supplied ManagedKind with resources in an external system such as a cloud
|
||||
// provider API. It panics if asked to reconcile a managed resource kind that is
|
||||
|
@ -970,13 +955,17 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
|
||||
// If we started but never completed creation of an external resource we
|
||||
// may have lost critical information. For example if we didn't persist
|
||||
// an updated external name we've leaked a resource. The safest thing to
|
||||
// do is to refuse to proceed.
|
||||
// an updated external name which is non-deterministic, we have leaked a
|
||||
// resource. The safest thing to do is to refuse to proceed. However, if
|
||||
// the resource has a deterministic external name, it is safe to proceed.
|
||||
if meta.ExternalCreateIncomplete(managed) {
|
||||
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)
|
||||
if !r.deterministicExternalName {
|
||||
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")
|
||||
}
|
||||
|
||||
// We resolve any references before observing our external resource because
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
Copyright 2025 The Crossplane Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package managed
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
)
|
||||
|
||||
// ExternalConnecter an alias to ExternalConnector.
|
||||
// Deprecated: use ExternalConnector.
|
||||
type ExternalConnecter = ExternalConnector
|
||||
|
||||
// TypedExternalConnecter an alias to TypedExternalConnector.
|
||||
// Deprecated: use TypedExternalConnector.
|
||||
type TypedExternalConnecter[managed resource.Managed] interface {
|
||||
TypedExternalConnector[managed]
|
||||
}
|
||||
|
||||
// An ExternalDisconnector disconnects from a provider.
|
||||
//
|
||||
// Deprecated: Please use Disconnect() on the ExternalClient for disconnecting
|
||||
// from the provider.
|
||||
//
|
||||
//nolint:iface // We know it is a redundant interface.
|
||||
type ExternalDisconnector interface {
|
||||
// Disconnect from the provider and close the ExternalClient.
|
||||
Disconnect(ctx context.Context) error
|
||||
}
|
||||
|
||||
// ExternalDisconnecter an alias to ExternalDisconnector.
|
||||
//
|
||||
// Deprecated: Please use Disconnect() on the ExternalClient for disconnecting
|
||||
// from the provider.
|
||||
//
|
||||
//nolint:iface // We know it is a redundant interface
|
||||
type ExternalDisconnecter interface {
|
||||
ExternalDisconnector
|
||||
}
|
||||
|
||||
// NopDisconnecter aliases NopDisconnector.
|
||||
// Deprecated: Use NopDisconnector.
|
||||
type NopDisconnecter = NopDisconnector
|
||||
|
||||
// TODO: these types of aliases are only allowed in Go 1.23 and above.
|
||||
// type TypedNopDisconnecter[managed resource.Managed] = TypedNopDisconnector[managed]
|
||||
// type TypedNopDisconnecter[managed resource.Managed] = TypedNopDisconnector[managed]
|
||||
// type TypedExternalConnectDisconnecterFns[managed resource.Managed] = TypedExternalConnectDisconnectorFns[managed]
|
||||
|
||||
// NewNopDisconnecter an alias to NewNopDisconnector.
|
||||
// Deprecated: use NewNopDisconnector.
|
||||
func NewNopDisconnecter(c ExternalConnector) ExternalConnectDisconnector {
|
||||
return NewNopDisconnector(c)
|
||||
}
|
||||
|
||||
// ExternalDisconnecterFn aliases ExternalDisconnectorFn.
|
||||
// Deprecated: use ExternalDisconnectorFn.
|
||||
type ExternalDisconnecterFn = ExternalDisconnectorFn
|
||||
|
||||
// ExternalConnectDisconnecterFns aliases ExternalConnectDisconnectorFns.
|
||||
// Deprecated: use ExternalConnectDisconnectorFns.
|
||||
type ExternalConnectDisconnecterFns = ExternalConnectDisconnectorFns
|
||||
|
||||
// NopConnecter aliases NopConnector.
|
||||
// Deprecated: use NopConnector.
|
||||
type NopConnecter = NopConnector
|
||||
|
||||
// WithExternalConnecter aliases WithExternalConnector.
|
||||
// Deprecated: use WithExternalConnector.
|
||||
func WithExternalConnecter(c ExternalConnector) ReconcilerOption {
|
||||
return WithExternalConnector(c)
|
||||
}
|
||||
|
||||
// WithExternalConnectDisconnector specifies how the Reconciler should connect and disconnect to the API
|
||||
// used to sync and delete external resources.
|
||||
//
|
||||
// Deprecated: Please use Disconnect() on the ExternalClient for disconnecting from the provider.
|
||||
func WithExternalConnectDisconnector(c ExternalConnectDisconnector) ReconcilerOption {
|
||||
return func(r *Reconciler) {
|
||||
r.external.ExternalConnectDisconnector = c
|
||||
}
|
||||
}
|
||||
|
||||
// WithExternalConnectDisconnecter aliases WithExternalConnectDisconnector.
|
||||
// Deprecated: Please use Disconnect() on the ExternalClient for disconnecting from the provider.
|
||||
func WithExternalConnectDisconnecter(c ExternalConnectDisconnector) ReconcilerOption {
|
||||
return func(r *Reconciler) {
|
||||
r.external.ExternalConnectDisconnector = c
|
||||
}
|
||||
}
|
||||
|
||||
// WithTypedExternalConnectDisconnector specifies how the Reconciler should connect and disconnect to the API
|
||||
// used to sync and delete external resources.
|
||||
//
|
||||
// Deprecated: Please use Disconnect() on the ExternalClient for disconnecting from the provider.
|
||||
func WithTypedExternalConnectDisconnector[managed resource.Managed](c TypedExternalConnectDisconnector[managed]) ReconcilerOption {
|
||||
return func(r *Reconciler) {
|
||||
r.external.ExternalConnectDisconnector = &typedExternalConnectDisconnectorWrapper[managed]{c}
|
||||
}
|
||||
}
|
||||
|
||||
// WithTypedExternalConnectDisconnecter aliases WithTypedExternalConnectDisconnector.
|
||||
// Deprecated: Please use Disconnect() on the ExternalClient for disconnecting from the provider.
|
||||
func WithTypedExternalConnectDisconnecter[managed resource.Managed](c TypedExternalConnectDisconnector[managed]) ReconcilerOption {
|
||||
return func(r *Reconciler) {
|
||||
r.external.ExternalConnectDisconnector = &typedExternalConnectDisconnectorWrapper[managed]{c}
|
||||
}
|
||||
}
|
|
@ -285,7 +285,7 @@ func TestReconciler(t *testing.T) {
|
|||
mg: resource.ManagedKind(fake.GVK(&fake.Managed{})),
|
||||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
return nil, errBoom
|
||||
})),
|
||||
},
|
||||
|
@ -314,7 +314,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: true, ResourceUpToDate: true}, nil
|
||||
|
@ -352,7 +352,7 @@ func TestReconciler(t *testing.T) {
|
|||
mg: resource.ManagedKind(fake.GVK(&fake.Managed{})),
|
||||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{}, errBoom
|
||||
|
@ -383,7 +383,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithCreationGracePeriod(1 * time.Minute),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: false}, nil
|
||||
|
@ -428,7 +428,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: true}, nil
|
||||
|
@ -476,7 +476,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: true}, nil
|
||||
|
@ -524,7 +524,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: false}, nil
|
||||
|
@ -572,7 +572,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: false}, nil
|
||||
|
@ -607,7 +607,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: false}, nil
|
||||
|
@ -646,7 +646,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(&NopConnecter{}),
|
||||
WithExternalConnector(&NopConnector{}),
|
||||
WithConnectionPublishers(ConnectionPublisherFns{
|
||||
PublishConnectionFn: func(_ context.Context, _ resource.ConnectionSecretOwner, _ ConnectionDetails) (bool, error) {
|
||||
return false, errBoom
|
||||
|
@ -678,7 +678,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(&NopConnecter{}),
|
||||
WithExternalConnector(&NopConnector{}),
|
||||
WithConnectionPublishers(),
|
||||
WithFinalizer(resource.FinalizerFns{AddFinalizerFn: func(_ context.Context, _ resource.Object) error { return errBoom }}),
|
||||
},
|
||||
|
@ -711,7 +711,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: false}, nil
|
||||
|
@ -757,7 +757,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: false}, nil
|
||||
|
@ -806,7 +806,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: false}, nil
|
||||
|
@ -852,7 +852,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: false}, nil
|
||||
|
@ -910,7 +910,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(&NopConnecter{}),
|
||||
WithExternalConnector(&NopConnector{}),
|
||||
WithCriticalAnnotationUpdater(CriticalAnnotationUpdateFn(func(_ context.Context, _ client.Object) error { return nil })),
|
||||
WithConnectionPublishers(),
|
||||
WithFinalizer(resource.FinalizerFns{AddFinalizerFn: func(_ context.Context, _ resource.Object) error { return nil }}),
|
||||
|
@ -918,6 +918,45 @@ func TestReconciler(t *testing.T) {
|
|||
},
|
||||
want: want{result: reconcile.Result{Requeue: true}},
|
||||
},
|
||||
"CreateSuccessfulAfterExternalCreatePendingAndDeterministicName": {
|
||||
reason: "Successful managed resource creation which was previously pending and has a deterministic external name should trigger a requeue after a short wait.",
|
||||
args: args{
|
||||
m: &fake.Manager{
|
||||
Client: &test.MockClient{
|
||||
MockGet: test.NewMockGetFn(nil, func(obj client.Object) error {
|
||||
asManaged(obj, 42)
|
||||
meta.SetExternalCreatePending(obj, now.Time)
|
||||
return nil
|
||||
}),
|
||||
MockUpdate: test.NewMockUpdateFn(nil),
|
||||
MockStatusUpdate: test.MockSubResourceUpdateFn(func(_ context.Context, obj client.Object, _ ...client.SubResourceUpdateOption) error {
|
||||
want := newManaged(42)
|
||||
meta.SetExternalCreatePending(want, time.Now())
|
||||
meta.SetExternalCreateSucceeded(want, time.Now())
|
||||
want.SetConditions(xpv1.ReconcileSuccess().WithObservedGeneration(42))
|
||||
want.SetConditions(xpv1.Creating().WithObservedGeneration(42))
|
||||
if diff := cmp.Diff(want, obj, test.EquateConditions(), cmpopts.EquateApproxTime(1*time.Second)); diff != "" {
|
||||
reason := "Successful managed resource creation should be reported as a conditioned status."
|
||||
t.Errorf("\nReason: %s\n-want, +got:\n%s", reason, diff)
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
},
|
||||
Scheme: fake.SchemeWith(&fake.Managed{}),
|
||||
},
|
||||
mg: resource.ManagedKind(fake.GVK(&fake.Managed{})),
|
||||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnector(&NopConnector{}),
|
||||
WithCriticalAnnotationUpdater(CriticalAnnotationUpdateFn(func(_ context.Context, _ client.Object) error { return nil })),
|
||||
WithConnectionPublishers(),
|
||||
WithFinalizer(resource.FinalizerFns{AddFinalizerFn: func(_ context.Context, _ resource.Object) error { return nil }}),
|
||||
WithDeterministicExternalName(true),
|
||||
},
|
||||
},
|
||||
want: want{result: reconcile.Result{Requeue: true}},
|
||||
},
|
||||
"LateInitializeUpdateError": {
|
||||
reason: "Errors updating a managed resource to persist late initialized fields should trigger a requeue after a short wait.",
|
||||
args: args{
|
||||
|
@ -941,7 +980,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: true, ResourceUpToDate: true, ResourceLateInitialized: true}, nil
|
||||
|
@ -980,7 +1019,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: true, ResourceUpToDate: true}, nil
|
||||
|
@ -1013,7 +1052,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: true, ResourceUpToDate: true}, nil
|
||||
|
@ -1056,7 +1095,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: true, ResourceUpToDate: true}, nil
|
||||
|
@ -1094,7 +1133,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: true, ResourceUpToDate: true}, nil
|
||||
|
@ -1142,7 +1181,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: true, ResourceUpToDate: false}, nil
|
||||
|
@ -1184,7 +1223,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: true, ResourceUpToDate: false}, nil
|
||||
|
@ -1237,7 +1276,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: true, ResourceUpToDate: false}, nil
|
||||
|
@ -1389,7 +1428,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: true, ResourceUpToDate: true}, nil
|
||||
|
@ -1541,7 +1580,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithManagementPolicies(),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: false}, nil
|
||||
|
@ -1583,7 +1622,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithManagementPolicies(),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: true}, nil
|
||||
|
@ -1630,7 +1669,7 @@ func TestReconciler(t *testing.T) {
|
|||
o: []ReconcilerOption{
|
||||
WithInitializers(),
|
||||
WithManagementPolicies(),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: true}, nil
|
||||
|
@ -1683,7 +1722,7 @@ func TestReconciler(t *testing.T) {
|
|||
WithInitializers(),
|
||||
WithManagementPolicies(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(&NopConnecter{}),
|
||||
WithExternalConnector(&NopConnector{}),
|
||||
WithCriticalAnnotationUpdater(CriticalAnnotationUpdateFn(func(_ context.Context, _ client.Object) error { return nil })),
|
||||
WithConnectionPublishers(),
|
||||
WithFinalizer(resource.FinalizerFns{AddFinalizerFn: func(_ context.Context, _ resource.Object) error { return nil }}),
|
||||
|
@ -1723,7 +1762,7 @@ func TestReconciler(t *testing.T) {
|
|||
WithInitializers(),
|
||||
WithManagementPolicies(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(&NopConnecter{}),
|
||||
WithExternalConnector(&NopConnector{}),
|
||||
WithCriticalAnnotationUpdater(CriticalAnnotationUpdateFn(func(_ context.Context, _ client.Object) error { return nil })),
|
||||
WithConnectionPublishers(),
|
||||
WithFinalizer(resource.FinalizerFns{AddFinalizerFn: func(_ context.Context, _ resource.Object) error { return nil }}),
|
||||
|
@ -1760,7 +1799,7 @@ func TestReconciler(t *testing.T) {
|
|||
WithInitializers(),
|
||||
WithManagementPolicies(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: true, ResourceUpToDate: false}, nil
|
||||
|
@ -1808,7 +1847,7 @@ func TestReconciler(t *testing.T) {
|
|||
WithInitializers(),
|
||||
WithManagementPolicies(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: true, ResourceUpToDate: false}, nil
|
||||
|
@ -1856,7 +1895,7 @@ func TestReconciler(t *testing.T) {
|
|||
WithInitializers(),
|
||||
WithManagementPolicies(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: true, ResourceUpToDate: false}, nil
|
||||
|
@ -1905,7 +1944,7 @@ func TestReconciler(t *testing.T) {
|
|||
WithInitializers(),
|
||||
WithManagementPolicies(),
|
||||
WithReferenceResolver(ReferenceResolverFn(func(_ context.Context, _ resource.Managed) error { return nil })),
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
return ExternalObservation{ResourceExists: true, ResourceUpToDate: true, ResourceLateInitialized: true}, nil
|
||||
|
@ -2458,7 +2497,7 @@ func TestReconcilerChangeLogs(t *testing.T) {
|
|||
},
|
||||
mg: resource.ManagedKind(fake.GVK(&fake.Managed{})),
|
||||
o: []ReconcilerOption{
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
// resource doesn't exist, which should trigger a create operation
|
||||
|
@ -2495,7 +2534,7 @@ func TestReconcilerChangeLogs(t *testing.T) {
|
|||
},
|
||||
mg: resource.ManagedKind(fake.GVK(&fake.Managed{})),
|
||||
o: []ReconcilerOption{
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
// resource doesn't exist, which should trigger a create operation
|
||||
|
@ -2533,7 +2572,7 @@ func TestReconcilerChangeLogs(t *testing.T) {
|
|||
},
|
||||
mg: resource.ManagedKind(fake.GVK(&fake.Managed{})),
|
||||
o: []ReconcilerOption{
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
// resource exists but isn't up to date, which should trigger an update operation
|
||||
|
@ -2570,7 +2609,7 @@ func TestReconcilerChangeLogs(t *testing.T) {
|
|||
},
|
||||
mg: resource.ManagedKind(fake.GVK(&fake.Managed{})),
|
||||
o: []ReconcilerOption{
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
// resource exists but isn't up to date, which should trigger an update operation
|
||||
|
@ -2614,7 +2653,7 @@ func TestReconcilerChangeLogs(t *testing.T) {
|
|||
},
|
||||
mg: resource.ManagedKind(fake.GVK(&fake.Managed{})),
|
||||
o: []ReconcilerOption{
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
// resource exists but we set a deletion timestamp above, which should trigger a delete operation
|
||||
|
@ -2657,7 +2696,7 @@ func TestReconcilerChangeLogs(t *testing.T) {
|
|||
},
|
||||
mg: resource.ManagedKind(fake.GVK(&fake.Managed{})),
|
||||
o: []ReconcilerOption{
|
||||
WithExternalConnecter(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
WithExternalConnector(ExternalConnectorFn(func(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
c := &ExternalClientFns{
|
||||
ObserveFn: func(_ context.Context, _ resource.Managed) (ExternalObservation, error) {
|
||||
// resource exists but we set a deletion timestamp above, which should trigger a delete operation
|
||||
|
|
|
@ -9,13 +9,13 @@ import (
|
|||
|
||||
const errFmtUnexpectedObjectType = "unexpected object type %T"
|
||||
|
||||
// typedExternalConnectDisconnecterWrapper wraps a TypedExternalConnecter to a
|
||||
// typedExternalConnectDisconnectorWrapper wraps a TypedExternalConnector to a
|
||||
// common ExternalConnector.
|
||||
type typedExternalConnectDisconnecterWrapper[managed resource.Managed] struct {
|
||||
c TypedExternalConnectDisconnecter[managed]
|
||||
type typedExternalConnectDisconnectorWrapper[managed resource.Managed] struct {
|
||||
c TypedExternalConnectDisconnector[managed]
|
||||
}
|
||||
|
||||
func (c *typedExternalConnectDisconnecterWrapper[managed]) Connect(ctx context.Context, mg resource.Managed) (ExternalClient, error) {
|
||||
func (c *typedExternalConnectDisconnectorWrapper[managed]) Connect(ctx context.Context, mg resource.Managed) (ExternalClient, error) {
|
||||
cr, ok := mg.(managed)
|
||||
if !ok {
|
||||
return nil, errors.Errorf(errFmtUnexpectedObjectType, mg)
|
||||
|
@ -27,7 +27,7 @@ func (c *typedExternalConnectDisconnecterWrapper[managed]) Connect(ctx context.C
|
|||
return &typedExternalClientWrapper[managed]{c: external}, nil
|
||||
}
|
||||
|
||||
func (c *typedExternalConnectDisconnecterWrapper[managed]) Disconnect(ctx context.Context) error {
|
||||
func (c *typedExternalConnectDisconnectorWrapper[managed]) Disconnect(ctx context.Context) error {
|
||||
return c.c.Disconnect(ctx)
|
||||
}
|
||||
|
||||
|
@ -52,6 +52,7 @@ func (c *typedExternalClientWrapper[managed]) Create(ctx context.Context, mg res
|
|||
}
|
||||
return c.c.Create(ctx, cr)
|
||||
}
|
||||
|
||||
func (c *typedExternalClientWrapper[managed]) Update(ctx context.Context, mg resource.Managed) (ExternalUpdate, error) {
|
||||
cr, ok := mg.(managed)
|
||||
if !ok {
|
||||
|
|
|
@ -20,6 +20,8 @@ package reference
|
|||
|
||||
import (
|
||||
"context"
|
||||
"maps"
|
||||
"slices"
|
||||
"strconv"
|
||||
|
||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
|
@ -107,7 +109,7 @@ func ToIntPtrValue(v string) *int64 {
|
|||
// string pointers and need to be resolved as part of `ResolveMultiple`.
|
||||
func FromPtrValues(v []*string) []string {
|
||||
res := make([]string, len(v))
|
||||
for i := range len(v) {
|
||||
for i := range v {
|
||||
res[i] = FromPtrValue(v[i])
|
||||
}
|
||||
return res
|
||||
|
@ -116,7 +118,7 @@ func FromPtrValues(v []*string) []string {
|
|||
// FromFloatPtrValues adapts a slice of float64 pointer fields for use as CurrentValues.
|
||||
func FromFloatPtrValues(v []*float64) []string {
|
||||
res := make([]string, len(v))
|
||||
for i := range len(v) {
|
||||
for i := range v {
|
||||
res[i] = FromFloatPtrValue(v[i])
|
||||
}
|
||||
return res
|
||||
|
@ -125,7 +127,7 @@ func FromFloatPtrValues(v []*float64) []string {
|
|||
// FromIntPtrValues adapts a slice of int64 pointer fields for use as CurrentValues.
|
||||
func FromIntPtrValues(v []*int64) []string {
|
||||
res := make([]string, len(v))
|
||||
for i := range len(v) {
|
||||
for i := range v {
|
||||
res[i] = FromIntPtrValue(v[i])
|
||||
}
|
||||
return res
|
||||
|
@ -138,7 +140,7 @@ func FromIntPtrValues(v []*int64) []string {
|
|||
// string pointers and need to be resolved as part of `ResolveMultiple`.
|
||||
func ToPtrValues(v []string) []*string {
|
||||
res := make([]*string, len(v))
|
||||
for i := range len(v) {
|
||||
for i := range v {
|
||||
res[i] = ToPtrValue(v[i])
|
||||
}
|
||||
return res
|
||||
|
@ -147,7 +149,7 @@ func ToPtrValues(v []string) []*string {
|
|||
// ToFloatPtrValues adapts ResolvedValues for use as a slice of float64 pointer fields.
|
||||
func ToFloatPtrValues(v []string) []*float64 {
|
||||
res := make([]*float64, len(v))
|
||||
for i := range len(v) {
|
||||
for i := range v {
|
||||
res[i] = ToFloatPtrValue(v[i])
|
||||
}
|
||||
return res
|
||||
|
@ -156,7 +158,7 @@ func ToFloatPtrValues(v []string) []*float64 {
|
|||
// ToIntPtrValues adapts ResolvedValues for use as a slice of int64 pointer fields.
|
||||
func ToIntPtrValues(v []string) []*int64 {
|
||||
res := make([]*int64, len(v))
|
||||
for i := range len(v) {
|
||||
for i := range v {
|
||||
res[i] = ToIntPtrValue(v[i])
|
||||
}
|
||||
return res
|
||||
|
@ -188,6 +190,7 @@ type ResolutionRequest struct {
|
|||
Selector *xpv1.Selector
|
||||
To To
|
||||
Extract ExtractValueFn
|
||||
Namespace string
|
||||
}
|
||||
|
||||
// IsNoOp returns true if the supplied ResolutionRequest cannot or should not be
|
||||
|
@ -242,6 +245,7 @@ type MultiResolutionRequest struct {
|
|||
Selector *xpv1.Selector
|
||||
To To
|
||||
Extract ExtractValueFn
|
||||
Namespace string
|
||||
}
|
||||
|
||||
// IsNoOp returns true if the supplied MultiResolutionRequest cannot or should
|
||||
|
@ -323,7 +327,7 @@ func (r *APIResolver) Resolve(ctx context.Context, req ResolutionRequest) (Resol
|
|||
|
||||
// The reference is already set - resolve it.
|
||||
if req.Reference != nil {
|
||||
if err := r.client.Get(ctx, types.NamespacedName{Name: req.Reference.Name}, req.To.Managed); err != nil {
|
||||
if err := r.client.Get(ctx, types.NamespacedName{Name: req.Reference.Name, Namespace: req.Namespace}, req.To.Managed); err != nil {
|
||||
if kerrors.IsNotFound(err) {
|
||||
return ResolutionResponse{}, getResolutionError(req.Reference.Policy, errors.Wrap(err, errGetManaged))
|
||||
}
|
||||
|
@ -334,8 +338,9 @@ func (r *APIResolver) Resolve(ctx context.Context, req ResolutionRequest) (Resol
|
|||
return rsp, getResolutionError(req.Reference.Policy, rsp.Validate())
|
||||
}
|
||||
|
||||
// The reference was not set, but a selector was. Select a reference.
|
||||
if err := r.client.List(ctx, req.To.List, client.MatchingLabels(req.Selector.MatchLabels)); err != nil {
|
||||
// The reference was not set, but a selector was. Select a reference. If the
|
||||
// request has no namespace, then InNamespace is a no-op.
|
||||
if err := r.client.List(ctx, req.To.List, client.MatchingLabels(req.Selector.MatchLabels), client.InNamespace(req.Namespace)); err != nil {
|
||||
return ResolutionResponse{}, errors.Wrap(err, errListManaged)
|
||||
}
|
||||
|
||||
|
@ -361,41 +366,43 @@ func (r *APIResolver) ResolveMultiple(ctx context.Context, req MultiResolutionRe
|
|||
return MultiResolutionResponse{ResolvedValues: req.CurrentValues, ResolvedReferences: req.References}, nil
|
||||
}
|
||||
|
||||
valueMap := make(map[string]xpv1.Reference)
|
||||
|
||||
// The references are already set - resolve them.
|
||||
if len(req.References) > 0 {
|
||||
vals := make([]string, len(req.References))
|
||||
for i := range req.References {
|
||||
if err := r.client.Get(ctx, types.NamespacedName{Name: req.References[i].Name}, req.To.Managed); err != nil {
|
||||
if err := r.client.Get(ctx, types.NamespacedName{Name: req.References[i].Name, Namespace: req.Namespace}, req.To.Managed); err != nil {
|
||||
if kerrors.IsNotFound(err) {
|
||||
return MultiResolutionResponse{}, getResolutionError(req.References[i].Policy, errors.Wrap(err, errGetManaged))
|
||||
}
|
||||
return MultiResolutionResponse{}, errors.Wrap(err, errGetManaged)
|
||||
}
|
||||
vals[i] = req.Extract(req.To.Managed)
|
||||
valueMap[req.Extract(req.To.Managed)] = req.References[i]
|
||||
}
|
||||
|
||||
rsp := MultiResolutionResponse{ResolvedValues: vals, ResolvedReferences: req.References}
|
||||
sortedKeys, sortedRefs := sortMapByKeys(valueMap)
|
||||
|
||||
rsp := MultiResolutionResponse{ResolvedValues: sortedKeys, ResolvedReferences: sortedRefs}
|
||||
return rsp, rsp.Validate()
|
||||
}
|
||||
|
||||
// No references were set, but a selector was. Select and resolve references.
|
||||
if err := r.client.List(ctx, req.To.List, client.MatchingLabels(req.Selector.MatchLabels)); err != nil {
|
||||
// No references were set, but a selector was. Select and resolve
|
||||
// references. If the request has no namespace, then InNamespace is a no-op.
|
||||
if err := r.client.List(ctx, req.To.List, client.MatchingLabels(req.Selector.MatchLabels), client.InNamespace(req.Namespace)); err != nil {
|
||||
return MultiResolutionResponse{}, errors.Wrap(err, errListManaged)
|
||||
}
|
||||
|
||||
items := req.To.List.GetItems()
|
||||
refs := make([]xpv1.Reference, 0, len(items))
|
||||
vals := make([]string, 0, len(items))
|
||||
for _, to := range req.To.List.GetItems() {
|
||||
if ControllersMustMatch(req.Selector) && !meta.HaveSameController(r.from, to) {
|
||||
continue
|
||||
}
|
||||
|
||||
vals = append(vals, req.Extract(to))
|
||||
refs = append(refs, xpv1.Reference{Name: to.GetName()})
|
||||
valueMap[req.Extract(to)] = xpv1.Reference{Name: to.GetName()}
|
||||
}
|
||||
|
||||
rsp := MultiResolutionResponse{ResolvedValues: vals, ResolvedReferences: refs}
|
||||
sortedKeys, sortedRefs := sortMapByKeys(valueMap)
|
||||
|
||||
rsp := MultiResolutionResponse{ResolvedValues: sortedKeys, ResolvedReferences: sortedRefs}
|
||||
return rsp, getResolutionError(req.Selector.Policy, rsp.Validate())
|
||||
}
|
||||
|
||||
|
@ -406,6 +413,15 @@ func getResolutionError(p *xpv1.Policy, err error) error {
|
|||
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
|
||||
}
|
||||
|
||||
// ControllersMustMatch returns true if the supplied Selector requires that a
|
||||
// reference be to a managed resource whose controller reference matches the
|
||||
// referencing resource.
|
||||
|
|
|
@ -286,6 +286,30 @@ func TestResolve(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
"SuccessfulResolveNamespaced": {
|
||||
reason: "Resolve should be successful when a namespace is given",
|
||||
c: &test.MockClient{
|
||||
MockGet: test.NewMockGetFn(nil, func(obj client.Object) error {
|
||||
meta.SetExternalName(obj.(metav1.Object), value)
|
||||
return nil
|
||||
}),
|
||||
},
|
||||
from: &fake.Managed{},
|
||||
args: args{
|
||||
req: ResolutionRequest{
|
||||
Reference: ref,
|
||||
To: To{Managed: &fake.Managed{}},
|
||||
Extract: ExternalName(),
|
||||
Namespace: "cool-ns",
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
rsp: ResolutionResponse{
|
||||
ResolvedValue: value,
|
||||
ResolvedReference: ref,
|
||||
},
|
||||
},
|
||||
},
|
||||
"OptionalReference": {
|
||||
reason: "No error should be returned when the resolution policy is Optional",
|
||||
c: &test.MockClient{
|
||||
|
@ -384,6 +408,33 @@ func TestResolve(t *testing.T) {
|
|||
err: nil,
|
||||
},
|
||||
},
|
||||
"SuccessfulSelectNamespaced": {
|
||||
reason: "Resolve should be successful when a namespace is given",
|
||||
c: &test.MockClient{
|
||||
MockList: test.NewMockListFn(nil),
|
||||
},
|
||||
from: controlled,
|
||||
args: args{
|
||||
req: ResolutionRequest{
|
||||
Selector: &xpv1.Selector{
|
||||
MatchControllerRef: func() *bool { t := true; return &t }(),
|
||||
},
|
||||
To: To{List: &FakeManagedList{Items: []resource.Managed{
|
||||
&fake.Managed{}, // A resource that does not match.
|
||||
controlled, // A resource with a matching controller reference.
|
||||
}}},
|
||||
Extract: ExternalName(),
|
||||
Namespace: "cool-ns",
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
rsp: ResolutionResponse{
|
||||
ResolvedValue: value,
|
||||
ResolvedReference: &xpv1.Reference{Name: value},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
},
|
||||
"AlwaysResolveSelector": {
|
||||
reason: "Should not return early if the current value is non-zero, when the resolve policy is set to" +
|
||||
"Always",
|
||||
|
@ -458,6 +509,7 @@ func TestResolveMultiple(t *testing.T) {
|
|||
errBoom := errors.New("boom")
|
||||
now := metav1.Now()
|
||||
value := "coolv"
|
||||
value2 := "cooler"
|
||||
ref := xpv1.Reference{Name: "cool"}
|
||||
optionalPolicy := xpv1.ResolutionPolicyOptional
|
||||
alwaysPolicy := xpv1.ResolvePolicyAlways
|
||||
|
@ -469,6 +521,11 @@ func TestResolveMultiple(t *testing.T) {
|
|||
meta.SetExternalName(controlled, value)
|
||||
meta.AddControllerReference(controlled, meta.AsController(&xpv1.TypedReference{UID: types.UID("very-unique")}))
|
||||
|
||||
controlled2 := &fake.Managed{}
|
||||
controlled2.SetName(value2)
|
||||
meta.SetExternalName(controlled2, value2)
|
||||
meta.AddControllerReference(controlled2, meta.AsController(&xpv1.TypedReference{UID: types.UID("very-unique")}))
|
||||
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req MultiResolutionRequest
|
||||
|
@ -603,6 +660,30 @@ func TestResolveMultiple(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
"SuccessfulResolveNamespaced": {
|
||||
reason: "Resolve should be successful when a namespace is given",
|
||||
c: &test.MockClient{
|
||||
MockGet: test.NewMockGetFn(nil, func(obj client.Object) error {
|
||||
meta.SetExternalName(obj.(metav1.Object), value)
|
||||
return nil
|
||||
}),
|
||||
},
|
||||
from: &fake.Managed{},
|
||||
args: args{
|
||||
req: MultiResolutionRequest{
|
||||
References: []xpv1.Reference{ref},
|
||||
To: To{Managed: &fake.Managed{}},
|
||||
Extract: ExternalName(),
|
||||
Namespace: "cool-ns",
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
rsp: MultiResolutionResponse{
|
||||
ResolvedValues: []string{value},
|
||||
ResolvedReferences: []xpv1.Reference{ref},
|
||||
},
|
||||
},
|
||||
},
|
||||
"OptionalReference": {
|
||||
reason: "No error should be returned when the resolution policy is Optional",
|
||||
c: &test.MockClient{
|
||||
|
@ -702,6 +783,33 @@ func TestResolveMultiple(t *testing.T) {
|
|||
err: nil,
|
||||
},
|
||||
},
|
||||
"SuccessfulSelectNamespaced": {
|
||||
reason: "Resolve should be successful when a namespace is given",
|
||||
c: &test.MockClient{
|
||||
MockList: test.NewMockListFn(nil),
|
||||
},
|
||||
from: controlled,
|
||||
args: args{
|
||||
req: MultiResolutionRequest{
|
||||
Selector: &xpv1.Selector{
|
||||
MatchControllerRef: func() *bool { t := true; return &t }(),
|
||||
},
|
||||
To: To{List: &FakeManagedList{Items: []resource.Managed{
|
||||
&fake.Managed{}, // A resource that does not match.
|
||||
controlled, // A resource with a matching controller reference.
|
||||
}}},
|
||||
Extract: ExternalName(),
|
||||
Namespace: "cool-ns",
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
rsp: MultiResolutionResponse{
|
||||
ResolvedValues: []string{value},
|
||||
ResolvedReferences: []xpv1.Reference{{Name: value}},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
},
|
||||
"AlwaysResolveSelector": {
|
||||
reason: "Should not return early if the current value is non-zero, when the resolve policy is set to" +
|
||||
"Always",
|
||||
|
@ -757,6 +865,36 @@ func TestResolveMultiple(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
"OrderOutput": {
|
||||
reason: "Output values should ordered",
|
||||
c: &test.MockClient{
|
||||
MockList: test.NewMockListFn(nil),
|
||||
},
|
||||
from: controlled,
|
||||
args: args{
|
||||
req: MultiResolutionRequest{
|
||||
Selector: &xpv1.Selector{
|
||||
MatchControllerRef: func() *bool { t := true; return &t }(),
|
||||
},
|
||||
To: To{List: &FakeManagedList{
|
||||
Items: []resource.Managed{
|
||||
&fake.Managed{}, // A resource that does not match.
|
||||
controlled, // A resource with a matching controller reference.
|
||||
&fake.Managed{}, // A resource that does not match.
|
||||
controlled2, // A resource with a matching controller reference.
|
||||
},
|
||||
}},
|
||||
Extract: ExternalName(),
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
rsp: MultiResolutionResponse{
|
||||
ResolvedValues: []string{value2, value},
|
||||
ResolvedReferences: []xpv1.Reference{{Name: value2}, {Name: value}},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
|
|
|
@ -234,7 +234,7 @@ type ProviderConfigUsageList interface {
|
|||
GetItems() []ProviderConfigUsage
|
||||
}
|
||||
|
||||
// A Composite resource composes one or more Composed resources.
|
||||
// A Composite resource (or XR) is composed of other resources.
|
||||
type Composite interface { //nolint:interfacebloat // This interface has to be big.
|
||||
Object
|
||||
|
||||
|
@ -244,27 +244,29 @@ type Composite interface { //nolint:interfacebloat // This interface has to be b
|
|||
CompositionRevisionReferencer
|
||||
CompositionRevisionSelector
|
||||
ComposedResourcesReferencer
|
||||
EnvironmentConfigReferencer
|
||||
ClaimReferencer
|
||||
ConnectionSecretWriterTo
|
||||
ConnectionDetailsPublisherTo
|
||||
|
||||
Conditioned
|
||||
ConnectionDetailsPublishedTimer
|
||||
ReconciliationObserver
|
||||
}
|
||||
|
||||
// A LegacyComposite is a Crossplane v1 style legacy XR.
|
||||
type LegacyComposite interface {
|
||||
Composite
|
||||
ClaimReferencer
|
||||
ConnectionSecretWriterTo
|
||||
ConnectionDetailsPublishedTimer
|
||||
}
|
||||
|
||||
// Composed resources can be a composed into a Composite resource.
|
||||
type Composed interface {
|
||||
Object
|
||||
|
||||
Conditioned
|
||||
ConnectionSecretWriterTo
|
||||
ConnectionDetailsPublisherTo
|
||||
ReconciliationObserver
|
||||
}
|
||||
|
||||
// A CompositeClaim for a Composite resource.
|
||||
// A CompositeClaim of a composite resource (XR).
|
||||
type CompositeClaim interface { //nolint:interfacebloat // This interface has to be big.
|
||||
Object
|
||||
|
||||
|
@ -276,9 +278,11 @@ type CompositeClaim interface { //nolint:interfacebloat // This interface has to
|
|||
CompositeResourceDeleter
|
||||
CompositeResourceReferencer
|
||||
LocalConnectionSecretWriterTo
|
||||
ConnectionDetailsPublisherTo
|
||||
|
||||
Conditioned
|
||||
ConnectionDetailsPublishedTimer
|
||||
ReconciliationObserver
|
||||
}
|
||||
|
||||
// A Claim of a composite resource (XR).
|
||||
type Claim = CompositeClaim
|
||||
|
|
|
@ -193,20 +193,6 @@ func (c *Unstructured) SetWriteConnectionSecretToReference(ref *xpv1.LocalSecret
|
|||
_ = fieldpath.Pave(c.Object).SetValue("spec.writeConnectionSecretToRef", ref)
|
||||
}
|
||||
|
||||
// GetPublishConnectionDetailsTo of this composite resource claim.
|
||||
func (c *Unstructured) GetPublishConnectionDetailsTo() *xpv1.PublishConnectionDetailsTo {
|
||||
out := &xpv1.PublishConnectionDetailsTo{}
|
||||
if err := fieldpath.Pave(c.Object).GetValueInto("spec.publishConnectionDetailsTo", out); err != nil {
|
||||
return nil
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// SetPublishConnectionDetailsTo of this composite resource claim.
|
||||
func (c *Unstructured) SetPublishConnectionDetailsTo(ref *xpv1.PublishConnectionDetailsTo) {
|
||||
_ = fieldpath.Pave(c.Object).SetValue("spec.publishConnectionDetailsTo", ref)
|
||||
}
|
||||
|
||||
// GetCondition of this composite resource claim.
|
||||
func (c *Unstructured) GetCondition(ct xpv1.ConditionType) xpv1.Condition {
|
||||
conditioned := xpv1.ConditionedStatus{}
|
||||
|
|
|
@ -103,20 +103,6 @@ func (cr *Unstructured) SetWriteConnectionSecretToReference(r *xpv1.SecretRefere
|
|||
_ = fieldpath.Pave(cr.Object).SetValue("spec.writeConnectionSecretToRef", r)
|
||||
}
|
||||
|
||||
// GetPublishConnectionDetailsTo of this Composed resource.
|
||||
func (cr *Unstructured) GetPublishConnectionDetailsTo() *xpv1.PublishConnectionDetailsTo {
|
||||
out := &xpv1.PublishConnectionDetailsTo{}
|
||||
if err := fieldpath.Pave(cr.Object).GetValueInto("spec.publishConnectionDetailsTo", out); err != nil {
|
||||
return nil
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// SetPublishConnectionDetailsTo of this Composed resource.
|
||||
func (cr *Unstructured) SetPublishConnectionDetailsTo(ref *xpv1.PublishConnectionDetailsTo) {
|
||||
_ = fieldpath.Pave(cr.Object).SetValue("spec.publishConnectionDetailsTo", ref)
|
||||
}
|
||||
|
||||
// OwnedBy returns true if the supplied UID is an owner of the composed.
|
||||
func (cr *Unstructured) OwnedBy(u types.UID) bool {
|
||||
for _, owner := range cr.GetOwnerReferences() {
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/utils/ptr"
|
||||
|
||||
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/errors"
|
||||
|
@ -29,28 +30,49 @@ import (
|
|||
"github.com/crossplane/crossplane-runtime/pkg/resource/unstructured/reference"
|
||||
)
|
||||
|
||||
// Schema specifies the schema version of a composite resource's Crossplane
|
||||
// machinery fields.
|
||||
type Schema int
|
||||
|
||||
const (
|
||||
// SchemaModern indicates a modern Namespaced or Cluster scope composite
|
||||
// resource. Modern composite resources nest all Crossplane machinery fields
|
||||
// under spec.crossplane and status.crossplane, and can't be claimed.
|
||||
SchemaModern Schema = iota
|
||||
|
||||
// SchemaLegacy indicates a LegacyCluster scope composite resource. Legacy
|
||||
// composite resources don't nest Crossplane machinery fields - they're set
|
||||
// directly under spec and status. Legacy composite resources can be claimed.
|
||||
SchemaLegacy
|
||||
)
|
||||
|
||||
// An Option modifies an unstructured composite resource.
|
||||
type Option func(*Unstructured)
|
||||
|
||||
// WithGroupVersionKind sets the GroupVersionKind of the unstructured composite
|
||||
// resource.
|
||||
// WithGroupVersionKind sets the GroupVersionKind of the composite resource.
|
||||
func WithGroupVersionKind(gvk schema.GroupVersionKind) Option {
|
||||
return func(c *Unstructured) {
|
||||
c.SetGroupVersionKind(gvk)
|
||||
}
|
||||
}
|
||||
|
||||
// WithConditions returns an Option that sets the supplied conditions on an
|
||||
// unstructured composite resource.
|
||||
// WithConditions sets the supplied conditions on the composite resource.
|
||||
func WithConditions(c ...xpv1.Condition) Option {
|
||||
return func(cr *Unstructured) {
|
||||
cr.SetConditions(c...)
|
||||
}
|
||||
}
|
||||
|
||||
// New returns a new unstructured composed resource.
|
||||
// WithSchema sets the schema of the composite resource.
|
||||
func WithSchema(s Schema) Option {
|
||||
return func(c *Unstructured) {
|
||||
c.Schema = s
|
||||
}
|
||||
}
|
||||
|
||||
// New returns a new unstructured composite resource.
|
||||
func New(opts ...Option) *Unstructured {
|
||||
c := &Unstructured{unstructured.Unstructured{Object: make(map[string]any)}}
|
||||
c := &Unstructured{Unstructured: unstructured.Unstructured{Object: make(map[string]any)}}
|
||||
for _, f := range opts {
|
||||
f(c)
|
||||
}
|
||||
|
@ -60,9 +82,11 @@ func New(opts ...Option) *Unstructured {
|
|||
// +k8s:deepcopy-gen=true
|
||||
// +kubebuilder:object:root=true
|
||||
|
||||
// An Unstructured composed resource.
|
||||
// An Unstructured composite resource.
|
||||
type Unstructured struct {
|
||||
unstructured.Unstructured
|
||||
|
||||
Schema Schema
|
||||
}
|
||||
|
||||
// GetUnstructured returns the underlying *unstructured.Unstructured.
|
||||
|
@ -70,52 +94,87 @@ func (c *Unstructured) GetUnstructured() *unstructured.Unstructured {
|
|||
return &c.Unstructured
|
||||
}
|
||||
|
||||
// GetCompositionSelector of this Composite resource.
|
||||
// GetCompositionSelector of this composite resource.
|
||||
func (c *Unstructured) GetCompositionSelector() *metav1.LabelSelector {
|
||||
path := "spec.crossplane.compositionSelector"
|
||||
if c.Schema == SchemaLegacy {
|
||||
path = "spec.compositionSelector"
|
||||
}
|
||||
|
||||
out := &metav1.LabelSelector{}
|
||||
if err := fieldpath.Pave(c.Object).GetValueInto("spec.compositionSelector", out); err != nil {
|
||||
if err := fieldpath.Pave(c.Object).GetValueInto(path, out); err != nil {
|
||||
return nil
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// SetCompositionSelector of this Composite resource.
|
||||
// SetCompositionSelector of this composite resource.
|
||||
func (c *Unstructured) SetCompositionSelector(sel *metav1.LabelSelector) {
|
||||
_ = fieldpath.Pave(c.Object).SetValue("spec.compositionSelector", sel)
|
||||
path := "spec.crossplane.compositionSelector"
|
||||
if c.Schema == SchemaLegacy {
|
||||
path = "spec.compositionSelector"
|
||||
}
|
||||
|
||||
_ = fieldpath.Pave(c.Object).SetValue(path, sel)
|
||||
}
|
||||
|
||||
// GetCompositionReference of this Composite resource.
|
||||
// GetCompositionReference of this composite resource.
|
||||
func (c *Unstructured) GetCompositionReference() *corev1.ObjectReference {
|
||||
path := "spec.crossplane.compositionRef"
|
||||
if c.Schema == SchemaLegacy {
|
||||
path = "spec.compositionRef"
|
||||
}
|
||||
|
||||
out := &corev1.ObjectReference{}
|
||||
if err := fieldpath.Pave(c.Object).GetValueInto("spec.compositionRef", out); err != nil {
|
||||
if err := fieldpath.Pave(c.Object).GetValueInto(path, out); err != nil {
|
||||
return nil
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// SetCompositionReference of this Composite resource.
|
||||
// SetCompositionReference of this composite resource.
|
||||
func (c *Unstructured) SetCompositionReference(ref *corev1.ObjectReference) {
|
||||
_ = fieldpath.Pave(c.Object).SetValue("spec.compositionRef", ref)
|
||||
path := "spec.crossplane.compositionRef"
|
||||
if c.Schema == SchemaLegacy {
|
||||
path = "spec.compositionRef"
|
||||
}
|
||||
|
||||
_ = fieldpath.Pave(c.Object).SetValue(path, ref)
|
||||
}
|
||||
|
||||
// GetCompositionRevisionReference of this Composite resource.
|
||||
// GetCompositionRevisionReference of this composite resource.
|
||||
func (c *Unstructured) GetCompositionRevisionReference() *corev1.LocalObjectReference {
|
||||
path := "spec.crossplane.compositionRevisionRef"
|
||||
if c.Schema == SchemaLegacy {
|
||||
path = "spec.compositionRevisionRef"
|
||||
}
|
||||
|
||||
out := &corev1.LocalObjectReference{}
|
||||
if err := fieldpath.Pave(c.Object).GetValueInto("spec.compositionRevisionRef", out); err != nil {
|
||||
if err := fieldpath.Pave(c.Object).GetValueInto(path, out); err != nil {
|
||||
return nil
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// SetCompositionRevisionReference of this Composite resource.
|
||||
// SetCompositionRevisionReference of this composite resource.
|
||||
func (c *Unstructured) SetCompositionRevisionReference(ref *corev1.LocalObjectReference) {
|
||||
_ = fieldpath.Pave(c.Object).SetValue("spec.compositionRevisionRef", ref)
|
||||
path := "spec.crossplane.compositionRevisionRef"
|
||||
if c.Schema == SchemaLegacy {
|
||||
path = "spec.compositionRevisionRef"
|
||||
}
|
||||
|
||||
_ = fieldpath.Pave(c.Object).SetValue(path, ref)
|
||||
}
|
||||
|
||||
// GetCompositionRevisionSelector of this resource claim.
|
||||
func (c *Unstructured) GetCompositionRevisionSelector() *metav1.LabelSelector {
|
||||
path := "spec.crossplane.compositionRevisionSelector"
|
||||
if c.Schema == SchemaLegacy {
|
||||
path = "spec.compositionRevisionSelector"
|
||||
}
|
||||
|
||||
out := &metav1.LabelSelector{}
|
||||
if err := fieldpath.Pave(c.Object).GetValueInto("spec.compositionRevisionSelector", out); err != nil {
|
||||
if err := fieldpath.Pave(c.Object).GetValueInto(path, out); err != nil {
|
||||
return nil
|
||||
}
|
||||
return out
|
||||
|
@ -123,17 +182,32 @@ func (c *Unstructured) GetCompositionRevisionSelector() *metav1.LabelSelector {
|
|||
|
||||
// SetCompositionRevisionSelector of this resource claim.
|
||||
func (c *Unstructured) SetCompositionRevisionSelector(sel *metav1.LabelSelector) {
|
||||
_ = fieldpath.Pave(c.Object).SetValue("spec.compositionRevisionSelector", sel)
|
||||
path := "spec.crossplane.compositionRevisionSelector"
|
||||
if c.Schema == SchemaLegacy {
|
||||
path = "spec.compositionRevisionSelector"
|
||||
}
|
||||
|
||||
_ = fieldpath.Pave(c.Object).SetValue(path, sel)
|
||||
}
|
||||
|
||||
// SetCompositionUpdatePolicy of this Composite resource.
|
||||
// SetCompositionUpdatePolicy of this composite resource.
|
||||
func (c *Unstructured) SetCompositionUpdatePolicy(p *xpv1.UpdatePolicy) {
|
||||
_ = fieldpath.Pave(c.Object).SetValue("spec.compositionUpdatePolicy", p)
|
||||
path := "spec.crossplane.compositionUpdatePolicy"
|
||||
if c.Schema == SchemaLegacy {
|
||||
path = "spec.compositionUpdatePolicy"
|
||||
}
|
||||
|
||||
_ = fieldpath.Pave(c.Object).SetValue(path, p)
|
||||
}
|
||||
|
||||
// GetCompositionUpdatePolicy of this Composite resource.
|
||||
// GetCompositionUpdatePolicy of this composite resource.
|
||||
func (c *Unstructured) GetCompositionUpdatePolicy() *xpv1.UpdatePolicy {
|
||||
p, err := fieldpath.Pave(c.Object).GetString("spec.compositionUpdatePolicy")
|
||||
path := "spec.crossplane.compositionUpdatePolicy"
|
||||
if c.Schema == SchemaLegacy {
|
||||
path = "spec.compositionUpdatePolicy"
|
||||
}
|
||||
|
||||
p, err := fieldpath.Pave(c.Object).GetString(path)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -141,8 +215,13 @@ func (c *Unstructured) GetCompositionUpdatePolicy() *xpv1.UpdatePolicy {
|
|||
return &out
|
||||
}
|
||||
|
||||
// GetClaimReference of this Composite resource.
|
||||
// GetClaimReference of this composite resource.
|
||||
func (c *Unstructured) GetClaimReference() *reference.Claim {
|
||||
// Only legacy XRs support claims.
|
||||
if c.Schema != SchemaLegacy {
|
||||
return nil
|
||||
}
|
||||
|
||||
out := &reference.Claim{}
|
||||
if err := fieldpath.Pave(c.Object).GetValueInto("spec.claimRef", out); err != nil {
|
||||
return nil
|
||||
|
@ -150,20 +229,35 @@ func (c *Unstructured) GetClaimReference() *reference.Claim {
|
|||
return out
|
||||
}
|
||||
|
||||
// SetClaimReference of this Composite resource.
|
||||
// SetClaimReference of this composite resource.
|
||||
func (c *Unstructured) SetClaimReference(ref *reference.Claim) {
|
||||
// Only legacy XRs support claims.
|
||||
if c.Schema != SchemaLegacy {
|
||||
return
|
||||
}
|
||||
|
||||
_ = fieldpath.Pave(c.Object).SetValue("spec.claimRef", ref)
|
||||
}
|
||||
|
||||
// GetResourceReferences of this Composite resource.
|
||||
// GetResourceReferences of this composite resource.
|
||||
func (c *Unstructured) GetResourceReferences() []corev1.ObjectReference {
|
||||
path := "spec.crossplane.resourceRefs"
|
||||
if c.Schema == SchemaLegacy {
|
||||
path = "spec.resourceRefs"
|
||||
}
|
||||
|
||||
out := &[]corev1.ObjectReference{}
|
||||
_ = fieldpath.Pave(c.Object).GetValueInto("spec.resourceRefs", out)
|
||||
_ = fieldpath.Pave(c.Object).GetValueInto(path, out)
|
||||
return *out
|
||||
}
|
||||
|
||||
// SetResourceReferences of this Composite resource.
|
||||
// SetResourceReferences of this composite resource.
|
||||
func (c *Unstructured) SetResourceReferences(refs []corev1.ObjectReference) {
|
||||
path := "spec.crossplane.resourceRefs"
|
||||
if c.Schema == SchemaLegacy {
|
||||
path = "spec.resourceRefs"
|
||||
}
|
||||
|
||||
empty := corev1.ObjectReference{}
|
||||
filtered := make([]corev1.ObjectReference, 0, len(refs))
|
||||
for _, ref := range refs {
|
||||
|
@ -174,20 +268,35 @@ func (c *Unstructured) SetResourceReferences(refs []corev1.ObjectReference) {
|
|||
}
|
||||
filtered = append(filtered, ref)
|
||||
}
|
||||
_ = fieldpath.Pave(c.Object).SetValue("spec.resourceRefs", filtered)
|
||||
_ = fieldpath.Pave(c.Object).SetValue(path, filtered)
|
||||
}
|
||||
|
||||
// GetReference returns reference to this composite.
|
||||
func (c *Unstructured) GetReference() *reference.Composite {
|
||||
return &reference.Composite{
|
||||
ref := &reference.Composite{
|
||||
APIVersion: c.GetAPIVersion(),
|
||||
Kind: c.GetKind(),
|
||||
Name: c.GetName(),
|
||||
}
|
||||
|
||||
if c.GetNamespace() != "" {
|
||||
ref.Namespace = ptr.To(c.GetNamespace())
|
||||
}
|
||||
|
||||
return ref
|
||||
}
|
||||
|
||||
// GetWriteConnectionSecretToReference of this Composite resource.
|
||||
// TODO(negz): Ideally we'd use LocalSecretReference for namespaced XRs. As is
|
||||
// we'll return a SecretReference with an empty namespace if the XR doesn't
|
||||
// actually have a spec.crossplane.writeConnectionSecretToRef.namespace field.
|
||||
|
||||
// GetWriteConnectionSecretToReference of this composite resource.
|
||||
func (c *Unstructured) GetWriteConnectionSecretToReference() *xpv1.SecretReference {
|
||||
// Only legacy XRs support connection secrets.
|
||||
if c.Schema != SchemaLegacy {
|
||||
return nil
|
||||
}
|
||||
|
||||
out := &xpv1.SecretReference{}
|
||||
if err := fieldpath.Pave(c.Object).GetValueInto("spec.writeConnectionSecretToRef", out); err != nil {
|
||||
return nil
|
||||
|
@ -195,26 +304,17 @@ func (c *Unstructured) GetWriteConnectionSecretToReference() *xpv1.SecretReferen
|
|||
return out
|
||||
}
|
||||
|
||||
// SetWriteConnectionSecretToReference of this Composite resource.
|
||||
// SetWriteConnectionSecretToReference of this composite resource.
|
||||
func (c *Unstructured) SetWriteConnectionSecretToReference(ref *xpv1.SecretReference) {
|
||||
// Only legacy XRs support connection secrets.
|
||||
if c.Schema != SchemaLegacy {
|
||||
return
|
||||
}
|
||||
|
||||
_ = fieldpath.Pave(c.Object).SetValue("spec.writeConnectionSecretToRef", ref)
|
||||
}
|
||||
|
||||
// GetPublishConnectionDetailsTo of this Composite resource.
|
||||
func (c *Unstructured) GetPublishConnectionDetailsTo() *xpv1.PublishConnectionDetailsTo {
|
||||
out := &xpv1.PublishConnectionDetailsTo{}
|
||||
if err := fieldpath.Pave(c.Object).GetValueInto("spec.publishConnectionDetailsTo", out); err != nil {
|
||||
return nil
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// SetPublishConnectionDetailsTo of this Composite resource.
|
||||
func (c *Unstructured) SetPublishConnectionDetailsTo(ref *xpv1.PublishConnectionDetailsTo) {
|
||||
_ = fieldpath.Pave(c.Object).SetValue("spec.publishConnectionDetailsTo", ref)
|
||||
}
|
||||
|
||||
// GetCondition of this Composite resource.
|
||||
// GetCondition of this composite resource.
|
||||
func (c *Unstructured) GetCondition(ct xpv1.ConditionType) xpv1.Condition {
|
||||
conditioned := xpv1.ConditionedStatus{}
|
||||
// The path is directly `status` because conditions are inline.
|
||||
|
@ -224,7 +324,7 @@ func (c *Unstructured) GetCondition(ct xpv1.ConditionType) xpv1.Condition {
|
|||
return conditioned.GetCondition(ct)
|
||||
}
|
||||
|
||||
// SetConditions of this Composite resource.
|
||||
// SetConditions of this composite resource.
|
||||
func (c *Unstructured) SetConditions(conditions ...xpv1.Condition) {
|
||||
conditioned := xpv1.ConditionedStatus{}
|
||||
// The path is directly `status` because conditions are inline.
|
||||
|
@ -233,7 +333,7 @@ func (c *Unstructured) SetConditions(conditions ...xpv1.Condition) {
|
|||
_ = fieldpath.Pave(c.Object).SetValue("status.conditions", conditioned.Conditions)
|
||||
}
|
||||
|
||||
// GetConditions of this Composite resource.
|
||||
// GetConditions of this composite resource.
|
||||
func (c *Unstructured) GetConditions() []xpv1.Condition {
|
||||
conditioned := xpv1.ConditionedStatus{}
|
||||
// The path is directly `status` because conditions are inline.
|
||||
|
@ -241,40 +341,28 @@ func (c *Unstructured) GetConditions() []xpv1.Condition {
|
|||
return conditioned.Conditions
|
||||
}
|
||||
|
||||
// GetConnectionDetailsLastPublishedTime of this Composite resource.
|
||||
// GetConnectionDetailsLastPublishedTime of this composite resource.
|
||||
func (c *Unstructured) GetConnectionDetailsLastPublishedTime() *metav1.Time {
|
||||
path := "status.crossplane.connectionDetails.lastPublishedTime"
|
||||
if c.Schema == SchemaLegacy {
|
||||
path = "status.connectionDetails.lastPublishedTime"
|
||||
}
|
||||
|
||||
out := &metav1.Time{}
|
||||
if err := fieldpath.Pave(c.Object).GetValueInto("status.connectionDetails.lastPublishedTime", out); err != nil {
|
||||
if err := fieldpath.Pave(c.Object).GetValueInto(path, out); err != nil {
|
||||
return nil
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// SetConnectionDetailsLastPublishedTime of this Composite resource.
|
||||
// SetConnectionDetailsLastPublishedTime of this composite resource.
|
||||
func (c *Unstructured) SetConnectionDetailsLastPublishedTime(t *metav1.Time) {
|
||||
_ = fieldpath.Pave(c.Object).SetValue("status.connectionDetails.lastPublishedTime", t)
|
||||
}
|
||||
|
||||
// GetEnvironmentConfigReferences of this Composite resource.
|
||||
func (c *Unstructured) GetEnvironmentConfigReferences() []corev1.ObjectReference {
|
||||
out := &[]corev1.ObjectReference{}
|
||||
_ = fieldpath.Pave(c.Object).GetValueInto("spec.environmentConfigRefs", out)
|
||||
return *out
|
||||
}
|
||||
|
||||
// SetEnvironmentConfigReferences of this Composite resource.
|
||||
func (c *Unstructured) SetEnvironmentConfigReferences(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. :)
|
||||
// TODO(muvaf): temporary workaround.
|
||||
if ref.String() == empty.String() {
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, ref)
|
||||
path := "status.crossplane.connectionDetails.lastPublishedTime"
|
||||
if c.Schema == SchemaLegacy {
|
||||
path = "status.connectionDetails.lastPublishedTime"
|
||||
}
|
||||
_ = fieldpath.Pave(c.Object).SetValue("spec.environmentConfigRefs", filtered)
|
||||
|
||||
_ = fieldpath.Pave(c.Object).SetValue(path, t)
|
||||
}
|
||||
|
||||
// SetObservedGeneration of this composite resource claim.
|
||||
|
@ -292,9 +380,13 @@ func (c *Unstructured) GetObservedGeneration() int64 {
|
|||
return status.GetObservedGeneration()
|
||||
}
|
||||
|
||||
// SetClaimConditionTypes of this Composite resource. You cannot set system
|
||||
// SetClaimConditionTypes of this composite resource. You cannot set system
|
||||
// condition types such as Ready, Synced or Healthy as claim conditions.
|
||||
func (c *Unstructured) SetClaimConditionTypes(in ...xpv1.ConditionType) error {
|
||||
// Only legacy XRs support claims.
|
||||
if c.Schema != SchemaLegacy {
|
||||
return nil
|
||||
}
|
||||
ts := c.GetClaimConditionTypes()
|
||||
m := make(map[xpv1.ConditionType]bool, len(ts))
|
||||
for _, t := range ts {
|
||||
|
@ -315,8 +407,12 @@ func (c *Unstructured) SetClaimConditionTypes(in ...xpv1.ConditionType) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// GetClaimConditionTypes of this Composite resource.
|
||||
// GetClaimConditionTypes of this composite resource.
|
||||
func (c *Unstructured) GetClaimConditionTypes() []xpv1.ConditionType {
|
||||
// Only legacy XRs support claims.
|
||||
if c.Schema != SchemaLegacy {
|
||||
return nil
|
||||
}
|
||||
cs := []xpv1.ConditionType{}
|
||||
_ = fieldpath.Pave(c.Object).GetValueInto("status.claimConditionTypes", &cs)
|
||||
return cs
|
||||
|
|
|
@ -96,7 +96,7 @@ func TestConditions(t *testing.T) {
|
|||
},
|
||||
"WeirdStatus": {
|
||||
reason: "It should not be possible to set a condition when status is not an object.",
|
||||
u: &Unstructured{unstructured.Unstructured{Object: map[string]any{
|
||||
u: &Unstructured{Unstructured: unstructured.Unstructured{Object: map[string]any{
|
||||
"status": "wat",
|
||||
}}},
|
||||
set: []xpv1.Condition{xpv1.Available()},
|
||||
|
@ -106,7 +106,7 @@ func TestConditions(t *testing.T) {
|
|||
},
|
||||
"WeirdStatusConditions": {
|
||||
reason: "Conditions should be overwritten if they are not an object.",
|
||||
u: &Unstructured{unstructured.Unstructured{Object: map[string]any{
|
||||
u: &Unstructured{Unstructured: unstructured.Unstructured{Object: map[string]any{
|
||||
"status": map[string]any{
|
||||
"conditions": "wat",
|
||||
},
|
||||
|
@ -145,7 +145,7 @@ func TestClaimConditionTypes(t *testing.T) {
|
|||
}{
|
||||
"CannotSetSystemConditionTypes": {
|
||||
reason: "Claim conditions API should fail to set conditions if a system condition is detected.",
|
||||
u: New(),
|
||||
u: New(WithSchema(SchemaLegacy)),
|
||||
set: []xpv1.ConditionType{
|
||||
xpv1.ConditionType("DatabaseReady"),
|
||||
xpv1.ConditionType("NetworkReady"),
|
||||
|
@ -157,37 +157,43 @@ func TestClaimConditionTypes(t *testing.T) {
|
|||
},
|
||||
"SetSingleCustomConditionType": {
|
||||
reason: "Claim condition API should work with a single custom condition type.",
|
||||
u: New(),
|
||||
u: New(WithSchema(SchemaLegacy)),
|
||||
set: []xpv1.ConditionType{xpv1.ConditionType("DatabaseReady")},
|
||||
want: []xpv1.ConditionType{xpv1.ConditionType("DatabaseReady")},
|
||||
},
|
||||
"SetMultipleCustomConditionTypes": {
|
||||
reason: "Claim condition API should work with multiple custom condition types.",
|
||||
u: New(),
|
||||
u: New(WithSchema(SchemaLegacy)),
|
||||
set: []xpv1.ConditionType{xpv1.ConditionType("DatabaseReady"), xpv1.ConditionType("NetworkReady")},
|
||||
want: []xpv1.ConditionType{xpv1.ConditionType("DatabaseReady"), xpv1.ConditionType("NetworkReady")},
|
||||
},
|
||||
"SetMultipleOfTheSameCustomConditionTypes": {
|
||||
reason: "Claim condition API not add more than one of the same condition.",
|
||||
u: New(),
|
||||
u: New(WithSchema(SchemaLegacy)),
|
||||
set: []xpv1.ConditionType{xpv1.ConditionType("DatabaseReady"), xpv1.ConditionType("DatabaseReady")},
|
||||
want: []xpv1.ConditionType{xpv1.ConditionType("DatabaseReady")},
|
||||
},
|
||||
"WeirdStatus": {
|
||||
reason: "It should not be possible to set a condition when status is not an object.",
|
||||
u: &Unstructured{unstructured.Unstructured{Object: map[string]any{
|
||||
"status": "wat",
|
||||
}}},
|
||||
u: &Unstructured{
|
||||
Unstructured: unstructured.Unstructured{Object: map[string]any{
|
||||
"status": "wat",
|
||||
}},
|
||||
Schema: SchemaLegacy,
|
||||
},
|
||||
set: []xpv1.ConditionType{xpv1.ConditionType("DatabaseReady")},
|
||||
want: []xpv1.ConditionType{},
|
||||
},
|
||||
"WeirdStatusClaimConditionTypes": {
|
||||
reason: "Claim conditions should be overwritten if they are not an object.",
|
||||
u: &Unstructured{unstructured.Unstructured{Object: map[string]any{
|
||||
"status": map[string]any{
|
||||
"claimConditionTypes": "wat",
|
||||
},
|
||||
}}},
|
||||
u: &Unstructured{
|
||||
Unstructured: unstructured.Unstructured{Object: map[string]any{
|
||||
"status": map[string]any{
|
||||
"claimConditionTypes": "wat",
|
||||
},
|
||||
}},
|
||||
Schema: SchemaLegacy,
|
||||
},
|
||||
set: []xpv1.ConditionType{xpv1.ConditionType("DatabaseReady")},
|
||||
want: []xpv1.ConditionType{xpv1.ConditionType("DatabaseReady")},
|
||||
},
|
||||
|
@ -341,7 +347,7 @@ func TestClaimReference(t *testing.T) {
|
|||
want *reference.Claim
|
||||
}{
|
||||
"NewRef": {
|
||||
u: New(),
|
||||
u: New(WithSchema(SchemaLegacy)),
|
||||
set: ref,
|
||||
want: ref,
|
||||
},
|
||||
|
@ -391,7 +397,7 @@ func TestWriteConnectionSecretToReference(t *testing.T) {
|
|||
want *xpv1.SecretReference
|
||||
}{
|
||||
"NewRef": {
|
||||
u: New(),
|
||||
u: New(WithSchema(SchemaLegacy)),
|
||||
set: ref,
|
||||
want: ref,
|
||||
},
|
||||
|
|
|
@ -46,6 +46,9 @@ type Composite struct {
|
|||
|
||||
// Name of the referenced composite.
|
||||
Name string `json:"name"`
|
||||
|
||||
// Namespace of the referenced composite.
|
||||
Namespace *string `json:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
// GroupVersionKind returns the GroupVersionKind of the claim reference.
|
||||
|
|
Loading…
Reference in New Issue