Skip to content

Commit

Permalink
Add support for external references.
Browse files Browse the repository at this point in the history
- Add ReadOnly flag to resource. True indicates an external resource we want to read (no create/update/delete)
- Reuse template  to describe the external resource (gvkn). Reason: we could templatize the name part of the external resource
- Use as much of existing resource reconcile flow as possible. Reason: we can optionally support ReadyWhen and IncludeWhen rules for the external resource
  • Loading branch information
barney-s committed Feb 5, 2025
1 parent b9f0419 commit e4cd30f
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 3 deletions.
5 changes: 4 additions & 1 deletion api/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,11 @@ type Validation struct {
type Resource struct {
// +kubebuilder:validation:Required
ID string `json:"id,omitempty"`
// +kubebuilder:validation:Required
// +kubebuilder:validation:Optional
Template runtime.RawExtension `json:"template,omitempty"`
// ReadOnly indicates an external resource we want to read and use in the Graph
// +kubebuilder:validation:Optional
ReadOnly bool `json:"readOnly,omitempty"`
// +kubebuilder:validation:Optional
ReadyWhen []string `json:"readyWhen,omitempty"`
// +kubebuilder:validation:Optional
Expand Down
5 changes: 4 additions & 1 deletion config/crd/bases/kro.run_resourcegraphdefinitions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ spec:
items:
type: string
type: array
readOnly:
description: ReadOnly indicates an external resource we want
to read and use in the Graph
type: boolean
readyWhen:
items:
type: string
Expand All @@ -88,7 +92,6 @@ spec:
x-kubernetes-preserve-unknown-fields: true
required:
- id
- template
type: object
type: array
schema:
Expand Down
5 changes: 4 additions & 1 deletion helm/crds/kro.run_resourcegraphdefinitions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ spec:
items:
type: string
type: array
readOnly:
description: ReadOnly indicates an external resource we want
to read and use in the Graph
type: boolean
readyWhen:
items:
type: string
Expand All @@ -88,7 +92,6 @@ spec:
x-kubernetes-preserve-unknown-fields: true
required:
- id
- template
type: object
type: array
schema:
Expand Down
12 changes: 12 additions & 0 deletions pkg/controller/instance/controller_reconcile.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,12 @@ func (igr *instanceGraphReconciler) handleResourceReconciliation(
}

resourceState.State = "SYNCED"

// For read-only resources, don't perform updates
if igr.runtime.ResourceDescriptor(resourceID).IsReadOnly() {
return nil
}

return igr.updateResource(ctx, rc, resource, observed, resourceID, resourceState)
}

Expand Down Expand Up @@ -354,6 +360,12 @@ func (igr *instanceGraphReconciler) deleteResourcesInOrder(ctx context.Context)
continue
}

// Skip deletion for read-only resources
if igr.runtime.ResourceDescriptor(resourceID).IsReadOnly() {
igr.state.ResourceStates[resourceID].State = "DELETED"

Check failure on line 365 in pkg/controller/instance/controller_reconcile.go

View workflow job for this annotation

GitHub Actions / lint

string `DELETED` has 3 occurrences, make it a constant (goconst)
continue
}

if err := igr.deleteResource(ctx, resourceID); err != nil {
return err
}
Expand Down
1 change: 1 addition & 0 deletions pkg/graph/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ func (b *Builder) buildRGResource(rgResource *v1alpha1.Resource, namespacedResou
includeWhenExpressions: includeWhen,
namespaced: isNamespaced,
order: order,
readOnly: rgResource.ReadOnly,
}, nil
}

Expand Down
8 changes: 8 additions & 0 deletions pkg/graph/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ type Resource struct {
// order reflects the original order in which the resources were specified,
// and lets us keep the client-specified ordering where the dependencies allow.
order int
// readOnly indicates if the resource should only be read and not created/updated
readOnly bool
}

// GetDependencies returns the dependencies of the resource.
Expand Down Expand Up @@ -164,6 +166,11 @@ func (r *Resource) IsNamespaced() bool {
return r.namespaced
}

// IsReadOnly returns whether the resource is read-only
func (r *Resource) IsReadOnly() bool {
return r.readOnly
}

// DeepCopy returns a deep copy of the resource.
func (r *Resource) DeepCopy() *Resource {
return &Resource{
Expand All @@ -177,5 +184,6 @@ func (r *Resource) DeepCopy() *Resource {
readyWhenExpressions: slices.Clone(r.readyWhenExpressions),
includeWhenExpressions: slices.Clone(r.includeWhenExpressions),
namespaced: r.namespaced,
readOnly: r.readOnly,
}
}
4 changes: 4 additions & 0 deletions pkg/runtime/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ type ResourceDescriptor interface {
// IsNamespaced returns true if the resource is namespaced, and false if it's
// cluster-scoped.
IsNamespaced() bool

// IsReadOnly returns true if the resource is marked as read only
// This is used for external references
IsReadOnly() bool
}

// Resource extends `ResourceDescriptor` to include the actual resource data.
Expand Down
10 changes: 10 additions & 0 deletions pkg/runtime/runtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2613,6 +2613,7 @@ type mockResource struct {
conditions []string
topLevelFields []string
namespaced bool
readOnly bool
obj *unstructured.Unstructured
}

Expand Down Expand Up @@ -2656,6 +2657,10 @@ func (m *mockResource) Unstructured() *unstructured.Unstructured {
return m.obj
}

func (m *mockResource) IsReadOnly() bool {
return m.readOnly
}

type mockResourceOption func(*mockResource)

/* func withGVR(group, version, resource string) mockResourceOption {
Expand Down Expand Up @@ -2686,6 +2691,11 @@ func withReadyExpressions(exprs []string) mockResourceOption {
}
}

func withReadOnly(ro bool) mockResourceOption {

Check failure on line 2694 in pkg/runtime/runtime_test.go

View workflow job for this annotation

GitHub Actions / lint

func `withReadOnly` is unused (unused)
return func(m *mockResource) {
m.readOnly = ro
}
}
func withConditions(conditions []string) mockResourceOption {
return func(m *mockResource) {
m.conditions = conditions
Expand Down

0 comments on commit e4cd30f

Please sign in to comment.