Adding a ZTP cluster back to ACM without reinstalling it using a baremetal host override.

Solution Verified - Updated -

Issue

Adding a ZTP cluster imported into ACM into git without a redeployment
With just a few steps in ArgoCD, a cluster that has gone missing can be easily added back into git. This process can be completed without deleting the installation of OpenShift on the baremetal host.

Downloading the Argo binary and logging in via the OpenShift route

First, download and install the ArgoCD binary and login via the route that's been exposed in the openshift-gitops-server namespace. This process will help complete the rest of the steps in this article.

# Pull down the argo CLI client
curl -sSL -o argocd-linux-amd64 \ 
https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64

sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd

rm argocd-linux-amd64

argoPass=$(oc get secret/openshift-gitops-cluster -n openshift-gitops -o \ 
jsonpath='{.data.admin\.password}' | base64 -d)

argoURL=$(oc get route openshift-gitops-server -n openshift-gitops -o \ 
jsonpath='{.spec.host}{"\n"}')

argocd login --insecure --grpc-web $argoURL  --username admin --password \ 
$argoPass

Disable Pruning and AutoSyncing in the Argo Application using the ArgoCD binary

Next, configure the application to not prune the existing CRs before adding them back to the kustomization.yaml file that Argo uses as a source of truth. It is important to make sure that the CRs that have been added back have all of the information that the site-config will generate, this allows Argo to compare the manifests and find a match.

This method uses the ArgoCD binary to set the syncing policy to none application wide. OpenShift does not include the Argo client by default, so it will be downloaded and used to control Argo from the command line.

oc patch -n openshift-gitops  applications.argoproj.io clusters  \
--type='json' -p='[{"op": "replace", "path": "/spec/syncPolicy/automated/prune" \
, "value":false}]'
application.argoproj.io/clusters patched

Alternatively, you can disable auto-syncing for the clusters application


argocd app set clusters --sync-policy none oc get applications -n openshift-gitops clusters -o json | jq .spec { "destination": { "namespace": "clusters-sub", "server": "https://kubernetes.default.svc" }, "project": "ztp-app-project", "source": { "path": "site-configs", "repoURL": "http://jumphost.inbound.example.bos2.lab:3000/kni/faredge-ztp.git", "targetRevision": "master" }, "syncPolicy": { "syncOptions": [ "CreateNamespace=true" ] } }

Prerequisites: existing cluster kubeconfig and custom resource overrides

Two copies of the imported cluster's kubeconfig will be required in the target namespace. One will be used by the hub cluster to issue commands on the spoke, the second will be referenced in the clusterdeployment override in an upcoming step.

NOTE: A copy of the cluster-admin kubeconfig can be obtained in the static pod manifests on the node or can be obtained via a secret in the openshift-kube-apiserver namespace. Also, ensure that there is not a preexisting kubeconfig in the managedcluster namespace before creating the kubeconfig that will be used to import the cluster.

ssh core@zt-sno4 'sudo cp /etc/kubernetes/static-pod-resources/kube-apiserver-certs/secrets/node-kubeconfigs/lb-ext.kubeconfig /home/core/ && sudo chmod o+r /home/core/lb-ext.kubeconfig'
scp core@zt-sno4:/home/core/lb-ext.kubeconfig kubeconfig-zt-sno4.yaml

# or 

oc get secret -n openshift-kube-apiserver node-kubeconfigs -ojson | jq '.data["lb-ext.kubeconfig"]' --raw-output | base64 -d > kubeconfig-zt-sno4.yaml

First, create the YAML for the cluster import.

cat hub-import-secret.yaml
---
apiVersion: v1
kind: Secret
metadata:
  name: auto-import-secret
  namespace: zt-sno4
type: Opaque
stringData:
  autoImportRetry: "5"
  kubeconfig: |
    apiVersion: v1
    kind: Config
    ..raw kubeconfig here..

Next, create the target namespace and both secrets. If the namespace already exists, clear out any existing kubeconfigs that could cause issues.

NOTE: The content of the secret must be "kubeconfig".

oc -n zt-sno4 delete secret zt-sno4-admin-kubeconfig 
oc create ns zt-sno4 
oc create -f hub-import-secret.yaml
oc create secret generic auto-import-secret --from-file=kubeconfig=kubeconfig-zt-sno4.yaml

