Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion cmd/object-controller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,10 @@ func newManager(cfg *config, restConfig *rest.Config) (manager.Manager, error) {
RenewDeadline: ptr.To(107 * time.Second),
RetryPeriod: ptr.To(26 * time.Second),
Cache: cache.Options{
ByObject: map[client.Object]cache.ByObject{&ocv1.ClusterObjectSet{}: {}},
ByObject: map[client.Object]cache.ByObject{
&ocv1.ClusterObjectSet{}: {},
&ocv1.ClusterObjectDeployment{}: {},
},
ReaderFailOnMissingInformer: true,
DefaultTransform: cacheutil.StripAnnotations(),
},
Expand Down Expand Up @@ -197,6 +200,11 @@ func newManager(cfg *config, restConfig *rest.Config) (manager.Manager, error) {
}).SetupWithManager(mgr); err != nil {
return nil, fmt.Errorf("setting up ClusterObjectSet controller: %w", err)
}
if err := (&controllers.ClusterObjectDeploymentReconciler{
Client: mgr.GetClient(),
}).SetupWithManager(mgr); err != nil {
return nil, fmt.Errorf("setting up ClusterObjectDeployment controller: %w", err)
}
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
return nil, err
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{{- if include "objectController.enabled" . }}
{{ tpl (.Files.Get "base/object-controller/crd/experimental/olm.operatorframework.io_clusterobjectdeployments.yaml") . }}
{{- end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//go:build !standard

package controllers

import (
"context"

"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/predicate"

ocv1 "github.com/operator-framework/operator-controller/api/v1"
)

// ClusterObjectDeploymentReconciler reconciles ClusterObjectDeployment objects by
// managing their owned ClusterObjectSet revisions.
//
// This is a skeleton: it does not yet implement any reconciliation behavior.
type ClusterObjectDeploymentReconciler struct {
Client client.Client
}

//+kubebuilder:rbac:groups=olm.operatorframework.io,resources=clusterobjectdeployments,verbs=get;list;watch;update;patch;create;delete
//+kubebuilder:rbac:groups=olm.operatorframework.io,resources=clusterobjectdeployments/status,verbs=update;patch
//+kubebuilder:rbac:groups=olm.operatorframework.io,resources=clusterobjectdeployments/finalizers,verbs=update
//+kubebuilder:rbac:groups=olm.operatorframework.io,resources=clusterobjectsets,verbs=get;list;watch;update;patch;create;delete

func (c *ClusterObjectDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
l := log.FromContext(ctx).WithName("cluster-object-deployment")
ctx = log.IntoContext(ctx, l)

existingDeployment := &ocv1.ClusterObjectDeployment{}
if err := c.Client.Get(ctx, req.NamespacedName, existingDeployment); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}

l.Info("reconcile starting")
defer l.Info("reconcile ending")

// No reconciliation behavior yet. This skeleton establishes the controller,
// its watches, and its RBAC so that behavior can be layered on in follow-ups.

return ctrl.Result{}, nil
}

func (c *ClusterObjectDeploymentReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(
&ocv1.ClusterObjectDeployment{},
builder.WithPredicates(
predicate.ResourceVersionChangedPredicate{},
),
).
Owns(
&ocv1.ClusterObjectSet{},
builder.WithPredicates(
predicate.ResourceVersionChangedPredicate{},
),
).
// A ClusterObjectSet's spec.group matches the name of the ClusterObjectDeployment
// that owns (or should adopt) it. Owns() only enqueues already-owned revisions, so
// this watch additionally surfaces not-yet-adopted (orphan) ClusterObjectSets.
Watches(
&ocv1.ClusterObjectSet{},
handler.EnqueueRequestsFromMapFunc(mapClusterObjectSetToClusterObjectDeployment),
).
Complete(c)
}

// mapClusterObjectSetToClusterObjectDeployment enqueues the ClusterObjectDeployment
// named by a ClusterObjectSet's spec.group.
func mapClusterObjectSetToClusterObjectDeployment(_ context.Context, obj client.Object) []ctrl.Request {
cos, ok := obj.(*ocv1.ClusterObjectSet)
if !ok || cos.Spec.Group == "" {
return nil
}
return []ctrl.Request{{NamespacedName: types.NamespacedName{Name: cos.Spec.Group}}}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//go:build !standard

package controllers

import (
"testing"

"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"

ocv1 "github.com/operator-framework/operator-controller/api/v1"
)

func Test_mapClusterObjectSetToClusterObjectDeployment(t *testing.T) {
for _, tc := range []struct {
name string
obj client.Object
want []ctrl.Request
}{
{
name: "maps spec.group to a ClusterObjectDeployment request",
obj: &ocv1.ClusterObjectSet{
ObjectMeta: metav1.ObjectMeta{Name: "cod-1-1"},
Spec: ocv1.ClusterObjectSetSpec{Group: "cod-1"},
},
want: []ctrl.Request{{NamespacedName: types.NamespacedName{Name: "cod-1"}}},
},
{
name: "returns nil when spec.group is empty",
obj: &ocv1.ClusterObjectSet{
ObjectMeta: metav1.ObjectMeta{Name: "cod-1-1"},
},
want: nil,
},
{
name: "returns nil for a non-ClusterObjectSet object",
obj: &ocv1.ClusterObjectDeployment{ObjectMeta: metav1.ObjectMeta{Name: "cod-1"}},
want: nil,
},
} {
t.Run(tc.name, func(t *testing.T) {
got := mapClusterObjectSetToClusterObjectDeployment(t.Context(), tc.obj)
require.Equal(t, tc.want, got)
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//go:build !standard

package controllers_test

import (
"testing"

"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"

ocv1 "github.com/operator-framework/operator-controller/api/v1"
"github.com/operator-framework/operator-controller/internal/object-controller/controllers"
)

const clusterObjectDeploymentName = "test-cod-1"

func Test_ClusterObjectDeploymentReconciler_Reconcile(t *testing.T) {
testScheme := newScheme(t)

for _, tc := range []struct {
name string
existingObjs []client.Object
}{
{
name: "returns no error when the ClusterObjectDeployment does not exist",
existingObjs: nil,
},
{
name: "returns no error for an existing ClusterObjectDeployment",
existingObjs: []client.Object{
&ocv1.ClusterObjectDeployment{
ObjectMeta: metav1.ObjectMeta{Name: clusterObjectDeploymentName},
},
},
},
} {
t.Run(tc.name, func(t *testing.T) {
testClient := fake.NewClientBuilder().
WithScheme(testScheme).
WithStatusSubresource(&ocv1.ClusterObjectDeployment{}).
WithObjects(tc.existingObjs...).
Build()

result, err := (&controllers.ClusterObjectDeploymentReconciler{
Client: testClient,
}).Reconcile(t.Context(), ctrl.Request{
NamespacedName: types.NamespacedName{
Name: clusterObjectDeploymentName,
},
})

require.NoError(t, err)
require.Equal(t, ctrl.Result{}, result)
})
}
}
5 changes: 4 additions & 1 deletion internal/object-controller/scheme/scheme.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ func init() {
utilruntime.Must(clientgoscheme.AddToScheme(Scheme))
utilruntime.Must(apiextensionsv1.AddToScheme(Scheme))
// Object management does not require the ClusterExtension or ClusterCatalog APIs.
Scheme.AddKnownTypes(ocv1.GroupVersion, &ocv1.ClusterObjectSet{}, &ocv1.ClusterObjectSetList{})
Scheme.AddKnownTypes(ocv1.GroupVersion,
&ocv1.ClusterObjectSet{}, &ocv1.ClusterObjectSetList{},
&ocv1.ClusterObjectDeployment{}, &ocv1.ClusterObjectDeploymentList{},
)
metav1.AddToGroupVersion(Scheme, ocv1.GroupVersion)
}
Loading
Loading