Skip to content

Commit

Permalink
Envtest based tests for controller watch changes
Browse files Browse the repository at this point in the history
  • Loading branch information
ebaron committed Jun 8, 2023
1 parent 084d877 commit d4a0485
Show file tree
Hide file tree
Showing 12 changed files with 431 additions and 69 deletions.
13 changes: 8 additions & 5 deletions internal/controllers/clustercryostat_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,16 @@ type ClusterCryostatReconciler struct {
*ReconcilerConfig
}

func NewClusterCryostatReconciler(config *ReconcilerConfig) *ClusterCryostatReconciler {
func NewClusterCryostatReconciler(config *ReconcilerConfig) (*ClusterCryostatReconciler, error) {
delegate, err := newReconciler(config, &operatorv1beta1.ClusterCryostat{},
&operatorv1beta1.ClusterCryostatList{}, false)
if err != nil {
return nil, err
}
return &ClusterCryostatReconciler{
ReconcilerConfig: config,
delegate: &Reconciler{
ReconcilerConfig: config,
},
}
delegate: delegate,
}, nil
}

// +kubebuilder:rbac:groups="",resources=pods;services;services/finalizers;endpoints;persistentvolumeclaims;events;configmaps;secrets;serviceaccounts,verbs=*
Expand Down
2 changes: 1 addition & 1 deletion internal/controllers/clustercryostat_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,6 @@ func (t *cryostatTestInput) expectTargetNamespaces() {
Expect(*cr.TargetNamespaceStatus).To(ConsistOf(t.TargetNamespaces))
}

