Skip to content

Instantly share code, notes, and snippets.

@majodev
Created August 11, 2026 14:31
Show Gist options
  • Select an option

  • Save majodev/75906493d8d0144d141c7eb926ba82ec to your computer and use it in GitHub Desktop.

Select an option

Save majodev/75906493d8d0144d141c7eb926ba82ec to your computer and use it in GitHub Desktop.
oci_compute_maintenances.sh
#!/usr/bin/env bash
set -euox pipefail
# This script writes out OCI instance maintenance events to a CSV file.
# It checks a single target OCI tenancy and checks all regions/compartments.
#
# Depends on:
# * https://github.com/oracle/oci-cli
# * https://github.com/jqlang/jq
#
# The OCI target tenancy either comes from:
# * the DEFAULT oci profile ($HOME/.oci/config) or
# * the explicitly set env var TENANCY_OCID.
profile=${OCI_CLI_PROFILE:-DEFAULT}
config_file=${OCI_CLI_CONFIG_FILE:-"$HOME/.oci/config"}
output_file=oci_compute_maintenances.csv
for required_command in oci jq; do
if ! command -v "$required_command" >/dev/null 2>&1; then
printf 'error: required command not found: %s\n' "$required_command" >&2
exit 1
fi
done
trim() {
local value=$1
value=${value#"${value%%[![:space:]]*}"}
value=${value%"${value##*[![:space:]]}"}
printf '%s' "$value"
}
read_profile_tenancy() {
local section= line= key= value=
[[ -r $config_file ]] || return 1
while IFS= read -r line || [[ -n $line ]]; do
line=${line%$'\r'}
line=$(trim "$line")
[[ -z $line || $line == \#* || $line == \;* ]] && continue
if [[ $line == \[*\] ]]; then
section=${line#\[}
section=${section%\]}
section=$(trim "$section")
continue
fi
if [[ $section == "$profile" && $line == *=* ]]; then
key=$(trim "${line%%=*}")
if [[ $key == tenancy ]]; then
value=$(trim "${line#*=}")
[[ -n $value ]] || return 1
printf '%s\n' "$value"
return 0
fi
fi
done < "$config_file"
return 1
}
if [[ -n ${TENANCY_OCID:-} ]]; then
tenancy_id=$TENANCY_OCID
elif ! tenancy_id=$(read_profile_tenancy); then
printf 'error: cannot resolve tenancy for OCI profile %s from %s\n' \
"$profile" "$config_file" >&2
exit 1
fi
regions=$(
oci iam region-subscription list --all |
jq -r '.data[]."region-name"'
)
[[ -n $regions ]] || {
printf 'error: OCI returned no subscribed regions\n' >&2
exit 1
}
compartments=$(
printf '%s\n' "$tenancy_id"
oci iam compartment list \
--compartment-id "$tenancy_id" \
--compartment-id-in-subtree true \
--access-level ACCESSIBLE \
--lifecycle-state ACTIVE \
--all |
jq -r '.data[].id'
)
{
printf '%s\n' 'ACCOUNT NAME,TENANT ID,VM ID,VM DISPLAY NAME,SHAPE,REGION,AD,FAULT DOMAIN,NETWORK TYPE,Maintenance Created Time,Maintenance Start Window,Maintenance Started Time,Maintenance Finished Time,Maintenance Due Date'
while IFS= read -r region; do
[[ -n $region ]] || continue
while IFS= read -r compartment_id; do
[[ -n $compartment_id ]] || continue
# you may want to filter just for --lifecycle-state SCHEDULED
events=$(
oci compute instance-maintenance-event list \
--compartment-id "$compartment_id" \
--region "$region" \
--all
)
while IFS= read -r event; do
[[ -n $event ]] || continue
instance_id=$(jq -r '."instance-id"' <<< "$event")
if ! instance_json=$(
oci compute instance get \
--instance-id "$instance_id" \
--region "$region" 2>/dev/null
); then
continue
fi
instance=$(
jq -c '.data | {
"display-name",
shape,
"availability-domain",
"fault-domain",
"network-type": ."launch-options"."network-type"
}' <<< "$instance_json"
)
jq -nr \
--arg profile "$profile" \
--arg tenancy "$tenancy_id" \
--arg region "$region" \
--argjson event "$event" \
--argjson instance "$instance" '
def normalize:
(. // "") | ascii_upcase | gsub("[-:]"; "_");
def normalize_ad:
(. // "") | split(":")[-1] | normalize;
def display_time:
if . == null or . == "" then ""
else
capture("^(?<y>[0-9]{4})-(?<m>[0-9]{2})-(?<d>[0-9]{2})T(?<h>[0-9]{2}):(?<min>[0-9]{2})") as $t
| ($t.h | tonumber) as $hour
| (if $hour == 0 then 12 elif $hour > 12 then $hour - 12 else $hour end) as $hour12
| "\($t.m)/\($t.d)/\($t.y) \($hour12 | tostring | if length == 1 then "0" + . else . end):\($t.min) \(if $hour < 12 then "AM" else "PM" end)"
end;
[
$profile,
$tenancy,
$event."instance-id",
$instance."display-name",
$instance.shape,
($region | normalize),
($instance."availability-domain" | normalize_ad),
($instance."fault-domain" | normalize),
($instance."network-type" | normalize),
($event."time-created" | display_time),
($event."time-window-start" | display_time),
($event."time-started" | display_time),
($event."time-finished" | display_time),
($event."time-hard-due-date" | display_time)
] | @csv
'
done < <(jq -c '.data[]' <<< "$events")
done <<< "$compartments"
done <<< "$regions"
} > "$output_file"
printf 'wrote %s\n' "$output_file" >&2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment