Patching ExaCS clusters using OCI-CLI


By Marije Politiek 9 september 2025

It's important to keep your ExaCS clusters up to date. In this article, colleague Mark Kempers, Infrastructure Specialist at MCX, explains some basic steps.

MCX collega aan het werk in de serverruimte

"In my case I made an interactive script so I can do the whole patch cycle in my terminal without clicking through the console. It lets me choose the environment, which update I would like to precheck/apply and provides me the status of the patch.


This can become helpful if not every employee can access the OCI console, but needs to patch the system. For example your DBA or Service Desk Engineer can do it without any tools. Just run the script!


So, let's take a dive into the scripting.


Right now, I will focus on fetching the GRID/OS patches for one VM cluster of the ExaCS infrastructure.


Let's start with the prerequisites.


Make sure you have a Linux machine installed with the oci-cli and jq. Refer to this piece of documentation on how in to install and configure the oci-cli.


In this case I have an ExaCS infrastructure with 4 different clusters. One for each DTAP (Development, Test, Acceptance and Production) environment. The goal is to keep all environments the same.


Building the script


Make sure you start with declaring all variables you need. In this case we need the OCIDs for all ExaCS VM clusters and today's date in UTC. Which will look something like this:

# Make sure to enter your OCIDs


DV_OCID="ocid1.cloudvmcluster.oc1.eu-amsterdam-1.xxxxxx"


TS_OCID="ocid1.cloudvmcluster.oc1.eu-amsterdam-1.xxxxxx"


AC_OCID="ocid1.cloudvmcluster.oc1.eu-amsterdam-1.xxxxxx"


PR_OCID="ocid1.cloudvmcluster.oc1.eu-amsterdam-1.xxxxxx"





# Current date in UTC


TODAY=$(date -u +%F) # e.g. "2025-09-04"

We will use this variables later in the scripting.


The next step will be to fetch all the patches available for a cluster. Of course we want a friendly formatted output. As oci-cli gives the output in JSON, we will format it to a readable table. Here is an example:

# Fetch the patches for the Development cluster


PATCH_LIST=$(oci db cloud-vm-cluster list-updates \


  --cloud-vm-cluster-id "$DV_OCID" \


  --all \


  --query "data[*].{id:id,description:description,version:version,release:\"time-released\",action:\"available-actions\"}" \


  --output table)


 


# Let's show the output on screen


echo "$PATCH_LIST"

When running this, the result will be a table in your terminal with the OCID of the patch, description, version, release time and available action (ROLLING-APPLY/PRECHECK).


Now it is important that you save the OCID of the specific patch you would like to install so we can kick off the precheck for that patch. Here is how to start the precheck.

oci db cloud-vm-cluster update \


  --cloud-vm-cluster-id "$DV_OCID" \


  --update-id "[SAVED PATCH OCID]" \


  --update-action PRECHECK \


  --force

So now we would like to know when the precheck is finished. As soon as the precheck starts we run a script to ask for the current status of the precheck. Every job that is running will already be stored in the history, but with a specific lifecycle state. The three most important lifecycle-states are FAILED, IN PROGRESS or SUCCEEDED. So let's see how that will look like.


The script below will ask for the status of that specific job every 60 seconds for 60 minutes. It will keep going for the time the status is 'IN PROGRESS'. It will finish as soon as it reach the status FAILED or SUCCEEDED. When reaching FAILED it will exit the script, when SUCCEEDED it will continue to apply the patch.

local max_attempts="${2:-60}"  # Default: try for 60 minutes


  local interval=60        # seconds between checks


  local attempt=1


 


  echo "Waiting for patch state to reach status SUCCEEDED..."


 


  while (( attempt <= max_attempts )); do


    vm_patch_status=$(oci db cloud-vm-cluster list-update-histories \


      --cloud-vm-cluster-id "$DV_OCID" \


      --output json   jq -r \


      --arg today "$TODAY" \


      '.data[]   select(."update-id" == "[SAVED_PATCH_ID]")   select(."update-action" == "PRECHECK")   select(."time-started"   startswith($today))   ."lifecycle-state"' )


 


    echo "Status is '$vm_patch_status'"


 


    if [[ "$vm_patch_status" == "SUCCEEDED" ]]; then


      echo "Precheck is succesfull!"


      run_vm_apply # Function to start applying the patch


    elif [[ "$vm_patch_status" == "FAILED" ]]; then


      echo "Patch failed the precheck, please check the console for the error."


      exit 0


    fi


 


    ((attempt++))


    sleep "$interval"


  done


 


  echo "Timeout reached. Resource did not reach SUCCEEDED state in $((max_attempts * interval / 60)) minutes."


  exit 0

