---
title: Disaster recovery for a hosted cluster in AWS
---

# Disaster recovery for a hosted cluster in AWS  {#hcp-disaster-recovery-aws}

You can recover a hosted cluster to the same region within Amazon Web Services (AWS). For example, you need disaster recovery when the upgrade of a management cluster fails and the hosted cluster is in a read-only state.

The disaster recovery process involves the following steps:

1. Backing up the hosted cluster on the source management cluster
2. Restoring the hosted cluster on a destination management cluster
3. Deleting the hosted cluster from the source management cluster

Your workloads remain running during the process. The Cluster API might be unavailable for a period, but that does not affect the services that are running on the worker nodes.

> [!IMPORTANT]
> Both the source management cluster and the destination management cluster must have the `--external-dns` flags to maintain the API server URL. See the following example:
>
> ```terminal {title="Example: External DNS flags"}
> --external-dns-provider=aws \
> --external-dns-credentials=<path_to_aws_credentials_file> \
> --external-dns-domain-filter=<basedomain>
> ```
>
> If you do not include the `--external-dns` flags to maintain the API server URL, you cannot migrate the hosted cluster.

## Overview of the backup and restore process for hosted control planes on AWS {#hcp-backup-restore-aws-overview_hcp-disaster-recovery-aws}

Get familiar with the backup and restore process for hosted control planes on Amazon Web Services (AWS).

The backup and restore process works as follows:

1. On management cluster 1, which you can think of as the source management cluster, the control plane and workers interact by using the external DNS API. The external DNS API is accessible, and a load balancer sits between the management clusters. ![Diagram that shows the workers accessing the external DNS API and the external DNS API pointing to the control plane through a load balancer](/openshift-docs-markdown/images/298_OpenShift_Backup_Restore_0123_00.png)
2. You take a snapshot of the hosted cluster, which includes etcd, the control plane, and the worker nodes. During this process, the worker nodes continue to try to access the external DNS API even if it is not accessible, the workloads are running, the control plane is saved in a local manifest file, and etcd is backed up to an S3 bucket. The data plane is active and the control plane is paused. ![298_OpenShift_Backup_Restore_0123_01](/openshift-docs-markdown/images/298_OpenShift_Backup_Restore_0123_01.png)
3. On management cluster 2, which you can think of as the destination management cluster, you restore etcd from the S3 bucket and restore the control plane from the local manifest file. During this process, the external DNS API is stopped, the hosted cluster API becomes inaccessible, and any workers that use the API are unable to update their manifest files, but the workloads are still running. ![298_OpenShift_Backup_Restore_0123_02](/openshift-docs-markdown/images/298_OpenShift_Backup_Restore_0123_02.png)
4. The external DNS API is accessible again, and the worker nodes use it to move to management cluster 2. The external DNS API can access the load balancer that points to the control plane. ![298_OpenShift_Backup_Restore_0123_03](/openshift-docs-markdown/images/298_OpenShift_Backup_Restore_0123_03.png)
5. On management cluster 2, the control plane and worker nodes interact by using the external DNS API. The resources are deleted from management cluster 1, except for the S3 backup of etcd. If you try to set up the hosted cluster again on management cluster 1, it will not work. ![298_OpenShift_Backup_Restore_0123_04](/openshift-docs-markdown/images/298_OpenShift_Backup_Restore_0123_04.png)

## Backing up a hosted cluster on AWS {#dr-hosted-cluster-within-aws-region-backup_hcp-disaster-recovery-aws}

To recover your hosted cluster in your target management cluster, you first need to back up all of the relevant data.

**Procedure**

1. Create a config map file to declare the source management cluster by entering the following command:

   ```terminal
   $ oc create configmap mgmt-parent-cluster -n default \
     --from-literal=from=${MGMT_CLUSTER_NAME}
   ```
2. Shut down the reconciliation in the hosted cluster and in the node pools by entering the following commands:

   ```terminal
   $ PAUSED_UNTIL="true"
   ```

   ```terminal
   $ oc patch -n ${HC_CLUSTER_NS} hostedclusters/${HC_CLUSTER_NAME} \
     -p '{"spec":{"pausedUntil":"'${PAUSED_UNTIL}'"}}' --type=merge
   ```

   ```terminal
   $ oc patch -n ${HC_CLUSTER_NS} nodepools/${NODEPOOLS} \
     -p '{"spec":{"pausedUntil":"'${PAUSED_UNTIL}'"}}' --type=merge
   ```

   ```terminal
   $ oc scale deployment -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} --replicas=0 \
     kube-apiserver openshift-apiserver openshift-oauth-apiserver control-plane-operator
   ```
3. Back up etcd and upload the data to an S3 bucket by running the following bash script:

   > [!TIP]
   > Wrap this script in a function and call it from the main function.

   ```terminal
   # ETCD Backup
   ETCD_PODS="etcd-0"
   if [ "${CONTROL_PLANE_AVAILABILITY_POLICY}" = "HighlyAvailable" ]; then
     ETCD_PODS="etcd-0 etcd-1 etcd-2"
   fi

   for POD in ${ETCD_PODS}; do
     # Create an etcd snapshot
     oc exec -it ${POD} -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} -- env ETCDCTL_API=3 /usr/bin/etcdctl --cacert /etc/etcd/tls/client/etcd-client-ca.crt --cert /etc/etcd/tls/client/etcd-client.crt --key /etc/etcd/tls/client/etcd-client.key --endpoints=localhost:2379 snapshot save /var/lib/data/snapshot.db
     oc exec -it ${POD} -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} -- env ETCDCTL_API=3 /usr/bin/etcdctl -w table snapshot status /var/lib/data/snapshot.db

     FILEPATH="/${BUCKET_NAME}/${HC_CLUSTER_NAME}-${POD}-snapshot.db"
     CONTENT_TYPE="application/x-compressed-tar"
     DATE_VALUE=`date -R`
     SIGNATURE_STRING="PUT\n\n${CONTENT_TYPE}\n${DATE_VALUE}\n${FILEPATH}"

     set +x
     ACCESS_KEY=$(grep aws_access_key_id ${AWS_CREDS} | head -n1 | cut -d= -f2 | sed "s/ //g")
     SECRET_KEY=$(grep aws_secret_access_key ${AWS_CREDS} | head -n1 | cut -d= -f2 | sed "s/ //g")
     SIGNATURE_HASH=$(echo -en ${SIGNATURE_STRING} | openssl sha1 -hmac "${SECRET_KEY}" -binary | base64)
     set -x

     # FIXME: this is pushing to the OIDC bucket
     oc exec -it etcd-0 -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} -- curl -X PUT -T "/var/lib/data/snapshot.db" \
       -H "Host: ${BUCKET_NAME}.s3.amazonaws.com" \
       -H "Date: ${DATE_VALUE}" \
       -H "Content-Type: ${CONTENT_TYPE}" \
       -H "Authorization: AWS ${ACCESS_KEY}:${SIGNATURE_HASH}" \
       https://${BUCKET_NAME}.s3.amazonaws.com/${HC_CLUSTER_NAME}-${POD}-snapshot.db
   done
   ```

   For more information about backing up etcd, see "Backing up and restoring etcd on a hosted cluster".
4. Back up Kubernetes and OpenShift Container Platform objects by entering the following commands. You need to back up the following objects:

   - `HostedCluster` and `NodePool` objects from the HostedCluster namespace
   - `HostedCluster` secrets from the HostedCluster namespace
   - `HostedControlPlane` from the Hosted Control Plane namespace
   - `Cluster` from the Hosted Control Plane namespace
   - `AWSCluster`, `AWSMachineTemplate`, and `AWSMachine` from the Hosted Control Plane namespace
   - `MachineDeployments`, `MachineSets`, and `Machines` from the Hosted Control Plane namespace
   - `ControlPlane` secrets from the Hosted Control Plane namespace

     1. Enter the following commands:

        ```terminal
        $ mkdir -p ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS} \
          ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}-${HC_CLUSTER_NAME}
        ```

        ```terminal
        $ chmod 700 ${BACKUP_DIR}/namespaces/
        ```
     2. Back up the `HostedCluster` objects from the `HostedCluster` namespace by entering the following commands:

        ```terminal
        $ echo "Backing Up HostedCluster Objects:"
        ```

        ```terminal
        $ oc get hc ${HC_CLUSTER_NAME} -n ${HC_CLUSTER_NS} -o yaml > \
          ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}/hc-${HC_CLUSTER_NAME}.yaml
        ```

        ```terminal
        $ echo "--> HostedCluster"
        ```

        ```terminal
        $ sed -i '' -e '/^status:$/,$d' \
          ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}/hc-${HC_CLUSTER_NAME}.yaml
        ```
     3. Back up the `NodePool` objects from the `HostedCluster` namespace by entering the following commands:

        ```terminal
        $ oc get np ${NODEPOOLS} -n ${HC_CLUSTER_NS} -o yaml > \
          ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}/np-${NODEPOOLS}.yaml
        ```

        ```terminal
        $ echo "--> NodePool"
        ```

        ```terminal
        $ sed -i '' -e '/^status:$/,$ d' \
          ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}/np-${NODEPOOLS}.yaml
        ```
     4. Back up the secrets in the `HostedCluster` namespace by running the following shell script:

        ```terminal
        $ echo "--> HostedCluster Secrets:"
        for s in $(oc get secret -n ${HC_CLUSTER_NS} | grep "^${HC_CLUSTER_NAME}" | awk '{print $1}'); do
            oc get secret -n ${HC_CLUSTER_NS} $s -o yaml > ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}/secret-${s}.yaml
        done
        ```
     5. Back up the secrets in the `HostedCluster` control plane namespace by running the following shell script:

        ```terminal
        $ echo "--> HostedCluster ControlPlane Secrets:"
        for s in $(oc get secret -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} | egrep -v "docker|service-account-token|oauth-openshift|NAME|token-${HC_CLUSTER_NAME}" | awk '{print $1}'); do
            oc get secret -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} $s -o yaml > ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}-${HC_CLUSTER_NAME}/secret-${s}.yaml
        done
        ```
     6. Back up the hosted control plane by entering the following commands:

        ```terminal
        $ echo "--> HostedControlPlane:"
        ```

        ```terminal
        $ oc get hcp ${HC_CLUSTER_NAME} -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} -o yaml > \
          ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}-${HC_CLUSTER_NAME}/hcp-${HC_CLUSTER_NAME}.yaml
        ```
     7. Back up the cluster by entering the following commands:

        ```terminal
        $ echo "--> Cluster:"
        ```

        ```terminal
        $ CL_NAME=$(oc get hcp ${HC_CLUSTER_NAME} -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} \
          -o jsonpath={.metadata.labels.\*} | grep ${HC_CLUSTER_NAME})
        ```

        ```terminal
        $ oc get cluster ${CL_NAME} -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} -o yaml > \
          ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}-${HC_CLUSTER_NAME}/cl-${HC_CLUSTER_NAME}.yaml
        ```
     8. Back up the AWS cluster by entering the following commands:

        ```terminal
        $ echo "--> AWS Cluster:"
        ```

        ```terminal
        $ oc get awscluster ${HC_CLUSTER_NAME} -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} -o yaml > \
          ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}-${HC_CLUSTER_NAME}/awscl-${HC_CLUSTER_NAME}.yaml
        ```
     9. Back up the AWS `MachineTemplate` objects by entering the following commands:

        ```terminal
        $ echo "--> AWS Machine Template:"
        ```

        ```terminal
        $ oc get awsmachinetemplate ${NODEPOOLS} -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} -o yaml > \
          ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}-${HC_CLUSTER_NAME}/awsmt-${HC_CLUSTER_NAME}.yaml
        ```
     10. Back up the AWS `Machines` objects by running the following shell script:

         ```terminal
         $ echo "--> AWS Machine:"
         ```

         ```terminal
         $ CL_NAME=$(oc get hcp ${HC_CLUSTER_NAME} -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} -o jsonpath={.metadata.labels.\*} | grep ${HC_CLUSTER_NAME})
         for s in $(oc get awsmachines -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} --no-headers | grep ${CL_NAME} | cut -f1 -d\ ); do
             oc get -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} awsmachines $s -o yaml > ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}-${HC_CLUSTER_NAME}/awsm-${s}.yaml
         done
         ```
     11. Back up the `MachineDeployments` objects by running the following shell script:

         ```terminal
         $ echo "--> HostedCluster MachineDeployments:"
         for s in $(oc get machinedeployment -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} -o name); do
             mdp_name=$(echo ${s} | cut -f 2 -d /)
             oc get -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} $s -o yaml > ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}-${HC_CLUSTER_NAME}/machinedeployment-${mdp_name}.yaml
         done
         ```
     12. Back up the `MachineSets` objects by running the following shell script:

         ```terminal
         $ echo "--> HostedCluster MachineSets:"
         for s in $(oc get machineset -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} -o name); do
             ms_name=$(echo ${s} | cut -f 2 -d /)
             oc get -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} $s -o yaml > ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}-${HC_CLUSTER_NAME}/machineset-${ms_name}.yaml
         done
         ```
     13. Back up the `Machines` objects from the Hosted Control Plane namespace by running the following shell script:

         ```terminal
         $ echo "--> HostedCluster Machine:"
         for s in $(oc get machine -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} -o name); do
             m_name=$(echo ${s} | cut -f 2 -d /)
             oc get -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} $s -o yaml > ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}-${HC_CLUSTER_NAME}/machine-${m_name}.yaml
         done
         ```
5. Clean up the `ControlPlane` routes by entering the following command:

   ```terminal
   $ oc delete routes -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} --all
   ```

   By entering that command, you enable the ExternalDNS Operator to delete the Route53 entries.
6. Verify that the Route53 entries are clean by running the following script:

   ```terminal
   function clean_routes() {

       if [[ -z "${1}" ]];then
           echo "Give me the NS where to clean the routes"
           exit 1
       fi

       # Constants
       if [[ -z "${2}" ]];then
           echo "Give me the Route53 zone ID"
           exit 1
       fi

       ZONE_ID=${2}
       ROUTES=10
       timeout=40
       count=0

       # This allows us to remove the ownership in the AWS for the API route
       oc delete route -n ${1} --all

       while [ ${ROUTES} -gt 2 ]
       do
           echo "Waiting for ExternalDNS Operator to clean the DNS Records in AWS Route53 where the zone id is: ${ZONE_ID}..."
           echo "Try: (${count}/${timeout})"
           sleep 10
           if [[ $count -eq timeout ]];then
               echo "Timeout waiting for cleaning the Route53 DNS records"
               exit 1
           fi
           count=$((count+1))
           ROUTES=$(aws route53 list-resource-record-sets --hosted-zone-id ${ZONE_ID} --max-items 10000 --output json | grep -c ${EXTERNAL_DNS_DOMAIN})
       done
   }

   # SAMPLE: clean_routes "<HC ControlPlane Namespace>" "<AWS_ZONE_ID>"
   clean_routes "${HC_CLUSTER_NS}-${HC_CLUSTER_NAME}" "${AWS_ZONE_ID}"
   ```

**Verification**

Check all of the OpenShift Container Platform objects and the S3 bucket to verify that everything looks as expected.

**Next steps**

Restore your hosted cluster.

## Restoring a hosted cluster {#dr-hosted-cluster-within-aws-region-restore_hcp-disaster-recovery-aws}

Gather all of the objects that you backed up and restore them in your destination management cluster.

**Prerequisites**

- You backed up the data from your source management cluster.