func newClusterCryostatController(config *controllers.ReconcilerConfig) controllers.CommonReconciler {
func newClusterCryostatController(config *controllers.ReconcilerConfig) (controllers.CommonReconciler, error) {
return controllers.NewClusterCryostatReconciler(config)
}
5 changes: 3 additions & 2 deletions internal/controllers/common/common_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import (
"strings"
"time"

"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
logf "sigs.k8s.io/controller-runtime/pkg/log"
)
Expand Down Expand Up @@ -84,9 +85,9 @@ func (o *defaultOSUtils) GenPasswd(length int) string {

// ClusterUniqueName returns a name for cluster-scoped objects that is
// uniquely identified by a namespace and name.
func ClusterUniqueName(kind string, name string, namespace string) string {
func ClusterUniqueName(gvk *schema.GroupVersionKind, name string, namespace string) string {
// Use the SHA256 checksum of the namespaced name as a suffix
nn := types.NamespacedName{Namespace: namespace, Name: name}
suffix := fmt.Sprintf("%x", sha256.Sum256([]byte(nn.String())))
return strings.ToLower(kind) + "-" + suffix
return strings.ToLower(gvk.Kind) + "-" + suffix
}
13 changes: 8 additions & 5 deletions internal/controllers/cryostat_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,16 @@ type CryostatReconciler struct {
*ReconcilerConfig
}

func NewCryostatReconciler(config *ReconcilerConfig) *CryostatReconciler {
func NewCryostatReconciler(config *ReconcilerConfig) (*CryostatReconciler, error) {
delegate, err := newReconciler(config, &operatorv1beta1.Cryostat{},
&operatorv1beta1.CryostatList{}, true)
if err != nil {
return nil, err
}
return &CryostatReconciler{
ReconcilerConfig: config,
delegate: &Reconciler{
ReconcilerConfig: config,
},
}
delegate: delegate,
}, nil
}

// +kubebuilder:rbac:groups=operator.cryostat.io,resources=cryostats,verbs=*
Expand Down
2 changes: 1 addition & 1 deletion internal/controllers/cryostat_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,6 @@ var _ = Describe("CryostatController", func() {
c.commonTests()
})

func newCryostatController(config *controllers.ReconcilerConfig) controllers.CommonReconciler {
func newCryostatController(config *controllers.ReconcilerConfig) (controllers.CommonReconciler, error) {
return controllers.NewCryostatReconciler(config)
}
10 changes: 5 additions & 5 deletions internal/controllers/openshift.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,26 +76,25 @@ func (r *Reconciler) finalizeOpenShift(ctx context.Context, cr *model.CryostatIn
return nil
}
reqLogger := r.Log.WithValues("Request.Namespace", cr.InstallNamespace, "Request.Name", cr.Name)
err := r.deleteConsoleLink(ctx, newConsoleLink(cr), reqLogger)
err := r.deleteConsoleLink(ctx, r.newConsoleLink(cr), reqLogger)
if err != nil {
return err
}
return r.deleteCorsAllowedOrigins(ctx, cr)
}

func newConsoleLink(cr *model.CryostatInstance) *consolev1.ConsoleLink {
func (r *Reconciler) newConsoleLink(cr *model.CryostatInstance) *consolev1.ConsoleLink {
// Cluster scoped, so use a unique name to avoid conflicts
return &consolev1.ConsoleLink{
ObjectMeta: metav1.ObjectMeta{
Name: common.ClusterUniqueName(cr.Object.GetObjectKind().GroupVersionKind().Kind,
cr.Name, cr.InstallNamespace),
Name: common.ClusterUniqueName(r.gvk, cr.Name, cr.InstallNamespace),
},
}
}

func (r *Reconciler) reconcileConsoleLink(ctx context.Context, cr *model.CryostatInstance) error {
reqLogger := r.Log.WithValues("Request.Namespace", cr.InstallNamespace, "Request.Name", cr.Name)
link := newConsoleLink(cr)
link := r.newConsoleLink(cr)

url := cr.Status.ApplicationURL
if len(url) == 0 {
Expand Down Expand Up @@ -250,6 +249,7 @@ func (r *Reconciler) getTokenFromPullSecret(ctx context.Context) (*string, error
return nil, fmt.Errorf("no %s key present in pull secret", corev1.DockerConfigJsonKey)
}

fmt.Println("dockerconfig: " + string(dockerConfigRaw))
// Unmarshal the .dockerconfigjson into a struct
dockerConfig := struct {
Auths map[string]struct {
Expand Down
10 changes: 5 additions & 5 deletions internal/controllers/rbac.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func (r *Reconciler) reconcileRBAC(ctx context.Context, cr *model.CryostatInstan
}

func (r *Reconciler) finalizeRBAC(ctx context.Context, cr *model.CryostatInstance) error {
return r.deleteClusterRoleBinding(ctx, newClusterRoleBinding(cr))
return r.deleteClusterRoleBinding(ctx, r.newClusterRoleBinding(cr))
}

func newServiceAccount(cr *model.CryostatInstance) *corev1.ServiceAccount {
Expand Down Expand Up @@ -172,19 +172,19 @@ func (r *Reconciler) reconcileRoleBinding(ctx context.Context, cr *model.Cryosta
return nil
}

func newClusterRoleBinding(cr *model.CryostatInstance) *rbacv1.ClusterRoleBinding {
func (r *Reconciler) newClusterRoleBinding(cr *model.CryostatInstance) *rbacv1.ClusterRoleBinding {
fmt.Println("CRB KIND: " + r.gvk.Kind) // XXX
return &rbacv1.ClusterRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: common.ClusterUniqueName(cr.Object.GetObjectKind().GroupVersionKind().Kind,
cr.Name, cr.InstallNamespace),
Name: common.ClusterUniqueName(r.gvk, cr.Name, cr.InstallNamespace),
},
}
}

const clusterRoleName = "cryostat-operator-cryostat"

func (r *Reconciler) reconcileClusterRoleBinding(ctx context.Context, cr *model.CryostatInstance) error {
binding := newClusterRoleBinding(cr)
binding := r.newClusterRoleBinding(cr)

sa := newServiceAccount(cr)
subjects := []rbacv1.Subject{
Expand Down
56 changes: 41 additions & 15 deletions internal/controllers/reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ import (
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/tools/record"
ctrl "sigs.k8s.io/controller-runtime"
Expand All @@ -84,9 +85,6 @@ type ReconcilerConfig struct {
IsCertManagerInstalled bool
EventRecorder record.EventRecorder
RESTMapper meta.RESTMapper
ObjectType client.Object
ListType client.ObjectList
IsNamespaced bool
Namespaces []string
common.ReconcilerTLS
}
Expand All @@ -95,11 +93,16 @@ type ReconcilerConfig struct {
// between the ClusterCryostat and Cryostat reconcilers
type CommonReconciler interface {
reconcile.Reconciler
SetupWithManager(mgr ctrl.Manager) error
GetConfig() *ReconcilerConfig
}

type Reconciler struct {
*ReconcilerConfig
objectType client.Object
listType client.ObjectList
isNamespaced bool
gvk *schema.GroupVersionKind
}

// Name used for Finalizer that handles Cryostat deletion
Expand Down Expand Up @@ -146,6 +149,21 @@ var reportsDeploymentConditions = deploymentConditionTypeMap{
operatorv1beta1.ConditionTypeReportsDeploymentReplicaFailure: appsv1.DeploymentReplicaFailure,
}

func newReconciler(config *ReconcilerConfig, objType client.Object, listType client.ObjectList,
isNamespaced bool) (*Reconciler, error) {
gvk, err := apiutil.GVKForObject(objType, config.Scheme)
if err != nil {
return nil, err
}
return &Reconciler{
ReconcilerConfig: config,
objectType: objType,
listType: listType,
isNamespaced: isNamespaced,
gvk: &gvk,
}, nil
}

func (r *Reconciler) reconcileCryostat(ctx context.Context, cr *model.CryostatInstance) (ctrl.Result, error) {
result, err := r.reconcile(ctx, cr)
return result, r.checkConflicts(cr, err)
Expand Down Expand Up @@ -299,17 +317,24 @@ func (r *Reconciler) reconcile(ctx context.Context, cr *model.CryostatInstance)
}

func (r *Reconciler) setupWithManager(mgr ctrl.Manager, impl reconcile.Reconciler) error {
gvk, err := apiutil.GVKForObject(r.ObjectType, mgr.GetScheme())
if err != nil {
return err
}
namespaces := namespacesToSet(r.Namespaces)
c := ctrl.NewControllerManagedBy(mgr).
For(r.ObjectType).
For(r.objectType).
// TODO remove this once only AllNamespace mode is supported
WithEventFilter(predicate.NewPredicateFuncs(func(object client.Object) bool {
// Restrict watch for CRs to specified namespaces
if object.GetObjectKind().GroupVersionKind().GroupKind() == gvk.GroupKind() {
// Restrict watch for namespaced CRs to specified namespaces
fmt.Println("KIND: " + object.GetObjectKind().GroupVersionKind().GroupKind().String()) // XXX
gk := object.GetObjectKind().GroupVersionKind().GroupKind()
if gk.Empty() {
gvk, err := apiutil.GVKForObject(object, mgr.GetScheme())
if err != nil {
r.Log.Info("failed to find GVK for %T %s/%s", object, object.GetNamespace(), object.GetName())
return false
}
gk = gvk.GroupKind()
fmt.Println("KIND after lookup: " + gvk.GroupKind().String()) // XXX
}
if gk == r.gvk.GroupKind() && len(object.GetNamespace()) > 0 {
_, pres := namespaces[object.GetNamespace()]
if !pres {
return false
Expand Down Expand Up @@ -613,18 +638,19 @@ func mergeLabelsAndAnnotations(dest *metav1.ObjectMeta, srcLabels, srcAnnotation

func (r *Reconciler) findObjectsForPullSecret(secret client.Object) []reconcile.Request {
if secret.GetNamespace() != "openshift-config" || secret.GetName() != "pull-secret" {
fmt.Printf("GOT SECRET %s/%s\n", secret.GetNamespace(), secret.GetName())
return nil
}
namespaces := []string{""}
if r.IsNamespaced {
if r.isNamespaced {
namespaces = r.Namespaces
}

result := []reconcile.Request{}
for _, namespace := range namespaces {
instanceList, ok := r.ListType.DeepCopyObject().(client.ObjectList)
instanceList, ok := r.listType.DeepCopyObject().(client.ObjectList)
if !ok {
r.Log.Error(fmt.Errorf("type %T is not an ObjectList", r.ListType),
r.Log.Error(fmt.Errorf("type %T is not an ObjectList", r.listType),
"could not allocate a list")
return []reconcile.Request{}
}
Expand All @@ -634,7 +660,7 @@ func (r *Reconciler) findObjectsForPullSecret(secret client.Object) []reconcile.
}
err := r.List(context.Background(), instanceList, listOps)
if err != nil {
r.Log.Error(err, "failed to list %T", r.ObjectType, "namespace", namespace)
r.Log.Error(err, "failed to list %T", r.objectType, "namespace", namespace)
return []reconcile.Request{}
}

Expand All @@ -656,7 +682,7 @@ func (r *Reconciler) findObjectsForPullSecret(secret client.Object) []reconcile.
},
}
// XXX
r.Log.Info(fmt.Sprintf("Enqueueing %T %s for pull-secret change", r.ObjectType, types.NamespacedName{Namespace: obj.GetNamespace(), Name: obj.GetName()}.String()))
r.Log.Info(fmt.Sprintf("Enqueueing %T %s for pull-secret change", r.objectType, types.NamespacedName{Namespace: obj.GetNamespace(), Name: obj.GetName()}.String()))
}
result = append(result, requests...)
}
Expand Down
Loading

0 comments on commit d4a0485

Please sign in to comment.