Assuming the patch precheck succeeds, we will continue to apply the patch. The command looks similar to the PRECHECK command. Let's take a look.

oci db cloud-vm-cluster update \


  --cloud-vm-cluster-id "$CLUSTER_OCID" \


  --update-id "[SAVED PATCH OCID]" \


  --update-action APPLY \


  --force

As soon as the patch APPLY runs, you can run the same check loop as mentioned above. Instead of filtering the output on PRECHECK, filter on the APPLY. The full command looks like this. Can you see the difference?

apply_status() { 


  local max_attempts="${2:-60}"  # Default: try for 60 minutes


  local interval=60        # seconds between checks


  local attempt=1


 


  echo "Waiting for patch state to reach status SUCCEEDED..."


 


  while (( attempt <= max_attempts )); do


    vm_apply_status=$(oci db cloud-vm-cluster list-update-histories \


      --cloud-vm-cluster-id "$DV_OCID" \


      --output json   jq -r \


      --arg today "$TODAY" \


      '.data[]   select(."update-id" == "[SAVED_PATCH_ID]")   select(."update-action" == "APPLY")   select(."time-started"   startswith($today))   ."lifecycle-state"' )


 


    echo "Status is '$vm_apply_status'"


 


    if [[ "$vm_apply_status" == "SUCCEEDED" ]]; then


      echo "Patch has succesfully been applied!"


      exit 0


    elif [[ "$vm_apply_status" == "FAILED" ]]; then


      echo "Patch failed to apply, please check the console for the error."


      exit 0


    fi


 


    ((attempt++))


    sleep "$interval"


  done


 


  echo "Timeout reached. Resource did not reach SUCCEEDED state in $((max_attempts * interval / 60)) minutes."


  exit 0

When the patch is installed successfully, it will tell you so. That's all it is! With some bash scripting skills, you can combine everything together and patch your environment with just one single command!


As you can see, you can change a variable to apply this to all of your clusters.


If you like some details on the full script I built for the patching cycles, don't hesitate to reach out! Happy to help."

We like to do things a little differently

Our strength lies in people who truly understand Oracle and are always curious about what's really going on. Discover how we work and who we are.


Stay up to date

Don't miss the most important MCX news, developments in cloud, Oracle and security, and our perspective on technology and collaboration? Sign up for our newsletter.

Newletter ENG

Most recent posts

Collega aan het werk achter beeldscherm
door Marije Politiek 27 januari 2026
For years, PeopleSoft Integration Broker (IB) has had a known limitation when making outbound HTTPS calls to servers requiring SNI (Server Name Indication). By default, IB resolves hostnames to IP addresses before establishing the TLS handshake. While functional in many cases, this approach prevents Java from sending the hostname in the TLS handshake, causing connections to fail on SNI-required endpoints, especially common in modern cloud environments.
MCX Jmeter
door Marije Politiek 15 januari 2026
Performance testing is crucial for delivering reliable IT services. But what if there is hardly any documentation on how to properly test your specific systems? MCX took on exactly that challenge by combining JMeter and PeopleSoft - a journey that started with frustration but ended in innovation. ‘It was a struggle, but that's exactly what makes the end result so satisfying.’ says Anu Khurana, Subject Matter Expert at MCX. Read Anu's full blog post below:
Bert MCX
door Marije Politiek 2 december 2025
Bert shares how MCX’s honest culture, teamwork and broad technical roles create a workplace where reliability, loyalty and personal growth truly matter.