> [!TIP]
> Ensure that the `kubeconfig` file of the destination management cluster is placed as it is set in the `KUBECONFIG` variable or, if you use the script, in the `MGMT2_KUBECONFIG` variable. Use `export KUBECONFIG=<Kubeconfig FilePath>` or, if you use the script, use `export KUBECONFIG=${MGMT2_KUBECONFIG}`.

**Procedure**

1. Verify that the new management cluster does not contain any namespaces from the cluster that you are restoring by entering these commands:

   ```terminal
   $ export KUBECONFIG=${MGMT2_KUBECONFIG}
   ```

   ```terminal
   $ BACKUP_DIR=${HC_CLUSTER_DIR}/backup
   ```

   ```terminal {title="Namespace deletion in the destination Management cluster"}
   $ oc delete ns ${HC_CLUSTER_NS} || true
   ```

   ```terminal
   $ oc delete ns ${HC_CLUSTER_NS}-{HC_CLUSTER_NAME} || true
   ```
2. Re-create the deleted namespaces by entering these commands:

   ```terminal {title="Namespace creation commands"}
   $ oc new-project ${HC_CLUSTER_NS}
   ```

   ```terminal
   $ oc new-project ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME}
   ```
3. Restore the secrets in the HC namespace by entering this command:

   ```terminal
   $ oc apply -f ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}/secret-*
   ```
4. Restore the objects in the `HostedCluster` control plane namespace by entering these commands:

   ```terminal {title="Restore secret command"}
   $ oc apply -f ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}-${HC_CLUSTER_NAME}/secret-*
   ```

   ```terminal {title="Cluster restore commands"}
   $ oc apply -f ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}-${HC_CLUSTER_NAME}/hcp-*
   ```

   ```terminal
   $ oc apply -f ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}-${HC_CLUSTER_NAME}/cl-*
   ```
5. If you are recovering the nodes and the node pool to reuse AWS instances, restore the objects in the HC control plane namespace by entering these commands:

   ```terminal {title="Commands for AWS"}
   $ oc apply -f ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}-${HC_CLUSTER_NAME}/awscl-*
   ```

   ```terminal
   $ oc apply -f ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}-${HC_CLUSTER_NAME}/awsmt-*
   ```

   ```terminal
   $ oc apply -f ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}-${HC_CLUSTER_NAME}/awsm-*
   ```

   ```terminal {title="Commands for machines"}
   $ oc apply -f ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}-${HC_CLUSTER_NAME}/machinedeployment-*
   ```

   ```terminal
   $ oc apply -f ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}-${HC_CLUSTER_NAME}/machineset-*
   ```

   ```terminal
   $ oc apply -f ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}-${HC_CLUSTER_NAME}/machine-*
   ```
6. Restore the etcd data and the hosted cluster by running this bash script:

   ```terminal
   ETCD_PODS="etcd-0"
   if [ "${CONTROL_PLANE_AVAILABILITY_POLICY}" = "HighlyAvailable" ]; then
     ETCD_PODS="etcd-0 etcd-1 etcd-2"
   fi

   HC_RESTORE_FILE=${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}/hc-${HC_CLUSTER_NAME}-restore.yaml
   HC_BACKUP_FILE=${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}/hc-${HC_CLUSTER_NAME}.yaml
   HC_NEW_FILE=${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}/hc-${HC_CLUSTER_NAME}-new.yaml
   cat ${HC_BACKUP_FILE} > ${HC_NEW_FILE}
   cat > ${HC_RESTORE_FILE} <<EOF
       restoreSnapshotURL:
   EOF

   for POD in ${ETCD_PODS}; do
     # Create a pre-signed URL for the etcd snapshot
     ETCD_SNAPSHOT="s3://${BUCKET_NAME}/${HC_CLUSTER_NAME}-${POD}-snapshot.db"
     ETCD_SNAPSHOT_URL=$(AWS_DEFAULT_REGION=${MGMT2_REGION} aws s3 presign ${ETCD_SNAPSHOT})

     # FIXME no CLI support for restoreSnapshotURL yet
     cat >> ${HC_RESTORE_FILE} <<EOF
       - "${ETCD_SNAPSHOT_URL}"
   EOF
   done

   cat ${HC_RESTORE_FILE}

   if ! grep ${HC_CLUSTER_NAME}-snapshot.db ${HC_NEW_FILE}; then
     sed -i '' -e "/type: PersistentVolume/r ${HC_RESTORE_FILE}" ${HC_NEW_FILE}
     sed -i '' -e '/pausedUntil:/d' ${HC_NEW_FILE}
   fi

   HC=$(oc get hc -n ${HC_CLUSTER_NS} ${HC_CLUSTER_NAME} -o name || true)
   if [[ ${HC} == "" ]];then
       echo "Deploying HC Cluster: ${HC_CLUSTER_NAME} in ${HC_CLUSTER_NS} namespace"
       oc apply -f ${HC_NEW_FILE}
   else
       echo "HC Cluster ${HC_CLUSTER_NAME} already exists, avoiding step"
   fi
   ```
