Skip to content

Commit

Permalink
allow precreating ACM resources (#96)
Browse files Browse the repository at this point in the history
* allow precreating ACM resources

* Update docs/ACMRegistration.md

Co-authored-by: Ian Miller <[email protected]>

---------

Co-authored-by: Ian Miller <[email protected]>
  • Loading branch information
loganmc10 and imiller0 authored Sep 8, 2023
1 parent 3fd3ce8 commit b009581
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 8 deletions.
35 changes: 35 additions & 0 deletions docs/ACMRegistration.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,38 @@ oc apply -f /tmp/acm-secret.yaml
```

Now your target cluster has a Secret than will allow it to authenticate to the ACM cluster and register itself. Once the registration succeeds, the secret is deleted from the target cluster.

## Pre-creating the ManagedCluster and (optionally) KlusterletAddonConfig
For use cases where flexible and ongoing control over the `ManagedCluster` and (optionally) the `klusterletAddonConfig` CRs is required you may pre-create these artifacts on the ACM hub cluster prior to relocation. This allows the user to control the lifetime and content (eg custom labels on the ManagedCluster) CRs beyond the initial installation phase.

When these CRs are pre-created for a cluster you can omit the `managedClusterSet` and `klusterletAddonConfig` fields from the relocation CR. In this case, the Service Account that you create only needs permissions to "get" Secrets for the cluster namespace created by the ManagedCluster.

For example (run these commands on your ACM cluster):
```
oc create sa -n multicluster-engine acm-registration-sa
cat << EOF | oc apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-secrets
namespace: <managed-cluster-name>
subjects:
- kind: ServiceAccount
name: acm-registration-sa
namespace: multicluster-engine
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
EOF
```
23 changes: 15 additions & 8 deletions internal/acm/reconcile.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,11 @@ func Reconcile(ctx context.Context, c client.Client, scheme *runtime.Scheme, rel
}

// the acmSecret holds the credentials for the ACM cluster
// these credentials should allow the following:
// Creating ManagedClusters (these are cluster scoped resources)
// Creating KlusterletAddonConfigs (these are namespace scoped resources)
// Getting Secrets (these are namespace scoped resources)
//
// the secret is deleted once registration succeeds
// there are 2 options:
// 1. Have this operator create the ManagedCluster and (optionally) KlusterletAddonConfig.
// In this case, the acmSecret token should have open-cluster-management:managedclusterset:admin:default (ClusterRole) permissions.
// 2. Pre-create the ManagedCluster and (optionally) KlusterletAddonConfig.
// In this case, the acmSecret token should have permissions to "get" Secrets for the namespace created by the ManagedCluster.
acmSecret := &corev1.Secret{}
if err := c.Get(ctx, types.NamespacedName{Name: relocation.Spec.ACMRegistration.ACMSecret.Name, Namespace: relocation.Spec.ACMRegistration.ACMSecret.Namespace}, acmSecret); err != nil {
return err
Expand Down Expand Up @@ -177,18 +176,26 @@ func Reconcile(ctx context.Context, c client.Client, scheme *runtime.Scheme, rel
},
}
if err := acmClient.Create(ctx, managedCluster); err != nil {
if !errors.IsAlreadyExists(err) {
if errors.IsForbidden(err) {
logger.Info("could not create ManagedCluster, proceeding anyway (it may have been pre-created)")
} else if !errors.IsAlreadyExists(err) {
return err
}
}

startTime := time.Now()
logger.Info("getting ACM import secret")
importSecret := &corev1.Secret{}
for {
if err := acmClient.Get(ctx, types.NamespacedName{Name: fmt.Sprintf("%s-import", relocation.Spec.ACMRegistration.ClusterName), Namespace: relocation.Spec.ACMRegistration.ClusterName}, importSecret); err != nil {
// after the ManagedCluster is created, it can take some time for this secret and the RBAC roles to be created
if errors.IsNotFound(err) || errors.IsForbidden(err) {
time.Sleep(time.Second * 10)

// we set a 5 minute timeout in case the ACM import secret can never be pulled
if time.Since(startTime) > time.Minute*5 {
return fmt.Errorf("could not get ACM import secret")
}
continue
}
return err
Expand Down Expand Up @@ -259,7 +266,7 @@ func Reconcile(ctx context.Context, c client.Client, scheme *runtime.Scheme, rel

logger.Info("waiting for Klusterlet to become Available")
// wait for the Klusterlet to become Available
startTime := time.Now()
startTime = time.Now()
for {
if checkKlusterlet(ctx, c, relocation, logger) == nil {
return nil
Expand Down

0 comments on commit b009581

Please sign in to comment.