#!/usr/bin/env bash # # Author: Georg Voell - georg.voell@standby.cloud # Version: @(#)setup-tools 3.3.0 19.01.2026 (c)2026 Standby.cloud # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ # # This script can be used free of charge. Use it as is or customize as needed. It is not guaranteed to be # error free and you will not be reimbursed for any damage it may cause. # #@ Check if all needed tools are installed and have the right version - else install them. #@ Configure oci tools and copy configuration to an operator host. #@ Optional: Setup a core infrastructure with terraform and execute terraform commands. #@ #@Usage: setup-tools [options] [action] #@ Options: -h, --help : Displays helptext. #@ -v, --version: Displays the version of the script. #@ Action: #@ update : Install or update Scripts and Tools. #@ remove : Delete installed Scripts and Tools. #@ config : Configure oci tools. #@ setup : Setup a core infrastructure (multitier) via terraform. #@ terraform : Manage your resources with terraform e.g.: setup-tools terraform "apply -auto-approve". #@ push : Copy configuration to destination ("user@ip" e.g. "opc@130.61.219.239"). # # Update history: # # V 3.0.0 24.04.2020 New version # V 3.0.1 11.06.2020 Using library # V 3.0.2 22.06.2020 Renamed "check-tools" to "setup-tools" and added actions # V 3.0.3 12.07.2020 Calling bootstrap # V 3.0.4 06.09.2020 Terraform config # V 3.0.5 06.09.2020 16.09.2020 Use new download URL: https://standby.cloud/download # V 3.0.6 23.09.2020 Packer included # V 3.0.7 17.10.2020 Warning if local keys could not be imported # V 3.0.8 17.01.2021 Remove get-authkeys also / bootstrap disabled # V 3.0.9 21.03.2021 Create file api-config # V 3.0.10 26.05.2021 New PreAuth Rules for Project Bucket and Terraform compartment with subs # V 3.0.11 15.11.2021 Include multitier infrastructure # V 3.0.12 13.12.2021 Small changes (Log handling) # V 3.0.13 06.09.2022 Init cli psm # V 3.1.0 05.06.2023 New copyright # V 3.1.1 23.08.2023 Install oci-tools and ocifs and start oci service # V 3.1.2 15.11.2023 Minor bugfixes # V 3.1.3 18.07.2024 Check for internet connectivity # V 3.2.0 12.08.2024 New minor version # V 3.2.1 13.11.2024 Use JSON values # V 3.2.2 10.08.2025 Download from Objectstorage # V 3.2.3 18.08.2025 Small bugfixes and setting to obsoltet: tcsh, opc and psm # V 3.2.4 14.09.2025 Small changes # V 3.3.0 19.01.2026 Revised with support of Claude Code # # Exit codes: # 01: Unknown or wrong parameter. # 02: Unknown action # 03: Need root privileges # 04: No internet # 05: Unexpected error # 99: User interrupt. # # Find executable bash library and source it lib=$(command -v lib.bash 2>/dev/null) if [[ -n "$lib" ]]; then source "$lib" else progdir=$(dirname "$0") if [[ -r "${progdir}/lib.bash" ]]; then source "${progdir}/lib.bash" else echo "Unexpected error: Unable to locate bash library 'lib.bash'." exit 1 fi fi # Repository where we load out scripts and tools from readonly baseurl="https://standby.cloud/download" readonly storageurl="https://objectstorage.eu-frankfurt-1.oraclecloud.com/n/frcc4jd4wdkp/b/download/o" # Set some defaults export SUPPRESS_LABEL_WARNING=True needinstall=0 downloadurl="$baseurl" # Logfile if [[ "$LOGFILE" != "" ]]; then logfile="$LOGFILE" else if [[ ! -d "${REALHOME}/logs" ]]; then mkdir -p "${REALHOME}/logs" chown "${REALUSER}:$REALGROUP" "${REALHOME}/logs" fi logfile="${REALHOME}/logs/${progstr}.log" if [[ -r "/var/log/bootstrap.log" && ! -f "${REALHOME}/logs/bootstrap.log" ]]; then ln -s "/var/log/bootstrap.log" "${REALHOME}/logs/bootstrap.log" fi if [[ -r "/var/log/install-tools.log" && ! -f "${REALHOME}/logs/install-tools.log" ]]; then ln -s "/var/log/install-tools.log" "${REALHOME}/logs/install-tools.log" fi # touch "$logfile" # chown "${REALUSER}:$REALGROUP" "$logfile" # export LOGFILE="$logfile" fi # Delete file function DeleteFile { local filename=${1} if [[ "$filename" != "" ]]; then if [[ -f "$filename" ]]; then rm -f "$filename" fi fi } # Do extra cleanup function ExtraCleanup { # Can't use filecheck, because we may removed the scripts DeleteFile "${scratchfile}.comp" DeleteFile "${scratchfile}.user" DeleteFile "${scratchfile}.json" DeleteFile "${scratchfile}.pre" DeleteFile "${scratchfile}.err" DeleteFile "${scratchfile}.pp" if [[ "$authuserid" != "" ]]; then # Cleanup api key if [[ "$fpid" != "" ]]; then CallOCI iam user api-key delete --user-id "$authuserid" --fingerprint "$fpid" --force >/dev/null fi # Cleanup access key if [[ "$s3id" != "" ]]; then CallOCI iam customer-secret-key delete --user-id "$authuserid" --customer-secret-key-id "$s3id" --force >/dev/null fi fi if [[ "$projectname" != "" ]]; then # Cleanup PreAuth bucket access if [[ "$preauthwid" != "" ]]; then CallOCI os preauth-request delete --bucket-name "$projectname" --par-id "$preauthwid" --force >/dev/null fi if [[ "$preauthrid" != "" ]]; then CallOCI os preauth-request delete --bucket-name "$projectname" --par-id "$preautrwid" --force >/dev/null fi fi # Reset terminal tset } function CheckNewerVersion { local tool=${1} local curvers=${2} local newvers="" local response="" local resultstr="" curl=$(filecheck -x curl) if [[ "$curl" != "" ]]; then if [[ "$tool" != "" && "$curvers" != "" ]]; then cmd=$(basename $tool) case "$cmd" in # V 3.2.3: opc deleted terraform | packer | jq | rclone) # echo "$curl -L -s ${downloadurl}/lists/cmd${bits}.txt" >/dev/stderr response=$($curl -L -s ${downloadurl}/lists/cmd${bits}.txt | grep "^${cmd}"$'\t' | grep $'\t'"$OS$") ;; # V 3.2.3: psm deleted ansible | oci | sdk) response=$($curl -L -s ${downloadurl}/lists/zip.txt | grep "^${cmd}"$'\t') ;; esac if [[ "$response" != "" ]]; then newvers=$(echo "$response" | cut -d$'\t' -f2) if [[ "$newvers" != "" ]]; then resultstr=$(compare-version --quiet $curvers $newvers) # echo "resultstr: '$resultstr'." if [[ "$resultstr" = "newer" ]]; then echo " (newer version $newvers available)" fi fi fi fi fi } function DisplayVersion { local stat=0 local installed="" printf "\nInstalled tools:\n\n" printf "tool\tversion\n" > "$scratchfile" # V 3.2.3: opc and psm deleted cmds="grep tail tar sed curl file zip unzip wget telnet nslookup git ansible python3 pip3 bash base32 rclone jq puttygen terraform packer oci sdk" for cmd in $cmds; do installed="" case "$cmd" in bash) cmd="$cmd --min 4.3" # nameref is needed ;; java) cmd="$cmd --min 1.8.0.5 --max 1.8.0" # Needed by glassfish ;; python3) installed=$(check-version python3.9) stat=$? if (( stat != 0 )); then installed=$(check-version /opt/rh/rh-python38/root/usr/bin/python3.8) stat=$? if (( stat != 0 )); then installed=$(check-version python3 --min 3.8) # Needed by oci-cli, 3.3 is needed by psm stat=$? fi fi ;; jq) cmd="$cmd --min 1.5" # Needed by browse-json ;; terraform) cmd="$cmd --min 1.0" # Needed by templates / modules ;; puttygen) cmd="$cmd --min 0.76" # Needed by key creation ;; esac if [[ "$installed" = "" ]]; then installed=$(check-version $cmd) stat=$? fi if (( stat > 0 )); then needinstall=1 if [[ "$proc" = "arm" ]]; then if [[ "$cmd" = "opc" ]]; then printf "%s ${red}(not available for ARM architecture)${normal}\n" "$installed" else printf "%s ${red}(needs to be installed)${normal}\n" "$installed" fi else if [[ "$OS" = "SunOS" && "$cmd" = "puttygen" || "$OS" = "SunOS" && "$cmd" = "opc" ]]; then printf "%s ${red}(not available for Solaris)${normal}\n" "$installed" else printf "%s ${red}(needs to be installed)${normal}\n" "$installed" fi fi else tool=$(echo "$installed" | cut -d' ' -f1) version=$(echo "$installed" | cut -d' ' -f2) okstr=$(echo "$installed" | cut -d' ' -f3) printf "$tool\t$version\n" >> "$scratchfile" if [[ "$okstr" = "need" ]]; then needinstall=1 printf "%s ${red}(needs to be updated)${normal}\n" "$installed" else cmd=$(echo "$installed" | cut -d' ' -f1) vers=$(echo "$installed" | cut -d' ' -f2) found=$(echo "$installed" | cut -d' ' -f3) newerstr=$(CheckNewerVersion "$cmd" "$vers") if [[ "$found" = "ok" ]]; then printf "%s %s ${green}%s${normal}%s\n" "$cmd" "$vers" "$found" "$newerstr" else printf "%s %s ${yellow}%s${normal}%s\n" "$cmd" "$vers" "$found" "$newerstr" fi fi fi done # Reset terminal tset } # Call oci cli and try several times if it fails (maybe because of connection errors) function CallOCI { local max=30 local i=0 local stat=1 if [[ "$oci" != "" ]]; then while [[ $stat -ne 0 && $i -lt $max ]]; do $oci "$@" >"${scratchfile}.pre" 2>"${scratchfile}.err" stat=$? # Increase counter (( i++ )) if (( stat == 0 )); then if [[ -s "${scratchfile}.pre" ]]; then norm-json --quiet --import "${scratchfile}.pre" stat=$? # norm-json failed - normally this should never be the case if (( stat != 0 )); then cat "${scratchfile}.pre" stat=$? fi else cat "${scratchfile}.pre" stat=$? fi else if (( i < max )); then # Command was not successful. Wait for a few seconds until we try again sleep 3 fi fi done DeleteFile "${scratchfile}.pre" fi return $stat } function WriteOCIJson { # Check if we could write to file touch $ocijson > /dev/null 2>&1 stat=$? if (( stat == 0 )); then chmod 600 $ocijson printf '{\n' > $ocijson printf ' "oci": {\n' >> $ocijson printf ' "tenancyname": "%s",\n' $tenancyname >> $ocijson printf ' "tenancyid": "%s",\n' $tenancyid >> $ocijson printf ' "homeregion": "%s",\n' $homeregion >> $ocijson printf ' "homeregionkey": "%s"\n' $hrkey >> $ocijson printf ' },\n' >> $ocijson printf ' "keys": {\n' >> $ocijson printf ' "username": "%s",\n' $username >> $ocijson printf ' "userid": "%s",\n' $authuserid >> $ocijson printf ' "apikey": "%s",\n' $apikey >> $ocijson printf ' "fingerprint": "%s",\n' $fingerprint >> $ocijson printf ' "passphrase": "%s",\n' $passphrase >> $ocijson printf ' "privkey": "%s",\n' $privkey >> $ocijson printf ' "pubkey": "%s"\n' $pubkey >> $ocijson printf ' },\n' >> $ocijson printf ' "s3": {\n' >> $ocijson printf ' "namespace": "%s",\n' $namespace >> $ocijson printf ' "accesskey": "%s",\n' $accesskeyid >> $ocijson printf ' "secretkey": "%s"\n' $secretaccesskey >> $ocijson printf ' }\n' >> $ocijson printf '}\n' >> $ocijson fi return $stat } function WriteProjectJson { # Check if we could write to file touch $projectjson > /dev/null 2>&1 stat=$? if (( stat == 0 )); then chmod 600 $projectjson printf '{\n' > $projectjson printf ' "project": {\n' >> $projectjson printf ' "name": "%s",\n' $projectname >> $projectjson printf ' "compartmentid": "%s",\n' $compartmentid >> $projectjson printf ' "writeuri": "%s",\n' $writeuri >> $projectjson printf ' "readuri": "%s"\n' $readuri >> $projectjson printf ' }\n' >> $projectjson printf '}\n' >> $projectjson fi return $stat } function ReadOCIJson { # Check if json config file exisits and is readable if [[ -r "$ocijson" ]]; then stat=0 else stat=1 fi if (( stat == 0 )); then tenancyname="$(cat "$ocijson" | browse-json oci/tenancyname --select 1 --quiet --raw)" tenancyid="$(cat "$ocijson" | browse-json oci/tenancyid --select 1 --quiet --raw)" homeregion="$(cat "$ocijson" | browse-json oci/homeregion --select 1 --quiet --raw)" username="$(cat "$ocijson" | browse-json keys/username --select 1 --quiet --raw)" authuserid="$(cat "$ocijson" | browse-json keys/userid --select 1 --quiet --raw)" privkey="$(cat "$ocijson" | browse-json keys/privkey --select 1 --quiet --raw)" pubkey="$(cat "$ocijson" | browse-json keys/pubkey --select 1 --quiet --raw)" apikey="$(cat "$ocijson" | browse-json keys/apikey --select 1 --quiet --raw)" fingerprint="$(cat "$ocijson" | browse-json keys/fingerprint --select 1 --quiet --raw)" passphrase="$(cat "$ocijson" | browse-json keys/passphrase --select 1 --quiet --raw)" namespace="$(cat "$ocijson" | browse-json s3/namespace --select 1 --quiet --raw)" accesskeyid="$(cat "$ocijson" | browse-json s3/accesskey --select 1 --quiet --raw)" secretaccesskey="$(cat "$ocijson" | browse-json s3/secretkey --select 1 --quiet --raw)" fi return $stat } function ReadProjectJson { # Check if json config file exisits and is readable if [[ -r "$projectjson" ]]; then stat=0 else stat=1 fi if (( stat == 0 )); then projectname="$(cat "$projectjson" | browse-json project/name --select 1 --quiet --raw)" compartmentid="$(cat "$projectjson" | browse-json project/compartmentid --select 1 --quiet --raw)" writeuri="$(cat "$projectjson" | browse-json project/writeuri --select 1 --quiet --raw)" readuri="$(cat "$projectjson" | browse-json project/readuri --select 1 --quiet --raw)" fi return $stat } function ReadBLZJson { local result="" local stat=1 # Check if json config file exisits and is readable if [[ -r "$blzjson" ]]; then stat=0 fi if [[ $stat -eq 0 && "$jq" != "" ]]; then apikey="$($jq -r '.[] | select(.keys) | .keys[] | select(.id=="oci") | .file' $blzjson)" privkey="$($jq -r '.[] | select(.keys) | .keys[] | select(.id=="opc") | .file' $blzjson)" jhkey="$($jq -r '.[] | select(.keys) | .keys[] | select(.id=="jh") | .file' $blzjson)" opsname="$($jq -r '.[] | select(.compartments) | .compartments[] | select(.id=="ops") | .name' $blzjson)" operationsid="$($jq -r '.[] | select(.compartments) | .compartments[] | select(.id=="ops") | .ocid' $blzjson)" netwname="$($jq -r '.[] | select(.compartments) | .compartments[] | select(.id=="netw") | .name' $blzjson)" networkid="$($jq -r '.[] | select(.compartments) | .compartments[] | select(.id=="netw") | .ocid' $blzjson)" appname="$($jq -r '.[] | select(.compartments) | .compartments[] | select(.id=="app") | .name' $blzjson)" applicationid="$($jq -r '.[] | select(.compartments) | .compartments[] | select(.id=="app") | .ocid' $blzjson)" dbname="$($jq -r '.[] | select(.compartments) | .compartments[] | select(.id=="db") | .name' $blzjson)" dbid="$($jq -r '.[] | select(.compartments) | .compartments[] | select(.id=="db") | .ocid' $blzjson)" if [[ "$opsname" != "" ]]; then projectname="$opsname" else stat=1 fi if [[ "$operationsid" != "" ]]; then result=$(ConvertOCID "$operationsid") if [[ "$result" != "" ]]; then compartmentid="$operationsid" else stat=1 fi else stat=1 fi fi return $stat } function InitOCITool { local tenancyid=${1} local ociregion=${2} local username=${3} local authuserid=${4} local myprivkey=${5} local fingerprint=${6} local passphrase=${7} # Check if .oci folder exists - otherwise create it if [[ ! -d "$ocifolder" ]]; then mkdir -m 0755 -p "$ocifolder" printf "Created folder '%s'.\n" "$ocifolder" fi # Create oci config file from template if it doesn't exists yet if [[ ! -f "$ocicfgfile" ]]; then printf "\nConfiguring tools. This may take a while.\n" if [[ -f "$ocitemplate" ]]; then myprivkey=$(echo "$myprivkey" | sed 's|~/|'${REALHOME}'/|') cat "$ocitemplate" | sed 's||'$tenancyid'|g' | sed 's||'$ociregion'|g' \ | sed 's||'$authuserid'|g' | sed 's||'$myprivkey'|g' \ | sed 's||'$username'|g' | sed 's||'$fingerprint'|g' \ | sed 's||'$passphrase'|g' > $ocicfgfile # if [ "$passphrase" != "" ]; then # echo "pass_phrase=$passphrase" >> $ocicfgfile # fi chmod 600 $ocicfgfile if [[ -f "$ociapitemplate" ]]; then if [[ ! -s "$ociapicfgfile" ]]; then # Create API standard variables oci-api "objectstorage.eu-frankfurt-1.oraclecloud.com" "get" "/n/" >/dev/null 2>&1 fi cat "$ociapitemplate" | sed 's||'$tenancyid'|g' | sed 's||'$passphrase'|g' \ | sed 's||'$ociregion'|g' | sed 's||'$fingerprint'|g' \ | sed 's||'$authuserid'|g' | sed 's||'$myprivkey'|g' \ | sed 's||'$username'|g' >> "$ociapicfgfile" chmod 600 "$ociapicfgfile" if [[ "$passphrase" != "" ]]; then echo "$passphrase" > "$ociapipwdfile" chmod 600 "$ociapipwdfile" fi fi else # No template - create config by user interaction if [[ "$OCI_CLI_CLOUD_SHELL" = "True" ]]; then echo "Nothing to do in Cloud Shell." else $oci setup config fi fi else errormsg 0 "OCI configuration '$ocicfgfile' already exists." fi # Check if oci-cli-rc file exists - otherwise create it if [[ ! -f "$ocircfile" ]]; then CallOCI setup oci-cli-rc --file "$ocircfile" >/dev/null fi } function InitRCLONETool { local cloudtype=${1} local tenancyid=${2} local namespace=${3} local accesskeyid=${4} local secretaccesskey=${5} local stat=1 local i=0 local max=60 # echo "accesskeyid: '$accesskeyid'." # echo "secretaccesskey: '$secretaccesskey'." # Check if .rclone folder exists - otherwise create it if [[ ! -d "$rclonefolder" ]]; then mkdir -m 0755 -p "$rclonefolder" printf "Created folder '$rclonefolder'.\n" fi if [[ -f "$rclonecfgfile" ]]; then errormsg 0 "RCLONE configuration '$rclonecfgfile' already exists." fi # Create config file from template if [[ "$cloudtype" = "ORACLE-OCI" ]]; then if [[ ! -r "$rcocitemplate" ]]; then echo "No template for rclone oci '$rcocitemplate'." else CallOCI iam region-subscription list --tenancy-id "$tenancyid" --all > "$scratchfile" stat=$? ociregions=$(cat "$scratchfile" | convert-json "regionName" --quiet --noheader --output tsv | sort) if [[ "$ociregions" != "" ]]; then touch $rclonecfgfile > /dev/null 2>&1 stat=$? if (( stat == 0 )); then for region in $ociregions; do cat "$rcocitemplate" | sed 's||'$region'|g' | sed 's||'$accesskeyid'|g' \ | sed 's||'$secretaccesskey'|g' | sed 's||'$namespace'|g' >> $rclonecfgfile printf "\n" >> $rclonecfgfile done fi chmod 600 $rclonecfgfile fi fi fi return $stat } function InitTerraformTool { local tenancyname=${1} local tenancyid=${2} local username=${3} local ociregion=${4} local authuserid=${5} local fingerprint=${6} local projectname=${7} local compartmentid=${8} local stat=1 # Check if .terraform.d folder exists - otherwise create it if [[ ! -d "$ocifolder" ]]; then mkdir -m 0755 -p "$ocifolder" printf "Created folder '$ocifolder'.\n" fi # Create profile file from template if [[ ! -r "$tftemplate" ]]; then echo "No template for terraform '$tftemplate'." else myprivkey=$(echo "$myprivkey" | sed 's|~/|'${REALHOME}'/|') cat "$tftemplate" | sed 's||'$tenancyid'|g' | sed 's||'$ociregion'|g' \ | sed 's||'$authuserid'|g' | sed 's||'$tenancyname'|g'\ | sed 's||'$projectname'|g' | sed 's||'$compartmentid'|g' \ | sed 's||'$username'|g' | sed 's||'$fingerprint'|g' > $tfprofilefile chmod 600 $tfprofilefile stat=$? fi return $stat } function InitTerraformProject { local statewriteuri=${1} # Check if projct folder already exists if [[ ! -d "$tfpjfolder" ]]; then # Create folder mkdir -p "$tfpjfolder" # Download terraform files if [[ "$downloadurl" = "$storageurl" ]]; then transfer --quiet ${downloadurl}/zip/multitier.zip --export "${tfpjfolder}/multitier.zip" stat=$? if (( stat == 0 )); then unzip -q "${tfpjfolder}/multitier.zip" -d "$tfpjfolder" filecheck -rm "${tfpjfolder}/multitier.zip" fi else git clone "https://gitlab.com/georg.voell/multitier.git" "$tfpjfolder" 2>/dev/null stat=$? fi if (( stat == 0 )); then # Create profile file from template if [[ ! -r "$tfstatefiletemplate" ]]; then echo "No template for terraform '$tfstatefiletemplate'." else cat "$tfstatefiletemplate" | sed 's||'$statewriteuri'|g' > $tfpjstatefile chmod 600 $tfpjstatefile fi echo "Please deploy your infrastructure with:" printf "\nsource %s\n" "$tcfgfile" printf "cd %s\n" "$tfpjfolder" echo "terraform init" echo "terraform apply" else echo "Unable to download multitier git repository." fi fi } function InitPSMTool { local tenancyid=${1} local ociregion=${2} local username=${3} local stat=0 local url="" local region="" # psmfolder="${REALHOME}/.psm/conf" # psmcfgfile="${psmfolder}/setup.conf" # psmtemplate="${templatesfolder}/psm/psm.template" # printf "tenancyid: '%s'.\n" "$tenancyid" # printf "ociregion: '%s'.\n" "$ociregion" # printf "username: '%s'.\n" "$username" # Check if psm and oci can be used psm=$(filecheck -x psm) if [[ "$psm" = "" ]]; then stat=1 else # Check if psm was already configured if [[ -r "$psmcfgfile" ]]; then confirm "Tool 'psm' already configured. Delete old configuration?" --yes "y/[yes]" --no "n/no" stat=$? if (( stat == 0 )); then $psm cleanup --force true >/dev/null 2>&1 stat=$? fi fi # Check if psm is already initialized if [[ ! -r "$psmcfgfile" && "$tenancyid" != "" && "$username" != "" && "$ociregion" != "" ]]; then # Source .admintools if it is available before first usage of oci cli if [[ -r "$tcfgfile" ]]; then source "$tcfgfile" fi # Get oci provider infos CallOCI iam identity-provider list --compartment-id $tenancyid --protocol SAML2 > "$scratchfile" stat=$? result=$(filecheck -sl "$scratchfile") if [[ $stat -eq 0 && "$result" != "" ]]; then url=$(browse-json --quiet --select 1 --import "$scratchfile" "metadataUrl") if [[ "$url" = "" ]]; then url=$(browse-json --quiet --select 1 --import "$scratchfile" "redirectUrl") fi if [[ "$url" != "" ]]; then idcs=$(echo "$url" | cut -d'/' -f3 | cut -d'.' -f1) fi fi # Get region from oci region region=$(echo "$ociregion" | cut -d'-' -f1) case "$region" in ap) region="aucom" ;; eu | uk | il | me | af) region="emea" ;; *) region="us" esac # echo "idcs: '$idcs'." # echo "region: '$region'." # Create profile file from template if [[ ! -r "$psmtemplate" ]]; then echo "No template for psm '$psmtemplate'." stat=2 else if [[ "$idcs" != "" && "$region" != "" ]]; then stat=1 while (( stat != 0 )); do printf "Enter password for user '$username': " read -s url printf "\n" cat "$psmtemplate" | sed 's||'$idcs'|g' | sed 's||'$region'|g' \ | sed 's||'$username'|g' | sed 's||'$url'|g' > "$scratchfile" $psm setup -c "$scratchfile" >/dev/null 2>&1 stat=$? if [[ ! -r "$psmcfgfile" ]]; then confirm "Tool 'psm' configuration failed (maybe wrong password). Abort?" --yes "y/[yes]" --no "n/no" stat=$? else echo "Tool 'psm' configured." fi done else stat=3 fi fi else stat=4 fi fi return $stat } function ShrinkString { local str=${1} local slen=${2} local size=0 if [[ "$str" != "" ]]; then size=$(printf "$str" | wc -m) if [[ "$slen" = "" ]]; then slen=$size fi if (( size > slen )); then (( slen-- )) echo "${str:0:$slen}*" else echo "$str" fi fi } # Get all compartments an write them to file function GetCompartments { local cid=${1} local stat=1 # To list all compartments, add: --compartment-id-in-subtree true CallOCI iam compartment list --compartment-id $cid --all --compartment-id-in-subtree true > "$scratchfile" stat=$? result=$(filecheck -sl "$scratchfile") if [[ $stat -eq 0 && "$result" != "" ]]; then cat "$scratchfile" | convert-json "lifecycleState,id,name,description" --quiet --noheader --output tsv > "${scratchfile}.temp" result=$(filecheck -sl "${scratchfile}.temp") if [[ "$result" != "" ]]; then printf "name\tdescription\tid\n" > "${scratchfile}.comp" while IFS=$'\t' read -r state id name description; do if [[ "$state" = "ACTIVE" && "$name" != "ManagedCompartmentForPaaS" ]]; then description=$(ShrinkString "$description" 40) printf "%s\t%s\t%s\n" "$name" "$description" "$id" >> "${scratchfile}.comp" fi done < "${scratchfile}.temp" fi # Did we found at least one compartment? result=$(filecheck -sl "${scratchfile}.comp") if [[ "$result" = "" ]]; then filecheck -rm "${scratchfile}.comp" stat=1 fi filecheck -rm "${scratchfile}.temp" fi return $stat } # Write a new entrry to passphrase file function WriteToPassphraseFile { local username=${1} local passphrase=${2} # Create passphrase file - if does not exists yet if [[ ! -f "$ppfile" ]]; then printf "username\tpassphrase\n" > "$ppfile" chmod 600 "$ppfile" fi # Check if passphrase was already stored result=$(grep -v "^$username " $ppfile) if [[ "$result" != "" ]]; then mv -f "$ppfile" "${scratchfile}.pp" cat "${scratchfile}.pp" | grep -v "^$username " > "$ppfile" chmod 600 "$ppfile" rm -f "${scratchfile}.pp" fi # Write username and passphrase to ppfile printf "%s\t%s\n" "$username" "$passphrase" >> "$ppfile" } # Get the passphrase from ppfile function GetPassphraseFromPassphraseFile { local username=${1} local pp="" if [[ "$username" != "" ]]; then if [[ -r "$ppfile" ]]; then pp="$(grep "^$username " "$ppfile" | cut -d$'\t' -f2)" fi fi echo "$pp" } # Return Namespace of Tenancy function GetNamespace { # set some defaults local stat=1 local max=120 local i=0 local ns="" if [[ "$oci" != "" ]]; then while [[ $stat -ne 0 && $i -lt $max ]]; do ns=$(echo "n" | $oci os ns get 2>/dev/null) stat=$? if [[ $stat -eq 0 && "$ns" != "" ]]; then # ns=$(echo "$ns" | browse-json data --select 1 --quiet) ns=$(echo "$ns" | norm-json --select 1 --quiet) stat=$? if [[ $stat -eq 0 && "$ns" != "" ]]; then echo "$ns" return $stat fi fi (( i++ )) sleep 3 done fi return $stat } # Access to Object Storage (needed by rclone) function CreateSecretKey { # Set some defaults local stat=1 local result="" CallOCI iam customer-secret-key create --display-name "S3 Access" --user-id "$authuserid" > "$scratchfile" stat=$? result=$(filecheck -s "$scratchfile") if [[ $stat -eq 0 && "$result" != "" ]]; then accesskeyid=$(cat "$scratchfile" | browse-json id --select 1 --quiet) s3id="$accesskeyid" secretaccesskey=$(cat "$scratchfile" | browse-json key --select 1 --quiet) return $stat else stat=1 fi return $stat } function CreateSSHKey { local userstr=${1} local inp1="" local inp2="" local pp="" local addparam="" local stat=1 if [[ "$userstr" != "" ]]; then while (( stat != 0 )); do printf "\nEnter new private key passphrase for key '$userstr': " read -s inp1 printf "\n" if [[ "$inp1" = "" ]]; then confirm "Leaving passphrase empty is insecure. Do you want to continue without it?" --yes "y/yes" --no "n/[no]" stat=$? else inp2=$(printf "${#inp1}") if (( inp2 < 5 )); then printf "Passphrase has to have at least 5 chars.\n" stat=1 else printf "Repeat the passphrase: " read -s inp2 printf "\n" if [[ "$inp1" = "$inp2" ]]; then stat=0 else printf "Passphrase not equal.\n" stat=1 fi if (( stat == 0 )); then pp="$inp1" if [[ "$userstr" = "$tenancyname" ]]; then tenantpassphrase="$pp" else passphrase="$pp" fi fi fi fi if (( stat == 0 )); then if [[ "$downloadurl" = "$storageurl" ]]; then addparam="local" else addparam="" fi if [[ "$pp" = "" ]]; then key-management create $addparam --username "$userstr" stat=$? else key-management create $addparam --username "$userstr" --passphrase "$pp" stat=$? # Write passphase to file WriteToPassphraseFile "$userstr" "$pp" fi fi done fi # Reset terminal tset return $stat } function ImportPrivateKey { local userstr=${1} local keyfile=${2} local stat=1 if [[ "$userstr" != "" && "$keyfile" != "" ]]; then if [[ -r "$keyfile" ]]; then confirm "\nPrivate Key found at '$keyfile'. Import it?" --yes "y/[yes]" --no "n/no" stat=$? if (( stat == 0 )); then # Existing key found - try to import key-management import "$keyfile" --username "$userstr" stat=$? if (( stat > 0 )); then errormsg 0 "Creating new key instead of using '$keyfile'." else if [[ "$userstr" = "$tenancyname" ]]; then tenantpassphrase=$(GetPassphraseFromPassphraseFile "$userstr") else passphrase=$(GetPassphraseFromPassphraseFile "$userstr") fi fi fi fi fi return $stat } # Check if oci cli works with defined API key function CheckOCIConfig { local userstr=${1} local fp=${2} local configfile=${3} local stat=0 local result="" if [[ ! -r "$configfile" || "$userstr" = "" || "$fp" = "" ]]; then stat=1 else result=$(grep "^\[$userstr\]" "$configfile") if [[ "$result" = "" ]]; then # User is not defined in config file stat=2 else result=$(grep "^fingerprint=$fp" "$configfile") if [[ "$result" = "" ]]; then # Fingerprint is not defined in config file stat=3 else export OCI_CLI_AUTH="api_key" export OCI_CLI_CONFIG_FILE="$configfile" export OCI_CLI_PROFILE="$userstr" # Check if configuration works result=$(GetNamespace) stat=$? if [[ $stat -gt 0 || "$result" = "" ]]; then stat=4 fi fi fi fi return $stat } function InitTools { # set some defaults stat=0 apicap="" secretcap="" # Check if json config exists - the get all infos from there if [[ -r "$ocijson" ]]; then ReadOCIJson stat=$? if [[ ! -f "$ocicfgfile" ]]; then # Get passphrase if possible # passphrase=$(GetPassphraseFromPassphraseFile "$username") # Init OCI InitOCITool "$tenancyid" "$homeregion" "$username" "$authuserid" "$apikey" "$fingerprint" "$passphrase" CheckOCIConfig "$username" "$fingerprint" "$ocicfgfile" stat=$? if (( stat > 0 )); then # OCI not configured printf "\n" exitcode=5 errormsg $exitcode "Tool 'oci' not configured accordingly." "Code: $stat" # API Key does not work: Unexpected Error Cleanup exit $exitcode else printf "\nTool 'oci' configured.\n" fi else printf "\nTool 'oci' already configured.\n" # Source .admintools to set needed environment variables if [[ -r "$tcfgfile" ]]; then source "$tcfgfile" fi fi else # Check if CloudShell is active if [[ "$OCI_CLI_CLOUD_SHELL" = "True" ]]; then printf "\nCollecting needed infos from cloud.\n" # Source .admintools to set needed environment variables if [[ -r "$tcfgfile" ]]; then source "$tcfgfile" fi # Check if we can use oci namespace=$(GetNamespace) stat=$? # Namespace is set if oci is installed and configured if [[ $stat -eq 0 && "$namespace" != "" ]]; then if [[ "$OCI_TENANCY" != "" ]]; then tenancyid="$OCI_TENANCY" stat=0 else tenancyid=$(CallOCI iam compartment list --all | browse-json compartmentId --select 1 --quiet) stat=$? fi if [[ $stat -eq 0 && "$tenancyid" != "" ]]; then CallOCI iam tenancy get --tenancy-id $tenancyid > "$scratchfile" stat=$? if (( stat == 0 )); then tenancyname=$(browse-json name --import "$scratchfile" --select 1 --quiet) hrkey=$(browse-json homeRegionKey --import "$scratchfile" --select 1 --quiet) if [[ "$tenancyname" != "" && "$hrkey" != "" ]]; then ### homeregion=$($oci iam region-subscription list | convert-json --quiet --noheader --output tsv | grep "true" | cut -d$'\t' -f3) homeregion=$(CallOCI iam region list --all | convert-json --quiet --output tsv | grep "^$hrkey " | cut -d$'\t' -f2) fi else # Unfortunately we don't have rights to get tenancy details homeregion="$OCI_REGION" CallOCI iam compartment get --compartment-id $tenancyid > "$scratchfile" stat=$? if (( stat == 0 )); then # Name of the root compartment tenancyname=$(cat "$scratchfile" | browse-json name --select 1 --quiet) else tenancyname="UNKNOWN" fi fi else exitcode=5 errormsg $exitcode "Unexpected error. Unable to detect tenancyid." Cleanup exit $exitcode fi # Userinfo csuser="" if [[ -r "$ociapicfgfile" ]]; then csuser=$(grep "^export API_USER_ID=" "$ociapicfgfile" | head -n 1 | cut -d'"' -f2) elif [[ -r "$ocicfgfile" ]]; then csuser=$(grep "^user=" "$ocicfgfile" | head -n 1 | cut -d'=' -f2) else if [[ "$OCI_CS_USER_OCID" != "" ]]; then csuser=$(echo "$OCI_CS_USER_OCID" | cut -d'/' -f2) fi fi if [[ "$csuser" = "" ]]; then csuser=$(echo "$REALUSER" | tr '_' '.') fi printf "\nWe need a user where we can attach the API key (needed for OCI CLI and terraform).\n" printf "Normally this is your account but also a technical user account can be useed here.\n" # Get a list for all users CallOCI iam user list --all > "$scratchfile" stat=$? result=$(filecheck -s "$scratchfile") if [[ $stat -eq 0 && "$result" != "" ]]; then cat "$scratchfile" | convert-json "name,id" --quiet --output tsv > "${scratchfile}.user" result=$(filecheck -s "${scratchfile}.user") if [[ "$result" != "" ]]; then stat=1 while (( stat != 0 )); do if [[ "$csuser" != "" ]]; then user=$(grep "$csuser" "${scratchfile}.user") else user="" fi if [[ "$user" = "" ]]; then printf "\nPlease choose your account from list (by number):\n" select-table --import "${scratchfile}.user" --export "$scratchfile" stat=$? if (( stat == 0 )); then user=$(cat "$scratchfile") csuser="$(echo "$user" | head -n 1 | cut -d$'\t' -f1)" else csuser="$oldcsuser" if [[ "$csuser" != "" ]]; then user=$(grep "$csuser" "${scratchfile}.user") else user="" fi fi fi username="$(echo "$user" | head -n 1 | cut -d$'\t' -f1)" authuserid="$(echo "$user" | head -n 1 | cut -d$'\t' -f2)" confirm "\nIs this your account name: '$username'?" --yes "y/[yes]" --no "n/no" stat=$? if (( stat == 0 )); then # Get all infos about user CallOCI iam user get --user-id $authuserid > "$scratchfile" result=$(filecheck -s "$scratchfile") if [[ "$result" != "" ]]; then apicap=$(cat "$scratchfile" | browse-json capabilities/canUseApiKeys --select 1 --quiet) secretcap=$(cat "$scratchfile" | browse-json capabilities/canUseCustomerSecretKeys --select 1 --quiet) if [[ "$apicap" != "true" || "$secretcap" != "true" ]]; then echo "User cannot attach API keys or create User Secret Keys - Please choose another user." csuser="" stat=1 fi else echo "Could not locate user - Please choose another user." csuser="" stat=1 fi else oldcsuser="$csuser" csuser="" fi done # printf "\n" if [[ "$username" != "" ]]; then username="$(basename $username)" fi fi fi else printf "\n" exitcode=5 errormsg $exitcode "Unexpected error. Please exit CloudShell and reconnect again." Cleanup exit $exitcode fi else printf "\nNo Cloud Shell and no JSON info files. Exiting.\n" Cleanup exit 5 fi fi # We only create the keys if they do not already exist if [[ ! -r "$ocijson" ]]; then passphrase="" keys=$(key-management list tsv --username "$username" | tailfromline2 | grep " current ") if [[ "$keys" = "" ]]; then # We don't have api keys created yet printf "\nCreating ssh keys for User.\n" ImportPrivateKey "$username" "${REALHOME}/.oci/oci_api_key.pem" stat=$? if (( stat > 0 )); then # Import of existing key failed or key does not exists yet CreateSSHKey "$username" fi # Get key infos keys=$(key-management list tsv --username "$username" | tailfromline2 | grep " current ") else # Get passphrase if possible passphrase=$(GetPassphraseFromPassphraseFile "$username") fi # Get api Key and Fingerprint fingerprint=$(echo "$keys" | cut -d$'\t' -f4) apikey=$(echo "$keys" | cut -d$'\t' -f5) # 11.09.2025: .pk8 used by apikey and not privkey if [[ -r "${apikey}.pk8" ]]; then # Prefering this key apikey="${apikey}.pk8" fi # Replace HOME apikey=$(echo "$apikey" | sed 's|^'${REALHOME}'|~|') # Check ssh key for tenancy already exists keys=$(key-management list tsv --username "$tenancyname" | tailfromline2 | grep " current ") if [[ "$keys" = "" ]]; then # We don't have ssh keys created yet printf "\nCreating ssh keys for Tenancy.\n" ImportPrivateKey "$tenancyname" "${REALHOME}/.ssh/id_rsa" stat=$? if (( stat > 0 )); then # Import of existing key failed or key does not exists yet CreateSSHKey "$tenancyname" fi # Get key infos keys=$(key-management list tsv --username "$tenancyname" | tailfromline2 | grep " current ") fi # Get priv Key privkey=$(echo "$keys" | cut -d$'\t' -f5) # Try to find pubkey if [[ -r "${privkey}.pub" ]]; then pubkey="${privkey}.pub" else pubkey="" fi # Replace HOME privkey=$(echo "$privkey" | sed 's|^'${REALHOME}'|~|') pubkey=$(echo "$pubkey" | sed 's|^'${REALHOME}'|~|') fi # We need oci for this if [[ "$oci" != "" && ! -r "$ocijson" ]]; then stat=0 # If user has api key capability - show existing keys and upload api key to user if [[ "$apicap" = "true" ]]; then # Check if our api key is already uploaded CallOCI iam user api-key list --user-id $authuserid > "$scratchfile" stat=$? result=$(filecheck -s "$scratchfile") if [[ "$result" != "" ]]; then # User has api keys - grep the fingerprints fpfound=$(cat "$scratchfile" | convert-json "fingerprint" --quiet --noheader --output tsv | grep "$fingerprint") else fpfound="" fi if [[ "$fpfound" = "" ]]; then # we don't have uploaded the api key yet # We can add max 3 api keys - so check if we can upload one if [[ "$result" != "" ]]; then result=$(cat "$scratchfile" | convert-json "fingerprint" --quiet --noheader --output tsv | wc -l) else result=0 fi if (( result > 2 )); then printf "\n" exitcode=5 errormsg $exitcode "Maximum number of 'API Keys' reached for user '$username' - please delete one first." Cleanup exit $exitcode else stat=1 while (( stat != 0 )); do # Auto upload file key-management show api --username "$username" | grep . > "$scratchfile" CallOCI iam user api-key upload --user-id $authuserid --key-file "$scratchfile" > /dev/null stat=$? if (( stat != 0 )); then # Unable to auto aupload - load the key manually via GUI printf "\nPlease copy this API key to your account in Web-GUI:\n\n" cat "$scratchfile" confirm "\nDid you attach the above public key to your user account?" --yes "y/[yes]" --no "n/no" stat=$? else fpid="$fingerprint" fi if (( stat == 0 )); then CallOCI iam user api-key list --user-id $authuserid > "$scratchfile" result=$(filecheck -s "$scratchfile") if [[ "$result" != "" ]]; then # User has api keys - grep the fingerprints result=$(cat "$scratchfile" | convert-json "fingerprint" --quiet --noheader --output tsv | grep "$fingerprint") fi if [[ "$result" = "" ]]; then confirm "API key could not be found. Try again?" --yes "y/[yes]" --no "n/no" stat=$? if (( stat > 0 )); then # User wants to exit here stat=0 fi else # fpid=$(key-management show fp --username "$username") fpid="$fingerprint" fi fi done fi fi # Check if oci config exists - otherwise create it by configuring oci tool if [[ "$result" != "" && ! -r "$ocicfgfile" ]]; then # Init OCI tool printf "\n" InitOCITool "$tenancyid" "$homeregion" "$username" "$authuserid" "$apikey" "$fingerprint" "$passphrase" # Using new api key CheckOCIConfig "$username" "$fingerprint" "$ocicfgfile" stat=$? if (( stat > 0 )); then # OCI not configured exitcode=5 errormsg $exitcode "Tool 'oci' not configured accordingly." "Code: $stat" # API Key does not work: Unexpected Error Cleanup exit $exitcode else echo "Tool 'oci' configured. Please wait until configuration is switched." # Append new config to .bashrc ### printf 'source %s\n' "$tcfgfile" >> $brcfile fi fi fi # If user has secret key capability - show existing secrets and create a new one if no secret exists if [[ $stat -eq 0 && "$secretcap" = "true" ]]; then CallOCI iam customer-secret-key list --user-id $authuserid > "$scratchfile" result=$(filecheck -s "$scratchfile") if [[ "$result" != "" ]]; then # User has secret keys - check it is less than 2 result=$(cat "$scratchfile" | convert-json "id" --quiet --noheader --output tsv | wc -l) if (( result > 1 )); then printf "\n" exitcode=5 errormsg $exitcode "Maximum number of 'Customer Secret Keys' reached for user '$username' - please delete one first." Cleanup exit $exitcode fi fi if [[ -r "$ocicfgfile" ]]; then # Using new api key CheckOCIConfig "$username" "$fingerprint" "$ocicfgfile" stat=$? if (( stat > 0 )); then exitcode=5 errormsg $exitcode "Unable to use oci cli. Please try '$progstr config' again." "Code: $stat" Cleanup exit $exitcode else # Check if OCI is configured namespace=$(GetNamespace) stat=$? if [[ $stat -gt 0 || "$namespace" = "" ]]; then printf "Unexpected error: Unable to use 'oci'.\n\n" else CreateSecretKey stat=$? printf "\n" if (( stat == 0 )); then echo "Secret-key created." else exitcode=5 errormsg $exitcode "Unable to create secret-key. Please try '$progstr config' again." "Code: $stat" Cleanup exit $exitcode fi fi fi fi fi fi # We should have all infos now - so write them to oci json config if [[ -d "$ocifolder" ]]; then if [[ ! -r "$ocijson" && "$accesskeyid" != "" ]]; then WriteOCIJson stat=$? if (( stat == 0 )); then fpid="" s3id="" fi fi fi # Init rclone if [[ "$rclone" != "" && "$accesskeyid" != "" && ! -f "$rclonecfgfile" ]]; then if [[ -r "$ocicfgfile" ]]; then # Using new api key CheckOCIConfig "$username" "$fingerprint" "$ocicfgfile" stat=$? if (( stat > 0 )); then exitcode=5 errormsg $exitcode "Unable to use oci cli. Please try '$progstr config' again." "Code: $stat" Cleanup exit $exitcode else # Check if OCI is configured namespace=$(GetNamespace) stat=$? if [[ $stat -gt 0 || "$namespace" = "" ]]; then printf "Unexpected error: Unable to use 'oci'.\n\n" else if [[ "$namespace" != "" ]]; then InitRCLONETool "ORACLE-OCI" "$tenancyid" "$namespace" "$accesskeyid" "$secretaccesskey" stat=$? if (( stat == 0 )); then echo "Tool 'rclone' configured." else echo "Tool 'rclone' not configured." fi fi fi # # Check if configuration works # $rclone lsd "${homeregion}:" >/dev/null 2>&1 # stat=$? # if [ $stat -ne 0 ]; then # # rclone not configured # echo "Tool 'rclone' not configured accordingly. Deleting config." # filecheck -rm $rclonecfgfile # fi fi fi else if [[ -f "$rclonecfgfile" ]]; then echo "Tool 'rclone' already configured." else echo "Tool 'rclone' not configured." fi fi # Check if project config exists - then get all infos from there if [[ -r "$projectjson" ]]; then ReadProjectJson stat=$? else # Read Basic Landing Zone infos (if available) if [[ -r "$blzjson" ]]; then ReadBLZJson stat=$? else # Get Projectname and compartment ocid if [[ "$tenancyid" != "" && "$compartmentid" = "" ]]; then printf "\nFor a terraform project, we need to define a compartment. If you don't want to\n" printf "use an existing compartment (preferred), stop here and create your compartment -\n" printf "or create a new one with this tool in the root compartment.\n" stat=1 while (( stat > 0 )); do confirm "\nDoes the compartment exists for your project?" --yes "y/[yes]" --no "n/no" stat=$? if (( stat == 0 )); then if [[ ! -f "${scratchfile}.comp" ]]; then if [[ -r "$ocicfgfile" ]]; then # Using new api key CheckOCIConfig "$username" "$fingerprint" "$ocicfgfile" stat=$? if (( stat > 0 )); then exitcode=5 errormsg $exitcode "Unable to use oci cli. Please try '$progstr config' again." "Code: $stat" Cleanup exit $exitcode else # Check if we can use oci namespace=$(GetNamespace) stat=$? if [[ $stat -gt 0 || "$namespace" = "" ]]; then printf "Unexpected error: Unable to use 'oci'.\n\n" else GetCompartments "$tenancyid" stat=$? fi fi fi fi if (( stat == 0 )); then printf "\nPlaease select a compartment (by number):\n" select-table --import "${scratchfile}.comp" --export "$scratchfile" stat=$? if (( stat == 0 )); then line=$(cat "$scratchfile") if [[ "$line" != "" ]]; then projectname=$(echo "$line" | cut -d' ' -f1) compartmentid=$(echo "$line" | cut -d' ' -f3) printf "\nChoosen compartment: '%s' - id: '%s'.\n" "$projectname" "$compartmentid" confirm "ok?" --yes "y/[yes]" --no "n/no" stat=$? else stat=1 fi fi else printf "\nNo compartment found - please create one.\n" fi else # stat=3 projectname="" compartmentid="" printf "\nPlease enter name and description for new compartment.\n" printf "Name: " read inp if [[ "$inp" != "" ]]; then projectname="$inp" printf "Description: " read inp printf "\n" if [[ "$inp" != "" ]]; then confirm "Name: '$projectname' - Description: '$inp' - ok?" --yes "y/[yes]" --no "n/no" stat=$? if (( stat == 0 )); then CallOCI iam compartment create --name "$projectname" --description "$inp" --compartment-id "$tenancyid" > "$scratchfile" stat=$? if (( stat == 0 )); then compartmentid=$(grep '"id": "' "$scratchfile" | cut -d'"' -f 4) fi fi fi fi if [[ "$projectname" != "" && "" != "$compartmentid" ]]; then printf "\nChoosen compartment: '%s' - id: '%s'.\n" "$projectname" "$compartmentid" stat=0 else stat=1 fi fi done printf "\n" fi fi fi # Create Project Bucket with pre-auth if [[ $stat -eq 0 && "$oci" != "" ]]; then CheckOCIConfig "$username" "$fingerprint" "$ocicfgfile" stat=$? if (( stat > 0 )); then exitcode=5 errormsg $exitcode "Unable to use oci cli. Please try '$progstr config' again." "Code: $stat" Cleanup exit $exitcode else # Check if we can use oci namespace=$(GetNamespace) stat=$? if [[ $stat -eq 0 && "$namespace" != "" ]]; then # Get list of buckts # V 3.2.3 CallOCI os bucket list --all --compartment-id "$compartmentid" --namespace "$namespace" >"$scratchfile" stat=$? result=$(filecheck -s "$scratchfile") if [[ $stat -eq 0 && "$result" != "" ]]; then # 20.09.2025 norm-json already done in CallOCI # bucketlist=$(norm-json --quiet --raw --import "$scratchfile" | grep '"name":' | cut -d'"' -f4) bucketlist=$(cat "$scratchfile" | grep '"name":' | cut -d'"' -f4) if [[ "$bucketlist" != "" ]]; then bucket=$(echo "$bucketlist" | grep '^'${projectname}'$') else bucket="" fi else bucket="" fi if [[ "$bucket" = "" ]]; then # Bucket does not exists yet - create it CallOCI os bucket create --compartment-id "$compartmentid" --namespace "$namespace" --name "$projectname" >/dev/null stat=$? if (( stat == 0 )); then printf "Bucket '%s' created.\n" "$projectname" else printf "Creation of bucket '%s' failed.\n" "$projectname" fi fi if [[ $stat -eq 0 && ! -r "$projectjson" && "$projectname" != "" ]]; then case "$OS" in Darwin) expires1day=$(date -v+1d +'%Y-%m-%d %H:%M' 2>/dev/null) expires10years=$(date -v+10y +'%Y-%m-%d %H:%M' 2>/dev/null) ;; *) expires1day=$(date -d "today + 1 days" +'%Y-%m-%d %H:%M' 2>/dev/null) expires10years=$(date -d "today + 10 years" +'%Y-%m-%d %H:%M' 2>/dev/null) ;; esac CallOCI os preauth-request create --bucket-name "$projectname" --name "BucketWriteAccess" --time-expires "$expires10years" \ --access-type "AnyObjectReadWrite" --bucket-listing-action "ListObjects" >"$scratchfile" stat=$? if (( stat == 0 )); then writeuri=$(browse-json accessUri --import "$scratchfile" --select 1 --quiet) if [[ "$writeuri" != "" ]]; then writeuri="https://objectstorage.${homeregion}.oraclecloud.com${writeuri}" printf "Write PreAuth for bucket '%s' created.\n" "$projectname" preauthwid=$(browse-json id --import "$scratchfile" --select 1 --quiet) else printf "Creation of Write PreAuth for bucket '%s' failed.\n" "$projectname" fi fi CallOCI os preauth-request create --bucket-name "$projectname" --name "BucketReadAccess" --time-expires "$expires10years" \ --access-type "AnyObjectRead" >"$scratchfile" stat=$? if (( stat == 0 )); then readuri=$(browse-json accessUri --import "$scratchfile" --select 1 --quiet) if [[ "$readuri" != "" ]]; then readuri="https://objectstorage.${homeregion}.oraclecloud.com${readuri}" printf "Read PreAuth for bucket '%s' created.\n" "$projectname" preauthrid=$(browse-json id --import "$scratchfile" --select 1 --quiet) else printf "Creation of Read PreAuth for bucket '%s' failed.\n" "$projectname" fi fi fi else exitcode=5 errormsg $exitcode "Unable to use oci cli. Please try '$progstr config' again." "Code: $stat" Cleanup exit $exitcode fi fi fi # We should have all infos now - so write them to project json config if [[ -d "$ocifolder" ]]; then if [[ ! -r "$projectjson" && "$projectname" != "" && "$compartmentid" != "" ]]; then WriteProjectJson stat=$? if (( stat == 0 )); then preauthwid="" preauthrid="" fi fi fi # Init terraform tool=$(filecheck -x terraform) if [[ "$tool" != "" && "$projectname" != "" && "$compartmentid" != "" && ! -f "$tfprofilefile" ]]; then InitTerraformTool "$tenancyname" "$tenancyid" "$username" "$homeregion" "$authuserid" "$fingerprint" "$projectname" "$compartmentid" stat=$? if (( stat == 0 )); then echo "Tool 'terraform' configured." else echo "Tool 'terraform' not configured." fi else if [[ -f "$tfprofilefile" ]]; then echo "Tool 'terraform' already configured." else echo "Tool 'terraform' not configured." fi fi # Create Tools config file # if [ ! -f "$tcfgfile" -a "$username" != "" ]; then if [[ "$username" != "" ]]; then if [[ ! -f "$tcfgfile" && ! -f "$blzjson" ]]; then # Show usage message only the first time printf "\nBefore using cloud tools, call 'source $tcfgfile'.\n" fi printf '# Source this file\n' > $tcfgfile printf '# Allowed values for OCI_CLI_AUTH: api_key, instance_obo_user,\n' >> $tcfgfile printf '# instance_principal, resource_principal, security_token.\n\n' >> $tcfgfile printf '# Needed by oci api\n' >> $tcfgfile printf 'if [[ -r "%s" ]]; then\n' $ociapicfgfile >> $tcfgfile printf ' source %s\n' "$ociapicfgfile" >> $tcfgfile printf 'fi\n\n' >> $tcfgfile printf '# Needed by terraform\n' >> $tcfgfile printf 'if [[ -r "%s" ]]; then\n' $tfprofilefile >> $tcfgfile printf ' source %s\n' "$tfprofilefile" >> $tcfgfile printf 'fi\n\n' >> $tcfgfile printf '# Needed by oci cli\n' >> $tcfgfile printf 'if [[ -r "%s" ]]; then\n' $ocicfgfile >> $tcfgfile printf ' export OCI_CLI_AUTH="api_key"\n' >> $tcfgfile printf ' export OCI_CLI_CONFIG_FILE="%s"\n' "$ocicfgfile" >> $tcfgfile printf ' export OCI_CLI_PROFILE="%s"\n' "$username" >> $tcfgfile printf 'else\n' >> $tcfgfile printf ' if [[ -r "/etc/oci/config" && "$OCI_REGION" != "" ]]; then\n' >> $tcfgfile printf ' export OCI_CLI_AUTH="instance_obo_user"\n' >> $tcfgfile printf ' export OCI_CLI_CONFIG_FILE="/etc/oci/config"\n' >> $tcfgfile printf ' export OCI_CLI_PROFILE="$OCI_REGION"\n' >> $tcfgfile printf ' else\n' >> $tcfgfile printf ' export OCI_CLI_AUTH="instance_principal"\n' >> $tcfgfile printf ' unset OCI_CLI_CONFIG_FILE\n' >> $tcfgfile printf ' unset OCI_CLI_PROFILE\n' >> $tcfgfile printf ' fi\n' >> $tcfgfile printf 'fi\n\n' >> $tcfgfile # Create Link if [[ ! -f "${infofolder}/.admintools" ]]; then if [[ "$USER" != "root" ]]; then check-sudo stat=$? if (( stat == 0 )); then sudo ln -s $tcfgfile "${infofolder}/.admintools" 2>/dev/null fi else ln -s $tcfgfile "${infofolder}/.admintools" 2>/dev/null fi fi fi return $stat } # Update mandb with new manuals function UpdateWhatis { # Create mandb case "$OS" in Darwin) makewhatis=$(filecheck -x "/usr/libexec/makewhatis") if [[ "$makewhatis" != "" ]]; then filecheck -rm "${manfolder}/whatis" $makewhatis "${manfolder}" > /dev/null 2>&1 fi ;; Linux) mandb=$(filecheck -x mandb) if [[ "$mandb" != "" ]]; then $mandb "${manfolder}" > /dev/null 2>&1 fi ;; SunOS) catman=$(filecheck -x catman) if [[ "$catman" != "" ]]; then $catman -M "${manfolder}" > /dev/null 2>&1 fi ;; esac if [[ "$needchown" = true ]]; then chown -fR ${REALUSER}:$REALGROUP $manfolder fi } function UpdateOS { # Update the whole OS printf "\n" echo "Will update the OS now. This may takes a couple of minutes." echo "Please do not stop the script while updating." case "$id_like" in fedora) yum=$(filecheck -x yum) if [[ "$yum" != "" ]]; then sudo $yum -y upgrade | tee --append $logfile # Move new repo files repodir="/etc/yum.repos.d" repofiles=$(ls ${repodir}/*.repo 2>/dev/null) rpmnewfiles=$(ls ${repodir}/*.rpmnew 2>/dev/null) if [[ "$rpmnewfiles" != "" ]]; then if [[ ! -d ${repodir}/old ]]; then sudo mkdir ${repodir}/old fi fi for rfile in $repofiles; do if [[ -f ${rfile}.rpmnew ]]; then sudo mv -f $rfile ${repodir}/old sudo mv -f ${rfile}.rpmnew $rfile echo "Old repo file '$rfile' moved to '${repodir}/old'." fi done fi ;; debian) aptget=$(filecheck -x apt-get) if [[ "$aptget" != "" ]]; then sudo $aptget -y update | tee --append $logfile sudo $aptget -y upgrade | tee --append $logfile fi ;; suse) zypper=$(filecheck -x zypper) if [[ "$zypper" != "" ]]; then sudo $zypper up | tee --append $logfile fi ;; alpine) apk=$(filecheck -x apk) if [[ "$apk" != "" ]]; then sudo $apk update | tee --append $logfile sudo $apk upgrade | tee --append $logfile fi ;; *) echo "Can't update OS for Linux Type '$id_like'." esac echo "OS update completed." } function CallTerraform { local cmd=${1} local currdir=$(pwd) local firstarg="" local moreargs="" local stat=0 if [[ "$cmd" != "" ]]; then if [[ ! -d "$tfpjfolder" ]]; then printf "\nFolder '%s' does not exists. Please create it first with '$progstr setup'.\n" "$tfpjfolder" else if [[ -r "$tcfgfile" ]]; then source "$tcfgfile" # Source .admintools to set needed environment variables cd "${tfpjfolder}" firstarg=$(echo "$cmd" | cut -d' ' -f1) moreargs=$(echo "$cmd" | cut -d' ' -f2-) if [[ "$moreargs" = "$firstarg" ]]; then moreargs="" fi if [[ "$OCI_CLI_CLOUD_SHELL" != "True" ]]; then if [[ "$firstarg" = "destroy" || "$firstarg" = "apply" && "$moreargs" = "-destroy" ]]; then printf "\nNot recommended to destroy all resources outside Cloud Shell.\n" confirm "Do you want to continue and destroy all resources?" --yes "y/yes" --no "n/[no]" stat=$? if (( stat > 0 )); then return 1 fi fi fi if [[ "$firstarg" != "init" ]]; then printf "\n" fi if [[ "$firstarg" = "plan" || "$firstarg" = "apply" || "$firstarg" = "destroy" ]]; then terraform init >/dev/null 2>&1 stat=$? if (( stat > 0 )); then # May need newer version if [[ -f ".terraform.lock.hcl" ]]; then rm -f ".terraform.lock.hcl" terraform init >/dev/null 2>&1 stat=$? fi fi if (( stat > 0 )); then printf "Unable to initialize terraform. Stopping here.\n" else # Validate terraform code terraform validate stat=$? fi fi # Call terraform with parameter if (( stat == 0 )); then terraform $cmd # 2>&1 | grep -v "\[DEBUG\] GET https://objectstorage.eu-frankfurt-1.oraclecloud.com/" stat=$? fi cd "$currdir" else printf "\nFile '%s' does not exists. Please create it first with '%s config'.\n" "$tcfgfile" "$progstr" fi fi else printf "\nNo options specified. Usage e.g.: '$progstr terraform \"apply -auto-approve\"'.\n" fi return $stat } function CallTerraformOutput { local cmd=${1} local python=$(filecheck -x python) local stat=0 terraform -chdir="${tfpjfolder}" $cmd -json 2>/dev/null >"${scratchfile}.out" stat=$? if [[ "$jq" != "" ]]; then terraform -chdir="${tfpjfolder}" $cmd -json 2>/dev/null | $jq -M . >"${scratchfile}.out" stat=$? else terraform -chdir="${tfpjfolder}" $cmd -json 2>/dev/null | $python -m json.tool >"${scratchfile}.out" stat=$? fi if (( stat == 0 )); then if [[ "$jq" != "" ]]; then cat "${scratchfile}.out" | $jq -M . else if [[ "$python" != "" ]]; then cat "${scratchfile}.out" | $python -m json.tool else cat "${scratchfile}.out" fi fi fi # Cleanup and exit filecheck -rm "${scratchfile}.out" return $stat } # Preset param1="" param2="" # Check parameters: Loop until all parameters are used up while [[ $# -gt 0 ]]; do pname=${1} case "$pname" in -v | --version) shift showversion=true ;; -h | --help) shift showhelp=true ;; *) shift if [[ "$pname" == -* ]]; then # Options begin with '-' errstr="Unknown option '$pname'." else if [[ "$param1" = "" ]]; then param1="$(ToLower "$pname")" else if [[ "$param2" = "" ]]; then param2="$pname" else errstr="Unknown additional parameter: '$pname'." fi fi fi esac done # Plausibility check if [[ "$param1" != "" ]]; then if [[ "$param1" != "update" && "$param1" != "remove" && "$param1" != "config" && "$param1" != "setup" && "$param1" != "terraform" && "$param1" != "push" ]]; then errstr="Unknown action '$param1'." fi fi # Check if setup-tools is alrady running result=$(ps -ef | grep "${progstr}$" | grep -v "grep" | tr -s ' ' | wc -l) if [[ $result -gt 2 && "$IGNORERUNNING" = "" ]]; then errstr="Tool '$progstr' already running. Please wait until this has finished." fi # Display help or error message DisplayHelp # Main export LOGFILE=$logfile # Define default variables firsttime=false # If script is called the first time, set this to true needsudo=false # We could install all scripts with user rights needchown=false # Need to change filerights toolsname="tools" scriptsname="scripts" templatesname="templates" # Look for needed tools oci=$(filecheck -x oci) jq=$(filecheck -x jq) rclone=$(filecheck -x rclone) # Check if we laready installed the scripts result=$(filecheck -x /usr/local/bin/$progstr) if [[ "$result" != "" ]]; then userhome="/usr/local" if [[ "$USER" != "root" ]]; then needsudo=true fi else result=$(filecheck -x ${REALHOME}/.local/bin/$progstr) if [[ "$result" != "" ]]; then userhome="${REALHOME}/.local" if [[ "$USER" = "root" ]]; then needchown=true fi else # We install the first time firsttime=true if [[ "$USER" = "root" ]]; then userhome="/usr/local" else userhome="${REALHOME}/.local" fi fi fi binfolder="${userhome}/bin" libfolder="${userhome}/lib" # lib64 manfolder="${userhome}/share/man" infofolder="${userhome}/share/info" appfolder="${userhome}/share/applications" templatesfolder="${userhome}/share/$templatesname" toolsfile="${infofolder}/installed-${toolsname}.txt" scriptsfile="${infofolder}/installed-${scriptsname}.txt" manfile="${infofolder}/installed-manuals.txt" manfile2="${infofolder}/installed-cmd-manuals.txt" templatesfile="${infofolder}/installed-${templatesname}.txt" zipsfile="${infofolder}/installed-zips.txt" libsfile="${infofolder}/installed-libs.txt" sshconfig="${REALHOME}/.ssh/config" keyshome="${REALHOME}/.ssh/keys" brcfile="${REALHOME}/.bashrc" tcfgfile="${REALHOME}/.admintools" ocifolder="${REALHOME}/.oci" ppfile="${ocifolder}/passphrase.txt" ocicfgfile="${ocifolder}/config" ociapicfgfile="${ocifolder}/api-config" ociapipwdfile="${ocifolder}/api-passwd" ocircfile="${ocifolder}/oci_cli_rc" ocijson="${ocifolder}/config.json" projectjson="${ocifolder}/project.json" blzjson="${ocifolder}/blz.json" ocitemplate="${templatesfolder}/oci/oci.template" ociapitemplate="${templatesfolder}/oci/api.template" #psmfolder="${REALHOME}/.psm/conf" #psmcfgfile="${psmfolder}/setup.conf" #psmtemplate="${templatesfolder}/psm/psm.template" rclonefolder="${REALHOME}/.config/rclone" rclonecfgfile="${rclonefolder}/rclone.conf" rcocitemplate="${templatesfolder}/rclone/oci.template" # rcopctemplate="${templatesfolder}/rclone/opc.template" tfprofilefile="${ocifolder}/tf-config" tftemplate="${templatesfolder}/terraform/profile.template" tfpjfolder="${REALHOME}/tf/multitier" tfpjstatefile="${tfpjfolder}/statefile.tf" tfstatefiletemplate="${templatesfolder}/terraform/statefile.template" cloudfile="${infofolder}/cloud.json" platformfile="${infofolder}/platform.json" # Set some more defaults stat=0 username="" passphrase="" namespace="" homeregion="" tenancyid="" tenancyname="" authuserid="" fingerprint="" privkey="" apikey="" pubkey="" projectname="" writeuri="" readuri="" compartmentid="" s3id="" fpid="" preauthwid="" preauthrid="" # Reset the terminal #if [ "$IGNORERUNNING" = "" ]; then # reset #fi if [[ "$param1" = "remove" ]]; then if [[ "$needsudo" = true ]]; then if [[ "$USER" != "root" ]]; then check-sudo stat=$? if (( stat == 0 )); then export IGNORERUNNING="true" # sudo --preserve-env "$0" remove sudo --preserve-env=PATH "$0" remove stat=$? exit $stat else errormsg 3 "Root privileges needed to delete scripts." fi fi fi echo "$progstr $param1" | ToUpper > "$scratchfile" printf "\n" print-header --import "$scratchfile" printf "\n" # Check if CloudShell is active if [[ "$OCI_CLI_CLOUD_SHELL" = "True" ]]; then # Try to remove terraform folder if state is empty if [[ -d "$tfpjfolder" ]]; then result=$(CallTerraformOutput show | wc -l) if (( result > 3 )); then errormsg 5 "Folder '$tfpjfolder' exists and statefile not empty. Please delete resources first with '$progstr terraform destroy'." rm -f "$scratchfile" exit 5 else # Ask for remove terraform project confirm "Do you want to remove folder '$tfpjfolder' (terraform project)?" --yes "y/[yes]" --no "n/no" stat=$? if (( stat == 0 )); then rm -fR "$tfpjfolder" stat=$stat if (( stat == 0 )); then printf "Folder '$tfpjfolder' deleted.\n\n" fi else printf "Skipped.\n\n" fi fi fi # Look for oci cli tool and check if we can use it stat=1 if [[ "$oci" != "" ]]; then if [[ -r "$tcfgfile" ]]; then source "$tcfgfile" # Source .admintools to set needed environment variables fi namespace=$(GetNamespace) stat=$? if (( stat > 0 )); then printf "Unexpected error: Unable to use 'oci'.\n\n" fi fi if [[ ! -d "$tfpjfolder" && $stat -eq 0 ]]; then # Read json config file ReadProjectJson stat=$? if (( stat == 0 )); then confirm "Do you want to delete bucket '$projectname' (terraform project)?" --yes "y/[yes]" --no "n/no" stat=$? if (( stat == 0 )); then # Remove bucket CallOCI os bucket delete --name "$projectname" --namespace "$namespace" --empty --force >/dev/null stat=$? if (( stat == 0 )); then printf "Bucket '$projectname' deleted.\n\n" # Delete config files filecheck -rm "$projectjson" filecheck -rm "$tfprofilefile" fi else printf "Skipped.\n\n" stat=0 fi fi fi if (( stat == 0 )); then # Read json config file ReadOCIJson stat=$? if (( stat == 0 )); then confirm "Do you want to detach keys from user (if found) and delete oci configuration files?" --yes "y/[yes]" --no "n/no" stat=$? if (( stat == 0 )); then # Check if user exists and was not already deleted CallOCI iam user list --name "$username" > "$scratchfile" stat=$? if [[ $stat -eq 0 && -s "$scratchfile" ]]; then # User exisits CallOCI iam customer-secret-key delete --user-id "$authuserid" --customer-secret-key-id "$accesskeyid" --force >/dev/null stat=$? if (( stat == 0 )); then CallOCI iam user api-key delete --user-id "$authuserid" --fingerprint "$fingerprint" --force >/dev/null stat=$? if (( stat == 0 )); then printf 'Keys (api-key and secret-key) detached from user '%s'.\n' "$username" else printf 'Unable to detach api-key '%s'.\n' "$fingerprint" fi else printf 'Unable to detach secret-key '%s'.\n' "$accesskeyid" fi fi if (( stat == 0 )); then # Rename rclone config file if [[ -f "$rclonecfgfile" ]]; then mv -f "$rclonecfgfile" "${rclonecfgfile}.old" fi # Rename oci config file if [[ -f "$ocicfgfile" ]]; then mv -f "$ocicfgfile" "${ocicfgfile}.old" fi # Delete config files filecheck -rm "$ociapicfgfile" filecheck -rm "$ociapipwdfile" filecheck -rm "$ocircfile" filecheck -rm "$ocijson" # filecheck -rm "$psmcfgfile" # filecheck -rm "$tcfgfile" # .admintools # Remove folder if they are empty rmdir "$ocifolder" 2>/dev/null rmdir "$rclonefolder" 2>/dev/null # rmdir "$psmfolder" 2>/dev/null printf "Configuration (oci) deleted.\n\n" fi else printf "Skipped.\n\n" fi fi fi else if [[ -f "$projectjson" || -f "$ocijson" ]]; then confirm "Do you want to delete oci configuration files?" --yes "y/[yes]" --no "n/no" stat=$? if (( stat == 0 )); then # Rename rclone config file if [[ -f "$rclonecfgfile" ]]; then mv -f "$rclonecfgfile" "${rclonecfgfile}.old" fi # Rename oci config file if [[ -f "$ocicfgfile" ]]; then mv -f "$ocicfgfile" "${ocicfgfile}.old" fi # Not in Cloud Shell - delete config files filecheck -rm "$projectjson" filecheck -rm "$tfprofilefile" filecheck -rm "$ociapicfgfile" filecheck -rm "$ociapipwdfile" filecheck -rm "$ocircfile" filecheck -rm "$ocijson" # filecheck -rm "$psmcfgfile" # filecheck -rm "$tcfgfile" # .admintools # Remove folder if they are empty rmdir "$ocifolder" 2>/dev/null rmdir "$rclonefolder" 2>/dev/null # rmdir "$psmfolder" 2>/dev/null printf "Configuration (oci) deleted.\n\n" else printf "Skipped.\n\n" fi fi fi # Only delete keys if configuration is deleted if [[ ! -f "$projectjson" && ! -f "$ocijson" ]]; then key-management list > "$scratchfile" result=$(head -n 1 "$scratchfile" | grep "^No keys") if [[ "$result" = "" ]]; then grep . "$scratchfile" confirm "\nDo you want to remove the keys from above?" --yes "y/[yes]" --no "n/no" stat=$? if (( stat == 0 )); then rm -fR "$keyshome" mv -f $sshconfig ${sshconfig}.old printf "Renamed '$sshconfig' to '${sshconfig}.old'.\n" printf "Keys deleted.\n\n" else printf "Skipped.\n\n" fi fi rm -f "$scratchfile" fi # Check if we have print-table available pt=$(filecheck -x print-table) if [[ -r $manfile || -r $manfile2 ]]; then printf "man1\tversion\n" > "$scratchfile" if [[ -r $manfile ]]; then tailfromline2 $manfile >> "$scratchfile" fi if [[ -r $manfile2 ]]; then tailfromline2 $manfile2 >> "$scratchfile" fi result=$(filecheck -sl "$scratchfile") if [[ "$result" != "" ]]; then if [[ "$pt" != "" ]]; then "$pt" --import "$scratchfile" else cat "$scratchfile" fi # Ask for remove manuals confirm "\nDo you want to remove the manuals from above?" --yes "y/[yes]" --no "n/no" stat=$? if (( stat == 0 )); then printf "\n" while IFS=$'\t' read -r cmd svers; do if [[ "$cmd" != "" && "$svers" != "" ]]; then if [[ -f "$cmd" ]]; then echo "Deleting manual '$cmd'." filecheck -rm "$cmd" fi fi done < <(tailfromline2 "$scratchfile" | StripComment) filecheck -rm "$manfile" filecheck -rm "$manfile2" UpdateWhatis printf "Manuals removed.\n\n" else printf "Skipped.\n\n" fi else filecheck -rm $manfile filecheck -rm $manfile2 fi rm -f "$scratchfile" fi if [[ -r $toolsfile ]]; then result=$(filecheck -sl $toolsfile) if [[ "$result" != "" ]]; then if [[ "$pt" != "" ]]; then "$pt" --import $toolsfile else cat $toolsfile fi # Ask for remove tools confirm "\nDo you want to remove the tools from above?" --yes "y/[yes]" --no "n/no" stat=$? if (( stat == 0 )); then printf "\n" while IFS=$'\t' read -r cmd svers; do if [[ "$cmd" != "" && "$svers" != "" ]]; then if [[ -f "$cmd" ]]; then echo "Deleting tool '$cmd'." filecheck -rm "$cmd" fi fi done < <(tailfromline2 "$toolsfile" | StripComment) if [[ -r "$zipsfile" ]]; then while IFS=$'\t' read -r cmd svers; do if [[ "$cmd" != "" && "$svers" != "" ]]; then echo "Deleting python-dir '$cmd'." rm -fR "$cmd" fi done < <(tailfromline2 "$zipsfile" | StripComment) fi if [[ -r "$libsfile" ]]; then while IFS=$'\t' read -r cmd; do if [[ "$cmd" != "" ]]; then echo "Deleting library '$cmd'." filecheck -rm "$cmd" fi done < <(tailfromline2 "$libsfile" | StripComment) fi if [[ -r "$templatesfile" ]]; then while IFS=$'\t' read -r cmd; do if [[ "$cmd" != "" ]]; then echo "Deleting template '$cmd'." filecheck -rm "$cmd" basedir=$(dirname "$cmd") rmdir "$basedir" 2>/dev/null fi done < <(tailfromline2 "$templatesfile" | StripComment) fi filecheck -rm "$toolsfile" filecheck -rm "$zipsfile" filecheck -rm "$libsfile" filecheck -rm "$templatesfile" rmdir "$templatesfolder" 2>/dev/null # rmdir "$manfolder" 2>/dev/null # rmdir "$infofolder" 2>/dev/null # rmdir "$appfolder" 2>/dev/null # rmdir "$binfolder" 2>/dev/null # rmdir "$libfolder" 2>/dev/null # rmdir "$userhome" 2>/dev/null filecheck -rm "/etc/yum.repos.d/tools${bits}.repo" filecheck -rm "/etc/yum.repos.d/tools${bits}.repo.osms-backup" filecheck -rm "$cloudfile" # filecheck -rm "${infofolder}/.admintools" # Delete logs filecheck -rm "/var/log/install-tools.log" filecheck -rm "/var/log/bootstrap.log" printf "Tools removed.\n\n" else printf "Skipped.\n\n" fi else filecheck -rm $toolsfile fi fi if [[ -d "${REALHOME}/logs" ]]; then ls -l "${REALHOME}/logs" > "$scratchfile" result=$(filecheck -sl "$scratchfile") if [[ "$result" != "" ]]; then printf "Content of log folder: ${REALHOME}/logs\n\n" tailfromline2 "$scratchfile" confirm "\nDo you want to remove the logs from above?" --yes "y/[yes]" --no "n/no" stat=$? if (( stat == 0 )); then rm -fR "${REALHOME}/logs" stat=$? if (( stat == 0 )); then printf "Logs removed.\n\n" else exitcode=5 fi else printf "Skipped.\n\n" fi else printf "\nNo logs found. Skipped.\n\n" fi fi if [[ -f $scriptsfile ]]; then if [[ "$pt" != "" ]]; then $pt --import $scriptsfile else cat $scriptsfile fi # Ask for remove template files confirm "\nDo you want to remove the scripts from above?" --yes "y/[yes]" --no "n/no" stat=$? if (( stat == 0 )); then # Remove get-authkeys from sshd_config if [[ -f "/etc/ssh/sshd_config.org" ]]; then km=$(filecheck -x key-management) if [[ "$km" != "" ]]; then if [[ "$USER" = "root" ]]; then $km remove else check-sudo stat=$? if (( stat == 0 )); then sudo $km remove fi fi else printf "\n" fi else printf "\n" fi while IFS=$'\t' read -r cmd svers; do if [[ "$cmd" != "" && "$svers" != "" ]]; then if [[ -f "$cmd" ]]; then # Tool exists - check if it has a version instvers=$(head -n 10 $cmd | grep '^# Version: @(#' | cut -d' ' -f4) if [[ "$instvers" != "" ]]; then echo "Deleting script '$cmd'." rm -f "$cmd" else echo "Script '$cmd' not deleted. Alternative version found." fi fi fi done < <(tailfromline2 "$scriptsfile" | StripComment) # Cleanup rm -f "$scriptsfile" printf "Scripts removed.\n" else printf "Skipped.\n" fi fi Cleanup exit $exitcode else if [[ "$IGNORERUNNING" = "" ]]; then echo "$progstr $param1" | ToUpper > "$scratchfile" printf "\n" print-header --import "$scratchfile" fi transfer --quiet ${downloadurl}/beta/install-scripts >/dev/null 2>&1 stat=$? if (( stat != 0 )); then downloadurl="$storageurl" transfer --quiet ${downloadurl}/beta/install-scripts >/dev/null 2>&1 stat=$? fi if (( stat != 0 )); then exitcode=4 errormsg $exitcode "No internet connection. Have to stop here." Cleanup exit $exitcode fi result=$(get-platform --output keys) id=$(GrepKey "$result" "id") # vers=$(GrepKey "$result" "version_main") id_like=$(GrepKey "$result" "id_like") name=$(GrepKey "$result" "name") # codename=$(GrepKey "$result" "codename") # version_id=$(GrepKey "$result" "version_id") version_main=$(GrepKey "$result" "version_main") pretty_name=$(GrepKey "$result" "pretty_name") proc=$(GrepKey "$result" "processor") # Infos about the processor type (e.g. i386, sparc, arm) bits=$(GrepKey "$result" "bit") # 32 or 64 # gateway=$(GrepKey "$result" "gateway") # iface=$(GrepKey "$result" "interface") # ifup=$(GrepKey "$result" "up") # lip=$(GrepKey "$result" "ip_v4") # cloud_id=$(GrepKey "$result" "cloud_id") # asn_id=$(GrepKey "$result" "asn_id") if [[ "$bits" != "32" && "$bits" != "64" ]]; then exitcode=5 errormsg $exitcode "Unexpected error. Have to stop here." "Unknown parameter returned by 'get-platform bit'" Cleanup exit $exitcode fi if [[ "$param1" = "update" || "$param1" = "" ]]; then result=$(filecheck "$0" -fmin) if [[ "$result" != "" && "$param1" = "" || "$IGNORERUNNING" = "true" ]]; then # We installed the scripts 0-15 minutes ago - there is no need for an update stat=1 else if [[ "$param1" = "" ]]; then if [[ "$USER" = "root" ]]; then transfer --quiet ${downloadurl}/beta/install-scripts | bash -s check > "$scratchfile" stat=$? else check-sudo stat=$? if (( stat == 0 )); then transfer --quiet ${downloadurl}/beta/install-scripts | sudo bash -s check > "$scratchfile" stat=$? else transfer --quiet ${downloadurl}/beta/install-scripts | bash -s check > "$scratchfile" stat=$? fi fi if (( stat == 0 )); then printf "\nInstalled scripts:\n\n" grep '^Script ' "$scratchfile" | sed 's|^Script ||g' confirm "\nDo you want to update scripts?" --yes "y/[yes]" --no "n/no" stat=$? fi else stat=0 fi fi if (( stat == 0 )); then # Create tmp script with update if [[ "$USER" = "root" ]]; then echo "transfer --quiet ${downloadurl}/beta/install-scripts | bash" > "$scratchfile" else check-sudo stat=$? if (( stat == 0 )); then echo "transfer --quiet ${downloadurl}/beta/install-scripts | sudo bash" > "$scratchfile" else echo "transfer --quiet ${downloadurl}/beta/install-scripts | bash" > "$scratchfile" fi fi echo "$progstr $param1 $param2" >> "$scratchfile" echo "rm -f $scratchfile" >> "$scratchfile" chmod 755 "$scratchfile" export IGNORERUNNING="true" "$scratchfile" rm -f "$scratchfile" stat=$? exit $stat fi DisplayVersion # Check if install-tools is alrady running result=$(ps -ef | grep "install-tools" | grep -v "grep" | tr -s ' ' | wc -l) if (( result > 0 )); then printf "\nTools are updating. Please wait until this has finished.\n" Cleanup exit else warn_user="false" if [[ "$name" != "Oracle Linux Server" ]]; then warn_user="true" else resultstr=$(compare-version 7 "$version_main") if [[ "$resultstr" = "older" ]]; then warn_user="true" fi fi if [[ "$warn_user" = "true" ]]; then printf "\nSystem OS: ${pretty_name}\n" errormsg 0 "Next action works best with Oracle Linux Server 7 or newer." errormsg 0 "Only continue with 'yes' if you want to test on a non productive environment." errormsg 0 "Install tools manually if automation fails." fi confirm "\nDo you want to install / update tools if possible?" --yes "y/[yes]" --no "n/no" stat=$? if (( stat == 0 )); then if [[ "$USER" = "root" ]]; then transfer --quiet ${downloadurl}/beta/install-tools | bash else check-sudo stat=$? if (( stat == 0 )); then # sudo --preserve-env=PATH env install-tools transfer --quiet ${downloadurl}/beta/install-tools | sudo --preserve-env=PATH bash else transfer --quiet ${downloadurl}/beta/install-tools | bash fi fi DisplayVersion fi fi # check-sudo # stat=$? # # if [ $stat -eq 0 -o "$USER" = "root" ]; then # # We only can update linux yet - maybe more to come # if [ "$OS" = "Linux" -a -f $toolsfile ]; then # confirm "\nDo you want to update the OS?" --yes "y/yes" --no "n/[no]" # stat=$? # # if [ $stat -eq 0 ]; then # UpdateOS # fi # fi # fi fi # if [ "$param1" = "bootstrap" -o "$param1" = "" ]; then # if [ "$USER" = "root" ]; then # bootstrap # else # check-sudo # stat=$? # # if [ $stat -eq 0 ]; then # sudo --preserve-env=PATH env bootstrap # fi # fi # fi if [[ "$param1" = "config" || "$param1" = "" ]]; then if [[ "$param1" = "" ]]; then confirm "\nDo you want to configure cloud tools?" --yes "y/[yes]" --no "n/no" stat=$? if (( stat == 0 )); then InitTools stat=$? # Does it makes sense to install extra tools and crontab if Cloud Tools could not be initialized? # else # stat=0 fi else InitTools stat=$? fi if (( stat == 0 )); then if [[ "$OCI_CLI_CLOUD_SHELL" != "True" ]]; then confirm "\nDo you want to configure crontab?" --yes "y/[yes]" --no "n/no" stat=$? if (( stat == 0 )); then # Download extra scripts curl -skL ${downloadurl}/samples/dl-extra.bash -o "$scratchfile" chmod 755 "$scratchfile" "$scratchfile" # Download crontab curl -skL ${downloadurl}/samples/crontab -o "$scratchfile" crontab "$scratchfile" stat=$? if (( stat == 0 )); then printf "\nCrontab configured. Check with 'crobtab -l'.\n" else printf "\nCrontab not configured. Create one with 'crobtab -e'.\n" fi fi fi fi fi if [[ "$OCI_CLI_CLOUD_SHELL" != "True" ]]; then if [[ "$param1" = "setup" ]]; then printf "\n" errormsg 5 "Setting up the multitier network via this tool only works in Cloud Shell." exit 5 fi else if [[ "$param1" = "setup" || "$param1" = "" ]]; then if [[ "$param1" = "" ]]; then if [[ ! -d "$tfpjfolder" ]]; then confirm "\nDo you want to setup a multitier network via terraform?" --yes "y/[yes]" --no "n/no" stat=$? else stat=1 fi else stat=0 fi if (( stat == 0 )); then if [[ -d "$tfpjfolder" ]]; then printf "\nFolder '%s' already exists. Please rename or remove it first.\n" "$tfpjfolder" else # If we don't have needed variables set - read them from config if [[ "$namespace" = "" ]]; then ReadOCIJson stat=$? else stat=0 fi # Print new line printf "\n" if (( stat > 0 )); then printf "Config file '$ocijson' could not be found. Please configure tools first with '$progstr config'.\n" else if [[ "$writeuri" = "" ]]; then ReadProjectJson stat=$? else stat=0 fi if (( stat > 0 )); then printf "Config file '$projectjson' could not be found. Please configure tools first with '$progstr config'.\n" else if [[ "$namespace" != "" && "$writeuri" != "" ]]; then InitTerraformProject "$writeuri" else printf "Unexpected: namespace '$namespace' or writeuri '$writeuri' is empty.\n" fi fi fi fi fi fi fi if [[ "$param1" = "terraform" ]]; then CallTerraform "$param2" exitcode=$? fi # if [ "$param1" = "classic" ]; then # ReadOCIJson # stat=$? # # printf "\n" # # if [ $stat -eq 0 ]; then # InitPSMTool "$tenancyid" "$homeregion" "$username" # exitcode=$? # else # printf "Config file '$ocijson' could not be found. Please configure tools first with '$progstr config'.\n" # exitcode=$stat # fi # fi if [[ "$param1" = "push" ]]; then if [[ "$param1" = "" ]]; then confirm "\nDo you want to push configuration to operator?" --yes "y/[yes]" --no "n/no" stat=$? else stat=0 fi if (( stat == 0 )); then # If we don't have needed variables set - read them from config if [[ "$namespace" = "" && -r "$ocijson" ]]; then ReadOCIJson stat=$? else stat=0 fi # Prit new line printf "\n" haveTF=0 if (( stat > 0 )); then printf "Config file '$ocijson' could not be found. Please configure tools first with '$progstr config'.\n" else if [[ "$param2" = "" ]]; then if [[ -d "${tfpjfolder}/.terraform" ]]; then CallTerraformOutput output > "$scratchfile" destination=$(browse-json --select 1 --quiet --import "$scratchfile" operator_private_ip/value) if [[ "$destination" != "" ]]; then destination="opc@$destination" haveTF=1 fi else destination="" fi while [[ "$destination" = "" && $stat -eq 0 ]]; do printf "Destination address ('user@ip' e.g. 'opc@130.61.219.239'): " read inp if [[ "$inp" = "" ]]; then confirm "You did not enter a destination address. Do you want to enter again?" --yes "y/[yes]" --no "n/no" stat=$? else destination="$inp" fi done else destination="$param2" fi if [[ "$destination" != "" ]]; then # Check destination if [[ ! -r "$sshconfig" ]]; then printf "No '$sshconfig' found. Exiting.\n" else # Create list of hosts hosts=$(cat "$sshconfig" | grep '^Host ' | cut -d' ' -f2 | grep -v '*') destuser=$(echo "$destination" | cut -d'@' -f1) destip=$(echo "$destination" | cut -d'@' -f2) hostname="" # Check if destination already exists and get the host name for host in $hosts; do hn=$(ssh -G $host | grep "^hostname " | cut -d' ' -f2) un=$(ssh -G $host | grep "^user " | cut -d' ' -f2) if [[ "$hn" = "$destip" && "$un" = "$destuser" ]]; then hostname="$host" fi done if [[ "$hostname" = "" ]]; then # No entry in sshconfig - write one while [[ "$hostname" = "" && $stat -eq 0 ]]; do if (( haveTF > 0 )); then inp="Operator" else printf "Enter an unique hostname (e.g. 'Operator'): " read inp fi if [[ "$inp" = "" ]]; then confirm "You did not enter a hostname. Do you want to try again?" --yes "y/[yes]" --no "n/no" stat=$? else result=$(cat "$sshconfig" | grep "^Host $inp$") if [[ "$result" != "" ]]; then haveTF=0 confirm "Hostname '$inp' already exists. Do you try to enter again?" --yes "y/[yes]" --no "n/no" stat=$? else needproxjump=0 hostname="$inp" sshkeys=$(key-management list tsv --username "$tenancyname" | tailfromline2 | grep " current ") sshprivkey=$(echo "$sshkeys" | cut -d$'\t' -f5) if [[ -r "${sshprivkey}.pk8" ]]; then # Prefering this key sshprivkey="${sshprivkey}.pk8" fi # Convert $REALHOME to ~ transpsshprivkey=$(echo "$sshprivkey" | sed 's|'"$REALHOME"'|~|') # Check if we have to encrypt key result=$(grep "ENCRYPTED" "$sshprivkey") sshkeygen=$(filecheck -x ssh-keygen) if [[ "$result" != "" && "$sshkeygen" != "" ]]; then tenantpassphrase=$(GetPassphraseFromPassphraseFile "$tenancyname") if [[ "$tenantpassphrase" != "" ]]; then cp "$sshprivkey" "${sshprivkey}.org" $sshkeygen -p -P "$tenantpassphrase" -N "" -m PEM -f "$sshprivkey" >/dev/null 2>&1 stat=$? if (( stat > 0 )); then # We were unable to decrypt the private key mv -f "${sshprivkey}.org" "$sshprivkey" chmod 600 "$sshprivkey" fi fi fi # Check if we can ssh to hostname ssh -i "$sshprivkey" ${destuser}@$destip -o BatchMode=yes -o ConnectTimeout=2 echo 2>/dev/null stat=$? if (( stat > 0 )); then if (( haveTF > 0 )); then bastion=$(browse-json --select 1 --quiet --import "$scratchfile" bastion_public_ip/value) if [[ "$bastion" != "" ]]; then bastionname="Bastion" stat=0 fi else bastionname="" fi if [[ "$bastionname" = "" ]]; then # Host not reachable - check for a bastion confirm "Host not reachable. Do you have a bastion host?" --yes "y/[yes]" --no "n/no" stat=$? if (( stat == 0 )); then # We do have a bastion - get the name of it while [[ "$bastionname" = "" ]]; do printf "Bastion hostname (leave blank to use name 'Bastion'): " read inp if [[ "$inp" = "" ]]; then bastionname="Bastion" else bastionname="$inp" fi confirm "You selected bastion hostname '$bastionname'. Correct?" --yes "y/[yes]" --no "n/no" stat=$? if (( stat > 0 )); then bastionname="" fi done else echo "Please setup a bastion host first. Then use 'push' again." hostname="" fi fi if [[ "$hostname" != "" ]]; then # Check if we already defined the bastion host bastion=$(echo "$hosts" | grep '\<'${bastionname}'\>') if [[ "$bastion" != "" ]]; then needproxjump=1 else # No Bastion defined in .ssh/config yet bastion="" while [[ "$bastion" = "" && $stat -eq 0 ]]; do if (( haveTF > 0 )); then bastion=$(browse-json --select 1 --quiet --import "$scratchfile" bastion_public_ip/value) if [[ "$bastion" != "" ]]; then bastion="opc@$bastion" fi fi if [[ "$bastion" = "" ]]; then printf "Bastion address ('user@ip' e.g. 'opc@130.61.219.239'): " read inp if [[ "$inp" = "" ]]; then confirm "You did not enter a bastion address. Do you want to try again?" --yes "y/[yes]" --no "n/no" stat=$? else bastion="$inp" fi fi if [[ "$bastion" != "" ]]; then ssh -i "$sshprivkey" "$bastion" -o BatchMode=yes -o ConnectTimeout=2 echo >/dev/null 2>&1 stat=$? if (( stat == 0 )); then # Bastion is reachable - write config needproxjump=1 bastuser=$(echo "$bastion" | cut -d'@' -f1) bastip=$(echo "$bastion" | cut -d'@' -f2) printf '\nHost %s\n' "$bastionname" >> "$sshconfig" printf '\tHostName %s\n' "$bastip" >> "$sshconfig" printf '\tUser %s\n' "$bastuser" >> "$sshconfig" printf '\tIdentityFile "%s"\n' "$transpsshprivkey" >> "$sshconfig" else # Bastion not reachable - Try again? bastion="" confirm "Bastion not reachable. Do you want to try again?" --yes "y/[yes]" --no "n/no" stat=$? if (( stat > 0 )); then # Bastion not reachable and we don't want to try again echo "You need to specify a bastion host first before using 'push' for 'private hosts'." hostname="" fi fi fi done fi fi fi fi if [[ "$hostname" != "" ]]; then # Check if host is reachable if (( needproxjump > 0 )); then # ssh -i "$sshprivkey" "${destuser}@$destip" -J $bastionname -o BatchMode=yes -o ConnectTimeout=2 echo >/dev/null 2>&1 ssh -i $sshprivkey "${destuser}@$destip" -o ProxyCommand="ssh -W %h:%p $bastionname -i $sshprivkey" \ -o BatchMode=yes -o ConnectTimeout=2 echo >/dev/null 2>&1 stat=$? else ssh -i "$sshprivkey" "${destuser}@$destip" -o BatchMode=yes -o ConnectTimeout=2 echo >/dev/null 2>&1 stat=$? fi if (( stat == 0 )); then printf '\nHost %s\n' "$hostname" >> "$sshconfig" printf '\tHostName %s\n' "$destip" >> "$sshconfig" printf '\tUser %s\n' "$destuser" >> "$sshconfig" if (( needproxjump > 0 )); then printf '\tProxyJump %s\n' "$bastionname" >> "$sshconfig" fi printf '\tIdentityFile "%s"\n' "$transpsshprivkey" >> "$sshconfig" else echo "Host '$hostname' not reachable. Unable to 'push'." hostname="" fi fi fi done fi if [[ "$hostname" != "" ]]; then # currdir=$(pwd) # cd # zip -q -r "${scratchfile}.zip" .oci .admintools # stat=$? # cd $currdir # # if [ $stat -eq 0 ]; then # scp -q "${scratchfile}.zip" "${hostname}:/tmp/config.zip" >/dev/null 2>&1 # stat=$? # fi # # filecheck -rm "${scratchfile}.zip" # # if [ $stat -eq 0 ]; then # printf 'if [ -d .oci ]; then\n' > "$scratchfile" # printf ' mv -f .oci .oci.org\n' >> "$scratchfile" # printf 'fi\n\n' >> "$scratchfile" # printf 'unzip -q /tmp/config.zip\n' >> "$scratchfile" # printf 'rm -f /tmp/config.zip\n' >> "$scratchfile" # printf 'rm -f %s\n' "$scratchfile" >> "$scratchfile" # # scp -q "$scratchfile" "${hostname}:$scratchfile" >/dev/null 2>&1 # stat=$? # # if [ $stat -eq 0 ]; then # ssh "$hostname" "cat "$scratchfile" | bash" >/dev/null 2>&1 # stat=$? # fi # fi scp -q "$ocijson" "${hostname}:/tmp/config.json" >/dev/null 2>&1 stat=$? if (( stat == 0 )); then scp -q "$projectjson" "${hostname}:/tmp/project.json" >/dev/null 2>&1 stat=$? fi if (( stat == 0 )); then printf 'if [[ ! -d "$HOME/.oci" ]]; then\n' > "$scratchfile" printf ' mkdir -m 0755 -p "$HOME/.oci"\n' >> "$scratchfile" printf 'fi\n\n' >> "$scratchfile" printf 'mv -f /tmp/config.json "$HOME/.oci/config.json"\n' >> "$scratchfile" printf 'mv -f /tmp/project.json "$HOME/.oci/project.json"\n' >> "$scratchfile" printf 'chmod 600 "$HOME/.oci/config.json" "$HOME/.oci/project.json"\n' >> "$scratchfile" printf 'rm -f %s\n' "$scratchfile" >> "$scratchfile" scp -q "$scratchfile" "${hostname}:$scratchfile" >/dev/null 2>&1 stat=$? if (( stat == 0 )); then ssh "$hostname" "cat "$scratchfile" | bash" >/dev/null 2>&1 stat=$? fi fi if (( stat == 0 )); then printf "Pushed configuration to host '$hostname'.\n" # Copy keys to destination key-management push "$hostname" --username "$username" 2>/dev/null else printf "Push configuration (ssh) failed. Please check '$sshconfig'.\n" exitcode=5 fi fi # Cleanup if [[ -f "${sshprivkey}.org" ]]; then mv "${sshprivkey}.org" "$sshprivkey" chmod 600 "$sshprivkey" fi fi fi fi fi fi fi # Cleanup and exit Cleanup exit $exitcode