Now, with pruning and automated synchronization disabled we can verify the existing CRs will match the values supplied in the imported cluster’s site-config. You can view the assisted service CRs in the cluster’s namespace to accomplish this. Create both a baremetalhost and a clusterdeployment override CR to pass into the site-config note the externallyProvisioned section in the baremetalhost and the installed: true in the clusterdeployment. This will prevent it from being reinstalled.

---
apiVersion: metal3.io/v1alpha1
kind: BareMetalHost
metadata:
    name: "{{ .Node.HostName }}"
    namespace: "{{ .Cluster.ClusterName }}"
    annotations:
      argocd.argoproj.io/sync-wave: "1"
      inspect.metal3.io: "{{ .Node.IronicInspect }}"
      bmac.agent-install.openshift.io/hostname: "{{ .Node.HostName }}"
      bmac.agent-install.openshift.io/installer-args: "{{ .Node.InstallerArgs }}"
      bmac.agent-install.openshift.io/ignition-config-overrides: "{{ .Node.IgnitionConfigOverride }}"
      bmac.agent-install.openshift.io/role: "{{ .Node.Role }}"
      baremetalhost.metal3.io/detached: "assisted-service-controller"
    labels:
      infraenvs.agent-install.openshift.io: "{{ .Cluster.ClusterName }}"
spec:
   bootMode: "{{ .Node.BootMode }}"
   externallyProvisioned: true
   bmc:
      address: "{{ .Node.BmcAddress }}"
      disableCertificateVerification: true
      credentialsName: "{{ .Node.BmcCredentialsName.Name }}"
   bootMACAddress: "{{ .Node.BootMACAddress }}"
   automatedCleaningMode: disabled
   online: true
   rootDeviceHints: "{{ .Node.RootDeviceHints }}"
   userData:  "{{ .Node.UserData }}"

---
apiVersion: hive.openshift.io/v1
kind: ClusterDeployment
metadata:
  name: "{{ .Cluster.ClusterName }}"
  namespace: "{{ .Cluster.ClusterName }}"
  annotations:
    argocd.argoproj.io/sync-wave: "1"
spec:
  baseDomain: "{{ .Site.BaseDomain }}"
  installed: true
  clusterInstallRef:
    group: extensions.hive.openshift.io
    kind: AgentClusterInstall
    name: "{{ .Cluster.ClusterName }}"
    version: v1beta1
  clusterName: "{{ .Cluster.ClusterName }}"
  # Override: clusterMetadata
  clusterMetadata:
    adminKubeconfigSecretRef:
      name: zt-sno4-admin-kubeconfig
    clusterID: ""
    infraID: ""
  platform:
    agentBareMetal:
      agentSelector:
        matchLabels:
          cluster-name: "{{ .Cluster.ClusterName }}"
  pullSecretRef:
    name: "{{ .Site.PullSecretRef.Name }}"

Now, add the crTemplates section to the site-config so that the new files are honored. Also verify the tree structure is as follows:

clusterNetwork:
  - cidr: "fd01::/48"
    hostPrefix: 64
machineNetwork:
  - cidr: "2600:52:7:59::/64"
serviceNetwork:
  - "fd02::/112"
networkType: "OVNKubernetes"
additionalNTPSources:
  - "2600:52:7:59::11"
crTemplates:
  BareMetalHost: "BareMetalHostOverride.yaml"
  ClusterDeployment: "ClusterDeploymentOverride.yaml"
# tree
├── BareMetalHostOverride.yaml
├── ClusterDeploymentOverride.yaml
├── hub-import-secret.yaml
├── inbound-example-bos2-lab.yaml
├── kustomization.yaml
└── zt-sno4.yaml

Now, kick off a sync between ArgoCD and what’s being added to git. Use the Argo client we downloaded earlier and be sure to commit the overrides and the site-config additions for “zt-sno4”.

oc get applications.argoproj.io clusters -n openshift-gitops -o json | jq .spec.source
{
  "path": "site-configs",
  "repoURL": "http://jumphost.inbound.example.bos2.lab:3000/kni/faredge-ztp.git",
  "targetRevision": "master"
}

cat ~/git/faredge/site-configs/kustomization.yaml

generators:
# list of all the siteConfig*.yaml exist in the repository
  - zt-sno1-ipv6.yaml
  - zt-sno4.yaml