7. If you are recovering the nodes and the node pool to reuse AWS instances, restore the node pool by entering this command:

   ```terminal
   $ oc apply -f ${BACKUP_DIR}/namespaces/${HC_CLUSTER_NS}/np-*
   ```

**Verification**

- To verify that the nodes are fully restored, use this function:

  ```terminal
  timeout=40
  count=0
  NODE_STATUS=$(oc get nodes --kubeconfig=${HC_KUBECONFIG} | grep -v NotReady | grep -c "worker") || NODE_STATUS=0

  while [ ${NODE_POOL_REPLICAS} != ${NODE_STATUS} ]
  do
      echo "Waiting for Nodes to be Ready in the destination MGMT Cluster: ${MGMT2_CLUSTER_NAME}"
      echo "Try: (${count}/${timeout})"
      sleep 30
      if [[ $count -eq timeout ]];then
          echo "Timeout waiting for Nodes in the destination MGMT Cluster"
          exit 1
      fi
      count=$((count+1))
      NODE_STATUS=$(oc get nodes --kubeconfig=${HC_KUBECONFIG} | grep -v NotReady | grep -c "worker") || NODE_STATUS=0
  done
  ```

**Next steps**

Shut down and delete your cluster.

## Deleting a hosted cluster from your source management cluster {#dr-hosted-cluster-within-aws-region-delete_hcp-disaster-recovery-aws}

After you back up your hosted cluster and restore it to your destination management cluster, you shut down and delete the hosted cluster on your source management cluster.

**Prerequisites**

- You backed up your data and restored it to your source management cluster.

> [!TIP]
> Ensure that the `kubeconfig` file of the destination management cluster is placed as it is set in the `KUBECONFIG` variable or, if you use the script, in the `MGMT_KUBECONFIG` variable. Use `export KUBECONFIG=<Kubeconfig FilePath>` or, if you use the script, use `export KUBECONFIG=${MGMT_KUBECONFIG}`.

**Procedure**

1. Scale the `deployment` and `statefulset` objects by entering these commands:

   > [!IMPORTANT]
   > Do not scale the stateful set if the value of its `spec.persistentVolumeClaimRetentionPolicy.whenScaled` field is set to `Delete`, because this could lead to a loss of data.
   >
   > As a workaround, update the value of the `spec.persistentVolumeClaimRetentionPolicy.whenScaled` field to `Retain`. Ensure that no controllers exist that reconcile the stateful set and would return the value back to `Delete`, which could lead to a loss of data.

   ```terminal
   $ export KUBECONFIG=${MGMT_KUBECONFIG}
   ```

   ```terminal {title="Scale down deployment commands"}
   $ oc scale deployment -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} --replicas=0 --all
   ```

   ```terminal
   $ oc scale statefulset.apps -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} --replicas=0 --all
   ```

   ```terminal
   $ sleep 15
   ```
