Skip to content
Open
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
1 change: 1 addition & 0 deletions bundle/manifests/operator.openshift.io_certmanagers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,7 @@ spec:
- TraceAll
type: string
managementState:
default: Managed
description: managementState indicates whether and how the operator
should manage the component
pattern: ^(Managed|Unmanaged|Force|Removed)$
Expand Down
1 change: 1 addition & 0 deletions config/crd/bases/operator.openshift.io_certmanagers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,7 @@ spec:
- TraceAll
type: string
managementState:
default: Managed
description: managementState indicates whether and how the operator
should manage the component
pattern: ^(Managed|Unmanaged|Force|Removed)$
Expand Down
1 change: 1 addition & 0 deletions config/crd/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ resources:
#+kubebuilder:scaffold:crdkustomizeresource

patchesStrategicMerge:
- patches/managementstate_default_in_certmanagers.yaml
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
# patches here are for enabling the conversion webhook for each CRD
#- patches/webhook_in_certmanagers.yaml
Expand Down
14 changes: 14 additions & 0 deletions config/crd/patches/managementstate_default_in_certmanagers.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: certmanagers.operator.openshift.io
spec:
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
properties:
spec:
properties:
managementState:
default: Managed
16 changes: 14 additions & 2 deletions pkg/operator/operatorclient/operatorclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
operatorv1 "github.com/openshift/api/operator/v1"
applyoperatorv1 "github.com/openshift/client-go/operator/applyconfigurations/operator/v1"
"github.com/openshift/library-go/pkg/apiserver/jsonpatch"
"github.com/openshift/library-go/pkg/operator/management"
"github.com/openshift/library-go/pkg/operator/v1helpers"

"github.com/openshift/cert-manager-operator/api/operator/v1alpha1"
Expand Down Expand Up @@ -140,7 +141,7 @@ func (c OperatorClient) GetOperatorState() (*operatorv1.OperatorSpec, *operatorv
return nil, nil, "", err
}

return &instance.Spec.OperatorSpec, &instance.Status.OperatorStatus, instance.ResourceVersion, nil
return operatorSpecForReconcile(&instance.Spec.OperatorSpec), &instance.Status.OperatorStatus, instance.ResourceVersion, nil
}

func (c OperatorClient) GetOperatorStateWithQuorum(ctx context.Context) (*operatorv1.OperatorSpec, *operatorv1.OperatorStatus, string, error) {
Expand All @@ -149,7 +150,18 @@ func (c OperatorClient) GetOperatorStateWithQuorum(ctx context.Context) (*operat
return nil, nil, "", err
}

return &instance.Spec.OperatorSpec, &instance.Status.OperatorStatus, instance.ResourceVersion, nil
return operatorSpecForReconcile(&instance.Spec.OperatorSpec), &instance.Status.OperatorStatus, instance.ResourceVersion, nil
}

// operatorSpecForReconcile returns a copy of spec with unknown managementState treated as Managed.
// GitOps tools such as Argo CD often create CertManager without managementState; library-go static
// resource controllers already proceed in that case, but deployment controllers require Managed.
func operatorSpecForReconcile(spec *operatorv1.OperatorSpec) *operatorv1.OperatorSpec {
reconcileSpec := spec.DeepCopy()
if management.IsOperatorUnknownState(reconcileSpec.ManagementState) {
reconcileSpec.ManagementState = operatorv1.Managed
}
return reconcileSpec
}

func GetUnsupportedConfigOverrides(operatorSpec *operatorv1.OperatorSpec) (*v1alpha1.UnsupportedConfigOverrides, error) {
Expand Down
98 changes: 98 additions & 0 deletions pkg/operator/operatorclient/operatorclient_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package operatorclient

import (
"context"
"testing"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/tools/cache"
"k8s.io/utils/clock"

operatorv1 "github.com/openshift/api/operator/v1"
"github.com/stretchr/testify/require"

"github.com/openshift/cert-manager-operator/api/operator/v1alpha1"
"github.com/openshift/cert-manager-operator/pkg/operator/clientset/versioned/fake"
certmanoperatorinformers "github.com/openshift/cert-manager-operator/pkg/operator/informers/externalversions"
)

func TestGetOperatorStateDefaultsUnknownManagementStateToManaged(t *testing.T) {
t.Parallel()

ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)

fakeClient := fake.NewClientset(&v1alpha1.CertManager{
ObjectMeta: metav1.ObjectMeta{Name: "cluster"},
Spec: v1alpha1.CertManagerSpec{
OperatorSpec: operatorv1.OperatorSpec{
LogLevel: operatorv1.Normal,
},
},
})
informers := certmanoperatorinformers.NewSharedInformerFactory(fakeClient, 0)
informer := informers.Operator().V1alpha1().CertManagers()
go informer.Informer().Run(ctx.Done())
require.True(t, cache.WaitForCacheSync(ctx.Done(), informer.Informer().HasSynced))

client := OperatorClient{
Informers: informers,
Client: fakeClient.OperatorV1alpha1(),
Clock: clock.RealClock{},
}

spec, _, _, err := client.GetOperatorState()
require.NoError(t, err)
require.Equal(t, operatorv1.Managed, spec.ManagementState)
}

func TestGetOperatorStatePreservesExplicitManagementState(t *testing.T) {
t.Parallel()

ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)

fakeClient := fake.NewClientset(&v1alpha1.CertManager{
ObjectMeta: metav1.ObjectMeta{Name: "cluster"},
Spec: v1alpha1.CertManagerSpec{
OperatorSpec: operatorv1.OperatorSpec{
ManagementState: operatorv1.Unmanaged,
},
},
})
informers := certmanoperatorinformers.NewSharedInformerFactory(fakeClient, 0)
informer := informers.Operator().V1alpha1().CertManagers()
go informer.Informer().Run(ctx.Done())
require.True(t, cache.WaitForCacheSync(ctx.Done(), informer.Informer().HasSynced))

client := OperatorClient{
Informers: informers,
Client: fakeClient.OperatorV1alpha1(),
Clock: clock.RealClock{},
}

spec, _, _, err := client.GetOperatorState()
require.NoError(t, err)
require.Equal(t, operatorv1.Unmanaged, spec.ManagementState)
}

func TestGetOperatorStateWithQuorumDefaultsUnknownManagementStateToManaged(t *testing.T) {
t.Parallel()

ctx, cancel := context.WithTimeout(context.Background(), wait.ForeverTestTimeout)
t.Cleanup(cancel)

fakeClient := fake.NewClientset(&v1alpha1.CertManager{
ObjectMeta: metav1.ObjectMeta{Name: "cluster"},
Spec: v1alpha1.CertManagerSpec{},
})
client := OperatorClient{
Client: fakeClient.OperatorV1alpha1(),
Clock: clock.RealClock{},
}

spec, _, _, err := client.GetOperatorStateWithQuorum(ctx)
require.NoError(t, err)
require.Equal(t, operatorv1.Managed, spec.ManagementState)
}