# Login to OpenShift argo via route
argoPass=$(oc get secret/openshift-gitops-cluster -n openshift-gitops -o \
 jsonpath='{.data.admin\.password}' | base64 -d)

argoURL=$(oc get route openshift-gitops-server -n openshift-gitops -o \
 jsonpath='{.spec.host}{"\n"}')

argocd --insecure --grpc-web $argoURL  --username \ 
admin --password $argoPass

# Sync both policies and clusters
argocd-linux-amd64 app sync policies
argocd-linux-amd64 app sync clusters

Verify the cluster has been added to Argo

Let’s verify the cluster has been added to Argo and is in a healthy state. If for any reason you are missing annotations or labels you can enable Argo’s self healing setting for the application and it will match the existing CRs with what’s in git.

Note: Many of the other fields in the assisted service CRs are immutable and can cause an error in Argo if they are not present.

# Collect a diff between the manifests stored in git and the ones present on the cluster
argocd app diff clusters

..omitted..

# Add any writable settings such as annotations/labels to the CRs in OpenShift

argocd app set clusters --self-heal

# Rerun a sync and verify the application is healthy
argocd app sync clusters

…omitted..

agent.open-cluster-management.io    KlusterletAddonConfig  zt-sno4      zt-sno4                     Synced                  klusterletaddonconfig.agent.open-cluster-management.io/zt-sno4 configured. Warning: resource klusterletaddonconfigs/zt-sno4 is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by  apply.  apply should only be used on resources created declaratively by either  create --save-config or  apply. The missing annotation will be patched automatically.
                                    Namespace                           zt-sno1                     Synced                   
                                    Namespace                           zt-sno4                     Synced                   
cluster.open-cluster-management.io  ManagedCluster                      zt-sno1                     Synced                   
cluster.open-cluster-management.io  ManagedCluster                      zt-sno4                     Synced  

Now, the cluster should be added back to Argo without having a redeployment kicked off. Last, enable automated syncing as the final step.

oc get applications.argoproj.io -A

NAMESPACE          NAME       SYNC STATUS   HEALTH STATUS
openshift-gitops   clusters   Synced        Healthy
openshift-gitops   policies   Synced        Healthy

argocd app set clusters --sync-policy automated

Now, confirm the cluster has been added back and the policies have been processed.

oc get managedcluster zt-sno4
NAME      HUB ACCEPTED   MANAGED CLUSTER URLS                           JOINED   AVAILABLE   AGE
zt-sno4   true           https://api.zt-sno4.inbound.example.bos2.lab:6443   True     True        3d5h

oc --kubeconfig=kubeconfig-zt-sno4.yaml get policies -A

NAMESPACE   NAME                                                           REMEDIATION ACTION   COMPLIANCE STATE   AGE
zt-sno3     ztp-vdu-mb-policies.vdu-mb-22a-config-policy         inform               Compliant          5h42m
zt-sno3     ztp-vdu-mb-policies.vdu-mb-22a-sriov-policy          inform               Compliant          5h42m
zt-sno3     ztp-vdu-mb-policies.vdu-mb-valid-22a                 inform               Compliant          5h42m
zt-sno3     ztp-group-du-sno.group-du-sno-414-prega-config-policy          inform               Compliant          5h42m
zt-sno3     ztp-group-du-sno.group-du-sno-414-prega-cs-config-policy       inform               Compliant          5h42m
zt-sno3     ztp-group-du-sno.group-du-sno-414-prega-subscriptions-policy   inform               Compliant          5h42m

Resources
https://github.com/noseka1/multicluster-management-rhacm-argocd
https://argo-cd.readthedocs.io/en/stable/user-guide/auto_sync/
https://access.redhat.com/documentation/en-us/red_hat_advanced_cluster_management_for_kubernetes/2.5/html-single/clusters/index#importing-the-cluster-manual
https://github.com/openshift/assisted-service/blob/386410998c9bc84a5f7463bd3298884c4aa923be/docs/hive-integration/import-installed-cluster.md#4-copy-the-kubeconfig-from-the-ocp-cluster-into-the-hub

Environment

OpenShift 4.10 and higher
Advanced Cluster Management 2.5 and higher

Subscriber exclusive content

A Red Hat subscription provides unlimited access to our knowledgebase, tools, and much more.

Current Customers and Partners

Log in for full access

Log In

New to Red Hat?

Learn more about Red Hat subscriptions

Using a Red Hat product through a public cloud?

How to access this content