@@ -3,6 +3,7 @@ package managedcluster
3
3
import (
4
4
"context"
5
5
"fmt"
6
+ "time"
6
7
7
8
"github.com/openshift/library-go/pkg/controller/factory"
8
9
"github.com/openshift/library-go/pkg/operator/events"
@@ -12,6 +13,7 @@ import (
12
13
"k8s.io/apimachinery/pkg/api/errors"
13
14
"k8s.io/apimachinery/pkg/api/meta"
14
15
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
16
+ "k8s.io/apimachinery/pkg/types"
15
17
rbacv1informers "k8s.io/client-go/informers/rbac/v1"
16
18
"k8s.io/client-go/kubernetes"
17
19
"k8s.io/klog/v2"
@@ -20,14 +22,20 @@ import (
20
22
informerv1 "open-cluster-management.io/api/client/cluster/informers/externalversions/cluster/v1"
21
23
listerv1 "open-cluster-management.io/api/client/cluster/listers/cluster/v1"
22
24
v1 "open-cluster-management.io/api/cluster/v1"
25
+ ocmfeature "open-cluster-management.io/api/feature"
23
26
"open-cluster-management.io/sdk-go/pkg/patcher"
24
27
25
28
"open-cluster-management.io/ocm/pkg/common/apply"
26
29
"open-cluster-management.io/ocm/pkg/common/queue"
30
+ "open-cluster-management.io/ocm/pkg/features"
27
31
"open-cluster-management.io/ocm/pkg/registration/helpers"
28
32
"open-cluster-management.io/ocm/pkg/registration/hub/manifests"
29
33
)
30
34
35
+ // this is an internal annotation to indicate a managed cluster is already accepted automatically, it is not
36
+ // expected to be changed or removed outside.
37
+ const clusterAcceptedAnnotationKey = "open-cluster-management.io/automatically-accepted-on"
38
+
31
39
var staticFiles = []string {
32
40
"rbac/managedcluster-clusterrole.yaml" ,
33
41
"rbac/managedcluster-clusterrolebinding.yaml" ,
@@ -38,6 +46,7 @@ var staticFiles = []string{
38
46
// managedClusterController reconciles instances of ManagedCluster on the hub.
39
47
type managedClusterController struct {
40
48
kubeClient kubernetes.Interface
49
+ clusterClient clientset.Interface
41
50
clusterLister listerv1.ManagedClusterLister
42
51
applier * apply.PermissionApplier
43
52
patcher patcher.Patcher [* v1.ManagedCluster , v1.ManagedClusterSpec , v1.ManagedClusterStatus ]
@@ -56,6 +65,7 @@ func NewManagedClusterController(
56
65
recorder events.Recorder ) factory.Controller {
57
66
c := & managedClusterController {
58
67
kubeClient : kubeClient ,
68
+ clusterClient : clusterClient ,
59
69
clusterLister : clusterInformer .Lister (),
60
70
applier : apply .NewPermissionApplier (
61
71
kubeClient ,
@@ -103,6 +113,14 @@ func (c *managedClusterController) sync(ctx context.Context, syncCtx factory.Syn
103
113
}
104
114
105
115
if ! managedCluster .Spec .HubAcceptsClient {
116
+ // If the ManagedClusterAutoApproval feature is enabled, we automatically accept a cluster only
117
+ // when it joins for the first time, afterwards users can deny it again.
118
+ if features .HubMutableFeatureGate .Enabled (ocmfeature .ManagedClusterAutoApproval ) {
119
+ if _ , ok := managedCluster .Annotations [clusterAcceptedAnnotationKey ]; ! ok {
120
+ return c .acceptCluster (ctx , managedClusterName )
121
+ }
122
+ }
123
+
106
124
// Current spoke cluster is not accepted, do nothing.
107
125
if ! meta .IsStatusConditionTrue (managedCluster .Status .Conditions , v1 .ManagedClusterConditionHubAccepted ) {
108
126
return nil
@@ -199,3 +217,13 @@ func (c *managedClusterController) removeManagedClusterResources(ctx context.Con
199
217
}
200
218
return operatorhelpers .NewMultiLineAggregate (errs )
201
219
}
220
+
221
+ func (c * managedClusterController ) acceptCluster (ctx context.Context , managedClusterName string ) error {
222
+ // TODO support patching both annotations and spec simultaneously in the patcher
223
+ acceptedTime := time .Now ()
224
+ patch := fmt .Sprintf (`{"metadata":{"annotations":{"%s":"%s"}},"spec":{"hubAcceptsClient":true}}` ,
225
+ clusterAcceptedAnnotationKey , acceptedTime .Format (time .RFC3339 ))
226
+ _ , err := c .clusterClient .ClusterV1 ().ManagedClusters ().Patch (ctx , managedClusterName ,
227
+ types .MergePatchType , []byte (patch ), metav1.PatchOptions {})
228
+ return err
229
+ }
0 commit comments