#!/bin/bash # # Author: Georg Voell - georg.voell@standby.cloud # Version: @(#)oci-api 3.2.0 11.08.2024 (c)2024 Standby.cloud # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ # # Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. # This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or # Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. # #@ This script is a wrapper for the OCI REST API. #@ #@Usage: oci-api [options] endpoint method [filename] request #@ Options: #@ -h, --help : Displays helptext. #@ -v, --version: Displays the version of the script. #@ Endpoint: REST endpoint e.g. "iaas.eu-frankfurt-1.oraclecloud.com". #@ Method : get | head | post | put | delete. #@ Filename: Optional filename needed together with post or put #@ Request : Request that is appended to endpoint e.g. "/20160918/volumeAttachments?compartmentId=$cid" #@ #@Examples: #@ List compartments: #@ oci-api identity.eu-frankfurt-1.oraclecloud.com get /20160918/compartments/?compartmentId=ocid1.tenancy.oc1..amgxr35ltsgdy63lzts6jm2qtil7ug2wpm6uc2kweau6det # # Doku: https://docs.cloud.oracle.com/de-de/iaas/Content/API/Concepts/usingapi.htm # API Reference: https://docs.cloud.oracle.com/en-us/iaas/api/ # # Version: 3.2.0 11.08.2024 New minor version # Usage: # oci-curl.bash [file-to-send-as-body] [extra-curl-args] # # JSON output is always enveloped with "items" and amount of items (totalItems). Disable this via 'export ENVELOPE_API=false' # # Preset: # # export TENANCY_ID=`browse-json oci/tenancyid --select 1 --raw --import ~/.oci/config.json` # export API_USER_ID=`browse-json keys/userid --select 1 --raw --import ~/.oci/config.json` # export API_USER=`browse-json keys/username --select 1 --raw --import ~/.oci/config.json` # export KEY_FINGERPRINT=`browse-json keys/fingerprint --select 1 --raw --import ~/.oci/config.json` # export PRIVATE_KEY_PATH=`browse-json keys/privkey --select 1 --raw --import ~/.oci/config.json` # export PRIVATE_KEY_PATH=$(eval echo ${PRIVATE_KEY_PATH}) # # If private key is encrypted, a file "~/.oci/api-passwd" with the password in the first line is expected - # otherwise you are prompted for the passphrase. # # Examples: # # Get all instance data: curl -L -sS http://169.254.169.254/opc/v1/instance # Get all instance vnics: curl -L -sS http://169.254.169.254/opc/v1/vnics # Get all instance volume attachments: curl -L -sS http://169.254.169.254/opc/v1/volumeAttachments # Get all instance certificates: curl -L -sS http://169.254.169.254/opc/v1/identity # # Get instance internal ip: curl -sS http://169.254.169.254/opc/v1/vnics/0/privateIp # Get instance metadata: curl -L -sS http://169.254.169.254/opc/v1/instance/metadata # Get instance metadata: curl -L -sS http://169.254.169.254/openstack/latest/meta_data.json # # region=`curl -sS http://169.254.169.254/opc/v1/instance/region` # Get region from instance # iid=`curl -sS http://169.254.169.254/opc/v1/instance/id` # Get the instanceId from instance # cid=`curl -sS http://169.254.169.254/opc/v1/instance/compartmentId` # Get the compartmentId from instance # # Write certificates from instance to file: # curl -sS http://169.254.169.254/opc/v1/identity/cert.pem -o cert.pem # curl -sS http://169.254.169.254/opc/v1/identity/key.pem -o key.pem # curl -sS http://169.254.169.254/opc/v1/identity/intermediate.pem -o intermediate.pem # cat cert.pem intermediate.pem > chain.pem # # curl -v --insecure --cert /home/opc/bin/cert.pem --key /home/opc/bin/key.pem -X GET "https://iaas.${region}.oraclecloud.com/20160918/instances/$iid" # # List compartments # oci-api identity.${HOME_REGION}.oraclecloud.com get "/20160918/compartments/?compartmentId=$TENANCY_ID" # # List all instances in compartment # oci-api iaas.eu-frankfurt-1.oraclecloud.com get "/20160918/instances?compartmentId=$cid" | convert-json --output json # # List single instance # oci-api iaas.${region}.oraclecloud.com get "/20160918/instances/$iid" | jq -M . # # List volume attachment # oci-api iaas.eu-frankfurt-1.oraclecloud.com get "/20160918/volumeAttachments?compartmentId=$cid" | jq -M . # oci-api iaas.eu-frankfurt-1.oraclecloud.com get "/20160918/volumeAttachments?compartmentId=$cid&instanceId=$iid" | jq -M . # # oci-api iaas.eu-frankfurt-1.oraclecloud.com post ./request.json "/20160918/vcns" # # Using oci cli instead: # # set -e # # if [[ -z "$COMPARTMENT_ID" ]];then # echo "COMPARTMENT_ID must be defined in the environment. " # exit 1 # fi # # USER_NAME="TestUser" # USER_DESCRIPTION="User created by raw request" # TARGET_URI='https://identity.us-phoenix-1.oraclecloud.com/20160918/users/' # HTTP_METHOD='POST' # PROFILE='ADMIN' # REQUEST_BODY="{\"compartmentId\": \"$COMPARTMENT_ID\", \"name\": \"$USER_NAME\", \"description\": \"$USER_DESCRIPTION\"}" # # echo "oci raw-request --profile ${PROFILE} --target-uri ${TARGET_URI} --http-method ${HTTP_METHOD} --request-body "${REQUEST_BODY}" | jq -r '.data.id'" # USER_OCID=$(oci raw-request --profile ${PROFILE} --target-uri ${TARGET_URI} --http-method ${HTTP_METHOD} --request-body "${REQUEST_BODY}" | jq -r '.data.id') # # echo "Created user OCID: $USER_OCID" # # Exit codes: # 001: Unknown or wrong parameter. # 002: Exit code from curl (2 - 98) # 099: User interrupt. # 100: No 'jq' in PATH # 101: External variables not set (e.g. TENANCY_ID, API_USER_ID, KEY_FINGERPRINT, PRIVATE_KEY_PATH) # 102: Head returned other code then 200 (ok) # 103: No variable "code" in JSON # 104: Empty body file # 105: S3 not yet implemented # Find executable bash library and source it lib=`which lib.bash 2>/dev/null | sed 's|^no 'lib.bash' in .*||'` if [ "$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 # Preset readonly toolsdir="admintools" # Source environment variables if [ -r "${HOME}/.$toolsdir" ]; then source "${HOME}/.$toolsdir" else if [ -r "/usr/local/share/info/.$toolsdir" ]; then source "/usr/local/share/info/.$toolsdir" fi fi # Do extra cleanup function ExtraCleanup() { filecheck -rm ${scratchfile}.head filecheck -rm ${scratchfile}.pre filecheck -rm ${scratchfile}.out } # Needed by s3-curl function sha256 { local str=${1} printf "$str" | openssl dgst -sha256 -hex | sed 's/SHA2-256(stdin)= //g' } # Needed by s3-curl function sign { local keyArg=${1} local msg=${2} # printf "${msg}" | openssl dgst -sha256 -mac hmac -macopt "hexkey:${hexKey}" | sed 's/^.* //' printf "${msg}" | openssl dgst -sha256 -mac hmac -macopt "${keyArg}" | sed 's/SHA2-256(stdin)= //g' } # Needed by s3-curl function getSignatureKey { local key=${1} local dateStamp1=${2} local regionName=${3} local serviceName=${4} local kDate kRegion kService kSigning kDate="$(sign "key:AWS4${key}" "${dateStamp1}")" # echo "kDate=$kDate" >&2 kRegion="$(sign "hexkey:${kDate}" "${regionName}")" kService="$(sign "hexkey:${kRegion}" "${serviceName}")" kSigning="$(sign "hexkey:${kService}" "aws4_request")" printf "${kSigning}" } # Access S3 compat-objectstorage REST API via curl # Source: https://gist.github.com/slawekzachcial/fe23184124763dfb82f233b5dde2394b # AWS Signing: https://docs.aws.amazon.com/IAM/latest/UserGuide/create-signed-request.html # Check: https://medium.com/@pratapgowda007/accessing-oci-object-storage-through-the-amazon-s3-compatibility-api-403fcfb54f3e # Check: https://towardsaws.com/aws-sigv4-in-3-mins-c324d20f19cf function s3-curl() { local host=${1} local method=${2} local request=${3} local region=`echo "$host" | cut -d'.' -f4` local endpoint="https://${host}$request" local service="s3" local contentType="application/x-amz-json-1.1" local amazonDate="$(date --utc +'%Y%m%dT%H%M%SZ')" local dateStamp="$(date --utc +'%Y%m%d')" local result="" local stat=0 local requestParameters="" # local parameterName="location" # local requestParameters="$(printf '{"Name":"%s","WithDecryption":true}' "${parameterName}")" # local amazonTarget="AmazonSSM.GetParameter" result=`echo "$request" | grep '?'` if [ "$result" != "" ]; then requestParameters=`echo "$request" | cut -d'?' -f2` request=`echo "$request" | cut -d'?' -f1` # endpoint="https://${host}$request" fi if [ "$DEBUG_API" = true ]; then printf "\nS3 Test:\n\n" echo "host: '$host'." echo "method: '$method'." echo "request: '$request'." echo "requestParameters: '$requestParameters'." echo "region: '$region'." echo "endpoint: '$endpoint'." printf "\n" fi # --- TASK 1: create canonical request --- readonly canonicalUri="$request" readonly canonicalQueryString="" readonly payloadHash="$(sha256 "${requestParameters}")" readonly canonicalHeaders="host:${host}\nx-amz-content-sha256:${payloadHash}\nx-amz-date:${amazonDate}\n" readonly signedHeaders="host;x-amz-content-sha256;x-amz-date" readonly canonicalRequest="${method}\n${canonicalUri}\n${canonicalQueryString}\n${canonicalHeaders}\n${signedHeaders}\n${payloadHash}" # --- TASK 2: create the string to sign --- readonly algorithm="AWS4-HMAC-SHA256" readonly credentialScope="${dateStamp}/${region}/${service}/aws4_request" readonly stringToSign="${algorithm}\n${amazonDate}\n${credentialScope}\n$(sha256 "${canonicalRequest}")" # --- TASK 3: calculate the signature --- readonly signingKey="$(getSignatureKey "${S3_SECRETKEY}" "${dateStamp}" "${region}" "${service}")" readonly signature="$(sign "hexkey:${signingKey}" "${stringToSign}")" # --- TASK 4: add signing information to the request --- readonly authorizationHeader="${algorithm} \ Credential=${S3_ACCESSKEY}/${credentialScope}, \ SignedHeaders=${signedHeaders}, \ Signature=${signature}" # --- SEND REQUEST --- if [ "$DEBUG_API" = true ]; then echo -e "payloadHash: '$payloadHash'." echo -e "canonicalHeaders: '$canonicalHeaders'." echo -e "canonicalRequest: '$canonicalRequest'." echo -e "stringToSign: '$stringToSign'." fi curl \ "${endpoint}" \ --header "Authorization: ${authorizationHeader}" \ --header "x-amz-content-sha256: ${payloadHash}" \ --header "x-amz-date: ${amazonDate}" \ -sS -D ${scratchfile}.head > $scratchfile # --- CHECK RESULT --- stat=$? if [ "$DEBUG_API" = true ]; then if [ $stat -eq 0 ]; then printf "\nResult:\n\n" cat $scratchfile | pup # 'json{}' | "$jq" -M printf "\n" fi fi errormsg 0 "($progstr) S3 compatible objectstorage not implemented (curl code: $stat)." return 105 } # Access S3 compat-objectstorage REST API via curl # Source: https://curl.se/docs/manpage.html#--aws-sigv4 # curl version needed: 7.75.0 # Signing via '--aws-sigv4' does not work here function compat-curl() { local host=${1} local method=${2} local request=${3} local region=`echo "$host" | cut -d'.' -f4` local endpoint="https://${host}$request" local signkey="aws:amz:${region}:s3" if [ "$DEBUG_API" = true ]; then printf "\nS3 Test:\n\n" echo "host: '$host'." echo "method: '$method'." echo "request: '$request'." echo "region: '$region'." echo "endpoint: '$endpoint'." echo "user: '${S3_ACCESSKEY}:$S3_SECRETKEY'." echo "signkey: '$signkey'." printf "\n" fi # --url-query "graph=urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66" \ # --header "x-amz-security-token: ${AWS_SESSION_TOKEN}" curl --request "$method" "$endpoint" \ --user "${S3_ACCESSKEY}:$S3_SECRETKEY" \ --aws-sigv4 "$signkey" \ -sS -D ${scratchfile}.head > $scratchfile stat=$? if [ "$DEBUG_API" = true ]; then if [ $stat -eq 0 ]; then printf "\nResult:\n\n" cat $scratchfile | pup # 'json{}' | "$jq" -M printf "\n" fi fi errormsg 0 "($progstr) S3 compatible objectstorage not implemented (curl code: $stat)." return 105 } # Access OCI REST API via curl # Source: https://docs.cloud.oracle.com/iaas/Content/API/Concepts/signingrequests.htm#Bash # Signing: https://www.ateam-oracle.com/post/oracle-cloud-infrastructure-oci-rest-call-walkthrough-with-curl function oci-curl() { local alg=rsa-sha256 local sigVersion="1" local now="$(LC_ALL=C \date -u "+%a, %d %h %Y %H:%M:%S GMT")" local host=$1 local method=$2 local extra_args local keyId="$TENANCY_ID/$API_USER_ID/$KEY_FINGERPRINT" local sel="" local npg="" local qm="" case $method in "get" | "GET") local target=$3 extra_args=("${@: 4}") local curl_method="GET" local request_method="get" ;; "delete" | "DELETE") local target=$3 extra_args=("${@: 4}") local curl_method="DELETE" local request_method="delete" ;; "head" | "HEAD") local target=$3 extra_args=("--head" "${@: 4}") local curl_method="GET" local request_method="get" ;; "post" | "POST") local body=$3 local target=$4 extra_args=("${@: 5}") local curl_method="POST"; local request_method="post" local content_sha256="$(openssl dgst -binary -sha256 < $body | openssl enc -e -base64)" local content_type="application/json" local content_length="$(wc -c < $body | xargs)" ;; "put" | "PUT") local body=$3 local target=$4 extra_args=("${@: 5}") local curl_method="PUT" local request_method="put" local content_sha256="$(openssl dgst -binary -sha256 < $body | openssl enc -e -base64)" local content_type="application/json" local content_length="$(wc -c < $body | xargs)" ;; *) echo "invalid method"; return;; esac # Append page selector to target if nescessary if [ "$np" != "" -o "$ns" != "" ]; then if [ "$conversion" = "objects" ]; then sel="start" npg="$ns" else sel="page" npg="$np" fi qm=`echo "$target" | grep '?'` if [ "$qm" = "" ]; then target="${target}?${sel}=$npg" else target="${target}&${sel}=$npg" fi fi # This line will url encode all special characters in the request target except "/", "?", "=", and "&", since those characters are used # in the request target to indicate path and query string structure. If you need to encode any of "/", "?", "=", or "&", such as when # used as part of a path value or query string key or value, you will need to do that yourself in the request target you pass in. local escaped_target="$(echo $( rawurlencode "$target" ))" local request_target="(request-target): $request_method $escaped_target" local date_header="date: $now" local host_header="host: $host" local content_sha256_header="x-content-sha256: $content_sha256" local content_type_header="content-type: $content_type" local content_length_header="content-length: $content_length" local signing_string="$request_target\n$date_header\n$host_header" local headers="(request-target) date host" local curl_header_args curl_header_args=(-H "$date_header") local body_arg body_arg=() if [ "$curl_method" = "PUT" -o "$curl_method" = "POST" ]; then signing_string="$signing_string\n$content_sha256_header\n$content_type_header\n$content_length_header" headers=$headers" x-content-sha256 content-type content-length" curl_header_args=("${curl_header_args[@]}" -H "$content_sha256_header" -H "$content_type_header" -H "$content_length_header") body_arg=(--data-binary @${body}) fi # Check if we need a passphrase to encrypt if [ ! -f "${HOME}/.oci/api-passwd" ]; then local sig=$(printf '%b' "$signing_string" | \ openssl dgst -sha256 -sign $PRIVATE_KEY_PATH | \ openssl enc -e -base64 | tr -d '\n') else local sig=$(printf '%b' "$signing_string" | \ openssl dgst -sha256 -passin "file:${HOME}/.oci/api-passwd" -sign $PRIVATE_KEY_PATH | \ openssl enc -e -base64 | tr -d '\n') fi # curl -sS http://169.254.169.254/opc/v1/identity/cert.pem -o cert.pem # curl -sS http://169.254.169.254/opc/v1/identity/intermediate.pem -o intermediate.pem # curl -sS http://169.254.169.254/opc/v1/identity/key.pem -o key.pem # cat cert.pem intermediate.pem > chain.pem # openssl crl2pkcs7 -nocrl -certfile chain.pem | openssl pkcs7 -print_certs -noout # # curl "${extra_args[@]}" "${body_arg[@]}" -X $curl_method -sS https://${host}${escaped_target} "${curl_header_args[@]}" \ # --insecure --cert ./cert.pem if [ "$DEBUG_API" = true ]; then echo "curl call:" echo curl "${extra_args[@]}" "${body_arg[@]}" -X $curl_method -sS https://${host}${escaped_target} "${curl_header_args[@]}" \ -H "Authorization: Signature version=\"$sigVersion\",keyId=\"$keyId\",algorithm=\"$alg\",headers=\"${headers}\",signature=\"$sig\"" fi curl "${extra_args[@]}" "${body_arg[@]}" -X $curl_method -sS https://${host}${escaped_target} "${curl_header_args[@]}" \ -H "Authorization: Signature version=\"$sigVersion\",keyId=\"$keyId\",algorithm=\"$alg\",headers=\"${headers}\",signature=\"$sig\"" # -H "Authorization: Bearer " } # url encode all special characters except "/", "?", "=", and "&" function rawurlencode() { local string="${1}" local strlen=${#string} local encoded="" local pos c o for (( pos=0 ; pos ${scratchfile}.head # Check header for HTTP return code code=`grep "^HTTP/" ${scratchfile}.head` result=`echo "$code" | cut -d' ' -f2` if [ "$result" != "200" ]; then stat=102 else # Grep number of total items items=`grep "^opc-total-items: " ${scratchfile}.head | cut -d' ' -f2-` # Grep transfer method transfer=`grep "^Transfer-Encoding: " ${scratchfile}.head | cut -d' ' -f2-` # Check header for following pages # opc-retry-token and opc-request-id maybe also interesting here np=`grep "^opc-next-page: " ${scratchfile}.head | cut -d' ' -f2-` # Check header for previous pages pp=`grep "^opc-previous-page: " ${scratchfile}.head | cut -d' ' -f2-` # We are also interested in body if not only showhead if [ "$showhead" = false ]; then result=`filecheck -s "$scratchfile"` if [ "$result" != "" ]; then result=`head -c 1 $scratchfile` if [ "$result" = "[" ]; then havearray=true else havearray=false # Check for sub-arrays in JSON conversion="" case "$service" in query) result=`head -n 10 $scratchfile | grep '^ "items": '` if [ "$result" != "" ]; then conversion="items" fi ;; idcs) result=`head -n 10 $scratchfile | grep '^ "Resources": '` if [ "$result" != "" ]; then conversion="Resources" fi ;; objectstorage) result=`head -n 10 $scratchfile | grep '^ "objects": '` if [ "$result" != "" ]; then conversion="objects" fi ;; esac fi if [ "$service" = "objectstorage" ]; then # Check for errors or next start (objectstorage obejcts) in output ns=`browse-json nextStartWith --select 1 --raw --quiet --import $scratchfile` if [ "$ns" != "" ]; then ns=`rawurlencode $ns` fi fi fi fi fi else # Unfortunately, we don't have a header file (this should be unusual) - check output instead if [ "$showhead" = false ]; then result=`filecheck -s "$scratchfile"` if [ "$result" != "" ]; then code=`browse-json code --select 1 --raw --quiet --import $scratchfile` if [ "$code" = "" ]; then stat=103 fi else stat=104 fi fi fi return $stat } function PrinttHeaderObject() { local name="${1}" local size="" local storageTier="" local archivalState="" local md5="" local versionID="" local virtualFolder="" local virtualFolderCreator="" local etag="" local date="" local lastModified="" printf '{' if [ -r ${scratchfile}.head -a "$name" != "" ]; then size=`grep '^Content-Length: ' ${scratchfile}.head | cut -d' ' -f2-` storageTier=`grep '^storage-tier: ' ${scratchfile}.head | cut -d' ' -f2-` archivalState=`grep '^archival-state: ' ${scratchfile}.head | cut -d' ' -f2-` md5=`grep '^content-md5: ' ${scratchfile}.head | cut -d' ' -f2-` versionID=`grep '^version-id: ' ${scratchfile}.head | cut -d' ' -f2-` virtualFolder=`grep '^opc-meta-virtual-folder-directory-object: ' ${scratchfile}.head | cut -d' ' -f2-` virtualFolderCreator=`grep '^opc-meta-virtual-folder-directory-createdby: ' ${scratchfile}.head | cut -d' ' -f2-` etag=`grep '^etag: ' ${scratchfile}.head | cut -d' ' -f2-` date=`grep '^date: ' ${scratchfile}.head | cut -d' ' -f2-` lastModified=`grep '^last-modified: ' ${scratchfile}.head | cut -d' ' -f2-` if [ "$archivalState" = "" ]; then archivalState=null else archivalState='"'$archivalState'"' fi if [ "$virtualFolder" = "" ]; then virtualFolder=null else virtualFolder="$virtualFolder" fi if [ "$virtualFolderCreator" = "" ]; then virtualFolderCreator=null else virtualFolderCreator='"'$virtualFolderCreator'"' fi printf '\n "name": "%s",\n "size": %s,\n "storageTier": "%s",\n "archivalState": %s,\n "md5": "%s",\n "versionID": "%s",\n "virtualFolder": %s,\n "virtualFolderCreator": %s,\n "etag": "%s",\n "date": "%s",\n "lastModified": "%s"\n' "$name" "$size" "$storageTier" "$archivalState" "$md5" "$versionID" "$virtualFolder" "$virtualFolderCreator" "$etag" "$date" "$lastModified" fi printf '}\n' } function PrintHeader() { echo '{' printf ' "code": "%s",\n' "$code" if [ "$items" != "" ]; then printf ' "opcTotalItems": %s,\n' "$items" else printf ' "opcTotalItems": null,\n' fi if [ "$pp" != "" ]; then printf ' "opcPreviousPage": "%s",\n' "$pp" else printf ' "opcPreviousPage": null,\n' fi if [ "$np" != "" ]; then printf ' "opcNextPage": "%s",\n' "$np" else printf ' "opcNextPage": null,\n' fi if [ "$transfer" != "" ]; then printf ' "transferEncoding": "%s",\n' "$transfer" else printf ' "transferEncoding": null,\n' fi printf ' "service": "%s"\n' "$service" echo '}' } ### Main items=0 # Number of total items from header titems=0 # Number of total items calculated from array showhead=false # true for only display http head data (converted to JSON) havearray=false # true if JSON response starting with an array '[' haveOSObject="" # Name of the object in objectstorage we try to download or get metadata of filename="" # Needed for post and put conversion="" # Could be "items", "Resources" or "objects" endpoint="" # Rest API Endpoint (URL) method="" # get / delete / head / post / put request="" # Version and Call service="" # OCI service code="" # Status of the call e.g. "HTTP/1.1 200 OK" np="" # Next page (oagination for long lists) pp="" # Previous page (oagination for long lists) ns="" # Next start (objectstorage objects pagination) # 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 paramck=`echo "$pname" | grep '^-'` # Keys don't begin with '-' if [ "$paramck" != "" ]; then errstr="Unknown option '$pname'." else if [ "$endpoint" = "" ]; then endpoint=`echo "$pname" | tolower | sed 's|^https://||'` else if [ "$method" = "" ]; then method=`echo "$pname" | toupper` else if [ "$request" = "" ]; then if [ "$method" = "POST" -o "$method" = "PUT" ]; then if [ "$filename" = "" ]; then filename="$pname" if [ ! -r "$filename" ]; then errstr="Unable to read file '$filename'." fi if [ "$1" != "" ]; then request=${1} shift else errstr="Please specify a filename after method '$method' and before your request." fi else errstr="Unknown additional parameter: '$pname'." fi else request="$pname" fi else errstr="Unknown additional parameter: '$pname'." fi fi fi fi esac done # Plausibility check if [ "$endpoint" = "" -o "$method" = "" -o "$request" = "" ]; then errstr="Unsufficient parameters were specified." else # Determine service from endpoint and check if it is objectstorage request is looking for objects result=`echo "$endpoint" | grep ".compat.objectstorage."` if [ "$result" != "" ]; then service="compat-objectstorage" else result=`echo "$endpoint" | grep "^idcs-"` if [ "$result" != "" ]; then service="idcs" else service=`echo "$endpoint" | cut -d'.' -f1` if [ "$service" = "objectstorage" ]; then haveOSObject=`echo "$request" | grep '/o/' | sed 's|/o/|:|' | cut -d':' -f2` fi fi fi fi # Display help or error message DisplayHelp # Check if jq is installed jq=`filecheck -x jq` if [ "$jq" = "" ]; then exitcode=100 errormsg $exitcode "($progstr) 'jq' not installed." exit $exitcode fi # Call the REST API if [ "$HOME_REGION" != "" ]; then if [ "$service" = "compat-objectstorage" ]; then if [ "$S3_ACCESSKEY" != "" -a "$S3_SECRETKEY" != "" ]; then s3-curl "$endpoint" "$method" "$request" exitcode=$? else exitcode=101 fi else if [ "$TENANCY_ID" != "" -a "$API_USER_ID" != "" -a "$KEY_FINGERPRINT" != "" -a "$PRIVATE_KEY_PATH" != "" ]; then oci-curl "$endpoint" "$method" $filename "$request" --connect-timeout 10 --max-time 60 --retry 3 --retry-delay 5 -D ${scratchfile}.head > $scratchfile 2>/dev/null exitcode=$? else exitcode=101 fi fi else exitcode=101 fi if [ "$DEBUG_API" = true ]; then printf "\nexitcode curl: '%s'.\n" "$exitcode" printf "service: '%s'.\n" "$service" printf "endpoint: '%s'.\n" "$endpoint" printf "method: '%s'.\n" "$method" printf "filename: '%s'.\n" "$filename" printf "request: '%s'.\n" "$request" printf "haveOSObject: '%s'.\n" "$haveOSObject" if [ $exitcode -eq 0 ]; then # Check, if we only wanted to see the header result=`diff $scratchfile ${scratchfile}.head` stat=$? if [ $stat -eq 0 ]; then # We only asked for header information - no JSON in output showhead=true else # Check JSON syntax and pp JSON mv -f $scratchfile ${scratchfile}.pre cat ${scratchfile}.pre | "$jq" > $scratchfile exitcode=$? printf "jq exitcode: '%s'.\n\n" "$exitcode" read -p "Press enter to continue" printf "\nUnmodified Body:\n" cat ${scratchfile}.pre | more fi if [ $exitcode -eq 0 ]; then checkfiles exitcode=$? printf "checkfiles exitcode: '%s'.\n" "$exitcode" printf "code: '%s'.\n" "$code" printf "havearray: '%s'.\n" "$havearray" printf "conversion: '%s'.\n" "$conversion" printf "transfer: '%s'.\n" "$transfer" printf "items: '%s'.\n" "$items" printf "np: '%s'.\n" "$np" printf "pp: '%s'.\n" "$pp" printf "ns: '%s'.\n" "$ns" if [ "$showhead" = true ]; then printf "\nHead:\n" cat ${scratchfile}.head else printf "\n" read -p "Press enter to continue" printf "\nHead:\n" cat ${scratchfile}.head read -p "Press enter to continue" printf "\nBody:\n" cat $scratchfile | more fi fi fi Cleanup exit fi # Check if curl succeeded and output is valid JSON if [ $exitcode -gt 0 ]; then errormsg 0 "($progstr) Unable to access REST API. Error code: $exitcode." else result=`diff $scratchfile ${scratchfile}.head` stat=$? if [ $stat -eq 0 ]; then # We only asked for header information - no JSON in output showhead=true else if [ "$haveOSObject" != "" -a "$method" = "GET" ]; then # Assuming we want to download of a file from objectstorage checkfiles exitcode=$? if [ $exitcode -eq 0 ]; then cat $scratchfile fi Cleanup exit $exitcode fi # Check JSON syntax and pp JSON mv -f $scratchfile ${scratchfile}.pre cat ${scratchfile}.pre | "$jq" '.' > $scratchfile exitcode=$? fi if [ $exitcode -eq 0 ]; then checkfiles exitcode=$? fi # if [ $exitcode -eq 0 -o "$showhead" = true ]; then if [ $exitcode -eq 0 ]; then if [ $showhead = true ]; then # Just one page - don't loop over all pages np="" ns="" if [ "$haveOSObject" != "" ]; then # Get metadata for an OS object PrinttHeaderObject "$haveOSObject" > ${scratchfile}.out else PrintHeader > ${scratchfile}.out fi else # We had a result if [ "$conversion" = "" ]; then mv -f $scratchfile ${scratchfile}.out else cat $scratchfile | "$jq" '.'$conversion > ${scratchfile}.out fi # case "$service" in # query) # if [ "$havearray" = true ]; then # mv -f $scratchfile ${scratchfile}.out # else # cat $scratchfile | "$jq" '.items' > ${scratchfile}.out # fi # ;; # idcs) # # We don't search for single IDs - we don't know which IDCS domain hosts the ID # cat $scratchfile | "$jq" '.Resources' > ${scratchfile}.out # if [ $items -gt 1 ]; then # cat $scratchfile | "$jq" '.Resources' > ${scratchfile}.out # else # mv -f $scratchfile ${scratchfile}.out # fi # ;; # objectstorage | compat-objectstorage) # if [ $objects -gt 0 ]; then # cat $scratchfile | "$jq" '.objects' > ${scratchfile}.out # else # result=`cat $scratchfile | wc -l` # if [ "$result" = "1" ]; then # # Assuming namespace # result=`cat $scratchfile` # printf '{\n "data": %s\n}\n' "$result" > ${scratchfile}.out # else # mv -f $scratchfile ${scratchfile}.out # fi # fi # ;; # *) # mv -f $scratchfile ${scratchfile}.out # esac fi # We have more than one page while [ "$np" != "" -o "$ns" != "" ]; do oci-curl "$endpoint" "$method" $filename "$request" --connect-timeout 10 --max-time 60 --retry 3 --retry-delay 5 -D ${scratchfile}.head | "$jq" '.' > $scratchfile 2>/dev/null exitcode=$? if [ $exitcode -eq 0 ]; then checkfiles exitcode=$? else np="" ns="" fi if [ $exitcode -eq 0 ]; then if [ "$conversion" = "" ]; then cat $scratchfile >> ${scratchfile}.out else cat $scratchfile | jq '.'$conversion >> ${scratchfile}.out fi # case "$service" in # # Concatenate both files # query) # if [ "$havearray" = true ]; then # cat $scratchfile >> ${scratchfile}.out # else # cat $scratchfile | jq '.items' >> ${scratchfile}.out # fi # ;; # idcs) # cat $scratchfile | jq '.Resources' >> ${scratchfile}.out # ;; # objectstorage | compat-objectstorage) # if [ $objects -gt 0 ]; then # cat $scratchfile | jq '.objects' >> ${scratchfile}.out # else # cat $scratchfile >> ${scratchfile}.out # fi # ;; # *) # cat $scratchfile >> ${scratchfile}.out # esac fi done # # Check for array # result=`head -c 1 ${scratchfile}.out` # Read the first char in file # # if [ "$result" = "[" -o "$ENVELOPE_API" = false ]; then # if [ "$result" = "[" ]; then # # Use array # "$jq" --slurp add ${scratchfile}.out > ${scratchfile}.pre # stat=$? # else # # Create array # cat ${scratchfile}.out | "$jq" --slurp > ${scratchfile}.pre # stat=$? # fi # Check for empty result result=`head -n 1 ${scratchfile}.out` if [ "$result" != '[]' ]; then result=`echo "$result" | grep '"'` if [ "$result" != "" ]; then # Result is a string printf '[\n %s\n]\n' "$result" > ${scratchfile}.pre else # Normalize JSON cat ${scratchfile}.out | norm-json --quiet --raw > ${scratchfile}.pre fi if [ "$ENVELOPE_API" = false ]; then mv -f ${scratchfile}.pre ${scratchfile}.out else titems=`cat ${scratchfile}.pre | "$jq" -r '. | length'` # if [ $objects -gt 0 -a $titems -gt 1 ]; then # # We found a list of objectstorage objects # # echo "endpoint: '$endpoint' - request: '$request'." >> /tmp/test.txt # cat ${scratchfile}.pre | "$jq" -r '.[].name' > ${scratchfile}.out # "$jq" -r = raw output -> eliminates the "" # printf "" > ${scratchfile}.pre # while read result; do # result="$(echo $( rawurlencode "$result" ))" # echo Gefunden: $0 "$endpoint" "head" "${request}/$result" # $0 "$endpoint" "head" "${request}/$result" >> ${scratchfile}.pre # done < ${scratchfile}.out # mv -f ${scratchfile}.pre ${scratchfile}.out # cat ${scratchfile}.out | "$jq" '.items' | "$jq" --slurp > ${scratchfile}.pre # fi printf '{\n "content": ' > ${scratchfile}.out if [ $titems -eq 1 ]; then cat ${scratchfile}.pre | "$jq" '.[]' >> ${scratchfile}.out else cat ${scratchfile}.pre >> ${scratchfile}.out fi printf ',\n "contentItems": %s,\n "creator": "oci-api",\n "service": "%s",\n "endpoint": "%s",\n "method": "%s",\n "request": "%s"\n}\n' \ "$titems" "$service" "$endpoint" "$method" "$request" >> ${scratchfile}.out fi cat ${scratchfile}.out | "$jq" -M fi fi fi # Remove temp files Cleanup # Exit with error code exit $exitcode