Implementazione del rollback automatico

Utilizzare gli script per implementare il rollback automatico quando un job di applicazione non riesce in Resource Manager. Gli script di rollback automatico prevedono il monitoraggio degli errori dei job e la definizione di una procedura di rollback che include convalida, trigger personalizzati e azioni.

Negli ambienti di produzione, è essenziale definire una strategia di implementazione solida e flessibile. Una best practice comune consiste nell'integrare OCI Resource Manager con un sistema CI/CD (Continuous Integration/Continuous Delivery) per gestire l'intero ciclo di vita della distribuzione, incluso il rollback automatico.

Oracle Cloud Infrastructure (OCI) offre una piattaforma CI/CD nativa e completa di funzionalità: OCI DevOps. Questo servizio fornisce gli strumenti e le pipeline necessari per orchestrare perfettamente le operazioni di distribuzione, test, monitoraggio e rollback.

Script di rollback automatico

Per iniziare, abbiamo fornito il seguente script Bash di esempio, che può essere utilizzato in una pipeline di distribuzione DevOps OCI. Questo script descrive un meccanismo per il rollback automatico di uno stack di Resource Manager OCI in caso di errore di distribuzione.

Lo script funge da punto di partenza che puoi personalizzare per soddisfare i tuoi requisiti specifici, assicurandoti che sia in linea con le esigenze esclusive dei tuoi flussi di lavoro di distribuzione.

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 logica di rollback automatico implementata nello script include i passi riportati di seguito.

  1. Avvia distribuzione: creare un job di applicazione per distribuire la configurazione Terraform aggiornata.
  2. Monitora stato distribuzione: consente di monitorare continuamente lo stato del job di applicazione. Vedere Recupero dei dettagli di un job.
  3. Valuta errore: se il job di applicazione non riesce, valutare i criteri predefiniti per determinare se attivare un rollback automatico.
  4. Identifica stato stabile: recupera i job di applicazione riusciti per lo stack e determina il job di destinazione a cui si desidera eseguire il rollback: vedere Lista dei job.
  5. Rollback trigger: creare un job di rollback di applicazione per ripristinare lo stack allo stato stabile in precedenza.