2. Delete the `NodePool` objects by entering these commands:

   ```terminal
   NODEPOOLS=$(oc get nodepools -n ${HC_CLUSTER_NS} -o=jsonpath='{.items[?(@.spec.clusterName=="'${HC_CLUSTER_NAME}'")].metadata.name}')
   if [[ ! -z "${NODEPOOLS}" ]];then
       oc patch -n "${HC_CLUSTER_NS}" nodepool ${NODEPOOLS} --type=json --patch='[ { "op":"remove", "path": "/metadata/finalizers" }]'
       oc delete np -n ${HC_CLUSTER_NS} ${NODEPOOLS}
   fi
   ```
3. Delete the `machine` and `machineset` objects by entering these commands:

   ```terminal
   # Machines
   for m in $(oc get machines -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} -o name); do
       oc patch -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} ${m} --type=json --patch='[ { "op":"remove", "path": "/metadata/finalizers" }]' || true
       oc delete -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} ${m} || true
   done
   ```

   ```terminal
   $ oc delete machineset -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} --all || true
   ```
4. Delete the cluster object by entering these commands:

   ```terminal
   $ C_NAME=$(oc get cluster -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} -o name)
   ```

   ```terminal
   $ oc patch -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} ${C_NAME} --type=json --patch='[ { "op":"remove", "path": "/metadata/finalizers" }]'
   ```

   ```terminal
   $ oc delete cluster.cluster.x-k8s.io -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} --all
   ```
5. Delete the AWS machines (Kubernetes objects) by entering these commands. Do not worry about deleting the real AWS machines. The cloud instances will not be affected.

   ```terminal
   for m in $(oc get awsmachine.infrastructure.cluster.x-k8s.io -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} -o name)
   do
       oc patch -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} ${m} --type=json --patch='[ { "op":"remove", "path": "/metadata/finalizers" }]' || true
       oc delete -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} ${m} || true
   done
   ```
6. Delete the `HostedControlPlane` and `ControlPlane` HC namespace objects by entering these commands:

   ```terminal {title="Delete HostedControlPlane and ControlPlane HC NS commands"}
   $ oc patch -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} hostedcontrolplane.hypershift.openshift.io ${HC_CLUSTER_NAME} --type=json --patch='[ { "op":"remove", "path": "/metadata/finalizers" }]'
   ```

   ```terminal
   $ oc delete hostedcontrolplane.hypershift.openshift.io -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} --all
   ```

   ```terminal
   $ oc delete ns ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME} || true
   ```
7. Delete the `HostedCluster` and HC namespace objects by entering these commands:

   ```terminal {title="Delete HC and HC Namespace commands"}
   $ oc -n ${HC_CLUSTER_NS} patch hostedclusters ${HC_CLUSTER_NAME} -p '{"metadata":{"finalizers":null}}' --type merge || true
   ```

   ```terminal
   $ oc delete hc -n ${HC_CLUSTER_NS} ${HC_CLUSTER_NAME}  || true
   ```

   ```terminal
   $ oc delete ns ${HC_CLUSTER_NS} || true
   ```

**Verification**

- To verify that everything works, enter these commands:

  ```terminal {title="Validations commands"}
  $ export KUBECONFIG=${MGMT2_KUBECONFIG}
  ```

  ```terminal
  $ oc get hc -n ${HC_CLUSTER_NS}
  ```

  ```terminal
  $ oc get np -n ${HC_CLUSTER_NS}
  ```

  ```terminal
  $ oc get pod -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME}
  ```

  ```terminal
  $ oc get machines -n ${HC_CLUSTER_NS}-${HC_CLUSTER_NAME}
  ```

  ```terminal {title="Commands for inside the HostedCluster"}
  $ export KUBECONFIG=${HC_KUBECONFIG}
  ```

  ```terminal
  $ oc get clusterversion
  ```

  ```terminal
  $ oc get nodes
  ```

**Next steps**

Delete the OVN pods in the hosted cluster so that you can connect to the new OVN control plane that runs in the new management cluster:

1. Load the `KUBECONFIG` environment variable with the hosted cluster’s `kubeconfig` path.
2. Enter this command:

   ```terminal
   $ oc delete pod -n openshift-ovn-kubernetes --all
   ```
