Implémenter l'annulation (rollback) automatique

Utilisez des scripts pour implémenter l'annulation automatique en cas d'échec d'un travail d'application dans Resource Manager. Les scripts d'annulation automatique impliquent la surveillance des échecs de travail et la définition d'une procédure d'annulation qui inclut la validation, les déclencheurs personnalisés et les actions.

Dans les environnements de production, il est essentiel d'établir une stratégie de déploiement robuste et flexible. Une bonne pratique courante consiste à intégrer OCI Resource Manager à un système d'intégration continue/de livraison continue (CI/CD) pour gérer le cycle de vie complet du déploiement, y compris la restauration automatique.

Oracle Cloud Infrastructure (OCI) offre une plate-forme d'intégration continue et de déploiement continu native et complète : OCI DevOps. Ce service fournit les outils et les pipelines nécessaires pour orchestrer en toute transparence les opérations de déploiement, de test, de surveillance et d'annulation.

Script d'annulation automatique

Pour vous aider à démarrer, nous avons fourni l'exemple de script Bash suivant, qui peut être utilisé dans un pipeline de déploiement OCI DevOps. Ce script présente un mécanisme permettant d'annuler automatiquement une pile OCI Resource Manager en cas d'échec du déploiement.

Le script sert de point de départ que vous pouvez personnaliser en fonction de vos besoins spécifiques, en veillant à ce qu'il corresponde aux besoins uniques de vos workflows de déploiement.

Script
version: 0.1
component: command
timeoutInSeconds: 600
shell: bash
steps:
  - type: Command
    name: "Deployment Runner Functionality"
    command: |
      # The STACK_OCID variable is externally injected and remains unescaped.
      STACK_OCID="${STACK_OCID}"

      echo "Starting Resource Manager Apply Job for Stack: ${STACK_OCID}"

      # 1. Create the Apply Job and capture its OCID.
      job_id=$(
        oci resource-manager job create-apply-job \
          --execution-plan-strategy AUTO_APPROVED \
          --display-name "DevOps-Apply-$(date +%s)" \
          --stack-id "${STACK_OCID}" \
          --wait-for-state 'ACCEPTED' \
          --query 'data.id' \
          --raw-output \
      )

      # Check if the job creation command returned a valid ID
      if [ -z "$job_id" ]; then
        echo "ERROR: Failed to create Resource Manager Apply job or command failed."
        exit 1
      fi

      echo "Resource Manager Job OCID: $job_id"

      # 2. Polling Loop to monitor job status
      max_poll_time_seconds=600 # 10 minutes maximum wait time
      poll_interval_seconds=10
      elapsed_time=0

      while [ $elapsed_time -le $max_poll_time_seconds ]; do

        # Get the current job status.
        status=$(
          oci resource-manager job get \
            --job-id "$job_id" \
            --query 'data."lifecycle-state"' \
            --raw-output \
        )

        echo "Time Elapsed: ${elapsed_time}s / ${max_poll_time_seconds}s - Current Job Status: $status"

        if [ "$status" == "SUCCEEDED" ]; then
          echo "Resource Manager Apply Job SUCCEEDED."
          exit 0 # Success exit code
        elif [ "$status" == "FAILED" ] || [ "$status" == "CANCELED" ]; then
          echo "Resource Manager Apply Job FAILED or CANCELED."

          # Check failure reason and conditionally trigger rollback
          if [ "$status" == "FAILED" ]; then
            # Fetch failure code
            failure_code=$(
              oci resource-manager job get \
                --job-id "$job_id" \
                --query 'data."failure-details".code' \
                --raw-output \
            )
            if [ -z "$failure_code" ]; then
              echo "No failure-details.code found in job output (field is empty or missing)"
              echo "==== Full job JSON output for debugging: ===="
              oci resource-manager job get \
                --job-id "$job_id" \
            else
              echo "Failure code: $failure_code"
            fi

            if [ "$failure_code" == "TERRAFORM_EXECUTION_ERROR" ]; then
              echo "Detected Terraform configuration error. Starting automatic rollback process..."

              # Define a rollback function
              automatic_rollback() {
                # List all jobs, filter for successful Apply jobs, sort by time-created desc, and get latest job OCID
                # Part 1: Fetch and count all succeeded APPLY jobs
                matched_jobs=$(
                  oci resource-manager job list \
                    --stack-id "$STACK_OCID" \
                    --query 'data[?operation==`APPLY` && "lifecycle-state"==`SUCCEEDED`] | sort_by(@, &`"time-created"`)' \
                )
                job_count=$(echo "$matched_jobs" | jq 'length')
                echo "Number of matching jobs found: $job_count"

                # Part 2: Extract and print first OCID if any
                last_succeeded_apply_job_ocid=$(echo "$matched_jobs" | jq -r '.[0].id // empty')

                if [ -n "$last_succeeded_apply_job_ocid" ]; then
                  echo "Last succeeded apply job OCID: $last_succeeded_apply_job_ocid"
                else
                  echo "No previous successful apply jobs found. Rollback skipped."
                  return 0
                fi
                
                echo "Invoking OCI CLI to create rollback job for OCID: $last_succeeded_apply_job_ocid"
                
                oci resource-manager job create \
                  --from-json "{\"stackId\":\"${STACK_OCID}\",\"displayName\":\"DevOps-Apply-Rollback-$(date +%s)\",\"jobOperationDetails\":{\"operation\":\"APPLY_ROLLBACK\",\"executionPlanRollbackStrategy\":\"AUTO_APPROVED\",\"targetRollbackJobId\":\"$last_succeeded_apply_job_ocid\"}}" \
                
                echo "======Apply Rollback Job Creation Complete========="
              }

              # Call the rollback function
              automatic_rollback
            fi
          fi
          exit 1 # Failure exit code
        fi

        # Wait before polling again
        sleep $poll_interval_seconds

        let "elapsed_time = elapsed_time + poll_interval_seconds"
      done

      # If the loop finished without SUCCEEDED or FAILED status
      echo "Error: Resource Manager Apply Job timed out after ${max_poll_time_seconds} seconds."
      exit 1

La logique d'annulation automatique implémentée dans le script comprend les étapes suivantes :

  1. Lancer le déploiement : créez un travail d'application des modifications pour déployer la configuration Terraform mise à jour.
  2. Surveiller le statut du déploiement : surveillez en permanence le statut du travail d'application des modifications. Reportez-vous à Obtention des détails d'un travail.
  3. Evaluer l'échec : si le travail d'application échoue, évaluez des critères prédéfinis pour déterminer s'il faut déclencher une annulation automatique.
  4. Identifier l'état stable : récupérez les travaux d'application réussis pour la pile et déterminez le travail cible vers lequel effectuer l'annulation (rollback) : reportez-vous à Liste des travaux.
  5. Déclencher l'annulation : créez un travail d'annulation d'application pour restaurer la pile à l'état précédemment stable.