#!/bin/bash ## ---------------------------------------------------------------------------- # # SCRIPT NAME: aka_purge.sh # # DESCRIPTION: Purge the Akamai cache via CCU REST API v3. # # REVISION: v0.9 # DATE: May 2019 # AUTHORS: Luca, Genasci # Marco, De March # # CONTRIBUTORS: Raffaele, Rusconi # # TESTED: Tested in: # GNU bash, version 4.4.12(3)-release (x86_64-unknown-cygwin) # GNU bash, version 5.0.7(1)-release (x86_64-pc-linux-gnu) # GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu) # GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18) # ## ---------------------------------------------------------------------------- ## Definition if functions ---------------------------------------------------- function aa_set { local key="${1}" local val="${2}" shift 2 declare -a arr=( ${@} ) local t_key local idx=0 for el in "${arr[@]}" do t_key="${el%%:*}" [ "${key}" == "${t_key}" ] && { arr[idx]="${key}:${val}"; echo "${arr[@]}"; return 0; } let idx++ done arr[idx]="${key}:${val}" echo "${arr[@]}" return 0 } function aa_get { local key="${1}" shift 1 declare -a arr=( ${@} ) for el in "${arr[@]}" do t_key="${el%%:*}" [ "${key}" == "${t_key}" ] && { echo "${el#*:}"; return 0; } done return 1 } function _get_property { [ "$#" -lt 2 ] && return 1 local RC=$1 local PROP=$2 local value=$(cat ${RC} | sed "/^\s*#/d;s/\s*#[^\"']*$//" | grep ${PROP} | tail -n 1 | cut -d '=' -f2- ) if [ -z "${value}" ]; then return 1 else echo ${value} return 0 fi } function get_properties { local file="${1}" declare -a aka_props local tmp tmp=$( _get_property "${file}" client_secret ) [ -z "${tmp}" ] && { >&2 echo "ERROR: Please, set variable client_secret in file ${file}!!!"; exit 1; } aka_props=( $( aa_set client_secret ${tmp} "${aka_props[@]}" ) ) tmp=$( _get_property "${file}" client_token ) [ -z "${tmp}" ] && { >&2 echo "ERROR: Please, set variable client_token in file ${file}!!!"; exit 1; } aka_props=( $( aa_set client_token ${tmp} "${aka_props[@]}" ) ) tmp=$( _get_property "${file}" access_token ) [ -z "${tmp}" ] && { >&2 echo "ERROR: Please, set variable access_token in file ${file}!!!"; exit 1; } aka_props=( $( aa_set access_token ${tmp} "${aka_props[@]}" ) ) tmp=$( _get_property "${file}" host ) [ -z "${tmp}" ] && { >&2 echo "ERROR: Please, set variable host in file ${file}!!!"; exit 1; } aka_props=( $( aa_set host ${tmp} "${aka_props[@]}" ) ) tmp=$( _get_property "${file}" network ) [ -z "${tmp}" ] && aka_props=( $( aa_set network staging "${aka_props[@]}" ) ) || aka_props=( $( aa_set network ${tmp} "${aka_props[@]}" ) ) tmp=$( _get_property "${file}" action ) [ -z "${tmp}" ] && aka_props=( $( aa_set action invalidate "${aka_props[@]}" ) ) || aka_props=( $( aa_set action ${tmp} "${aka_props[@]}" ) ) tmp=$( _get_property "${file}" type ) [ -z "${tmp}" ] && aka_props=( $( aa_set type url "${aka_props[@]}" ) ) || aka_props=( $( aa_set type ${tmp} "${aka_props[@]}" ) ) tmp=$( _get_property "${file}" n_retries ) [ -z "${tmp}" ] && aka_props=( $( aa_set n_retries 3 "${aka_props[@]}" ) ) || aka_props=( $( aa_set n_retries ${tmp} "${aka_props[@]}" ) ) tmp=$( _get_property "${file}" t_retry ) [ -z "${tmp}" ] && aka_props=( $( aa_set t_retry 60 "${aka_props[@]}" ) ) || aka_props=( $( aa_set t_retry ${tmp} "${aka_props[@]}" ) ) echo "${aka_props[@]}" return 0 } function mk_nonce { local s=$1 if [ -z ${s} ]; then s=$( date -u +'%Y%m%dT%H:%M:%S%z' ); fi if [ $(uname) == 'Darwin' ]; then echo -n "${s}" | md5 -r | cut -d ' ' -f1 | sed 's/.\{4\}/&-/g' | sed 's/.$//' else echo -n "${s}" | md5sum | cut -d ' ' -f1 | sed 's/.\{4\}/&-/g' | sed 's/.$//' fi } function base64_hmac_sha256 { [ "$#" -lt 2 ] && return 1 local key=$1 local value=$2 echo -ne "${value}"| openssl sha256 -binary -hmac "${key}" | openssl base64 } function base64_sha256 { [ "$#" -lt 1 ] && return 1 local value=$1 echo -ne "${value}" | openssl dgst -binary -sha256 | openssl base64 } function mk_auth_header { [ "$#" -lt 3 ] && return 1 local timestamp=${1} local nonce=${2} shift 2 declare -a aka_props=( ${@} ) # EG1-HMAC-SHA256 echo -n "client_token="$(aa_get client_token "${aka_props[@]}")";access_token="$( aa_get access_token "${aka_props[@]}" )";timestamp=${timestamp};nonce=${nonce};" } function sign_data { [ "$#" -lt 2 ] && return 1 local key=${1} shift declare -a data_to_sign=( ${@} ) local method=$( aa_get method "${data_to_sign[@]}" ) local scheme=$( aa_get scheme "${data_to_sign[@]}" ) local host=$( aa_get host "${data_to_sign[@]}" ) local request_uri=$( aa_get request_uri "${data_to_sign[@]}" ) local hash_content=$( aa_get hash_content "${data_to_sign[@]}" ) local auth_header=$( aa_get auth_header "${data_to_sign[@]}" ) local data="${method}\t${scheme}\t${host}\t${request_uri}\t\t${hash_content}\tEG1-HMAC-SHA256 ${auth_header}" base64_hmac_sha256 "${key}" "${data}" } function mk_body { local type="${1}" local objects="${2}" local domain="${3}" local arr_objects local objs IFS=',' read -r -a arr_objects <<< "${objects}" for i in ${!arr_objects[@]} do local tmp=$( echo ${arr_objects[i]} | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' -e 's,/,\\/,g' ) if [ "${type}" == "cpcode" ]; then objs="${objs},${tmp}" else objs="${objs},\"${tmp}\"" fi done objs=$( echo "${objs}" | sed 's/^,//' ) if [ "${type}" == "url" ]; then echo "{\"hostname\":\"${domain}\",\"objects\":[${objs}]}" else echo "{\"objects\":[${objs}]}" fi } function get_objects { local file="${1}" local domain="${2}" local type="${3}" local objs case ${type} in url ) cat "${file}" | grep -E '^(http(s)?://'${domain}')?/' | sed -E 's|^http(s)?://'${domain}'||' | paste -sd ',' ;; cpcode ) cat "${file}" | sed -E '/^[0-9]+$/!d' | paste -sd ',' ;; tag ) cat "${file}" | paste -sd ',' ;; * ) return 1 ;; esac return 0 } function separate_objects { local objs="${1}" local limit=49000 local bytes buffer local b_len=0 declare -a arr bytes=$( echo "${objs}" | wc -c ) [ ${bytes} -le ${limit} ] && { echo ${objs}; return 0; } while true do buffer=${objs:${b_len}:${limit}} [ -z ${buffer} ] && break buffer=${buffer%,*} arr+=( ${buffer} ) b_len=$(( ${b_len} + ${#buffer} + 1 )) echo ${b_len} done echo "${arr[@]}" return 0 } function countdown(){ local cn=${1} local lb=${2} date1=$((`date +%s` + ${cn})); while [ "$date1" -ge `date +%s` ]; do echo -ne "${lb}: $(date -u --date @$(($date1 - `date +%s`)) +%H:%M:%S)\r"; sleep 0.1 done } function getopt_type { local type="BSD" getopt -T > /dev/null [ $? -eq 4 ] && type="GNU" echo "${type}" } ## Options of script ---------------------------------------------------------- P_NAME=${0##*\/} GETOPT_TYPE=$( getopt_type ) WARNING= [ "${GETOPT_TYPE}" != "GNU" ] && { WARNING+=$'\n'$'\e[93m'; WARNING+="WARNING"$'\n'; WARNING+=" The version of your getopt is not GNU."$'\n'; WARNING+=" If you want use the long options use the brew command to install gnu-getopt."$'\n'; WARNING+=" ${P_NAME} work fine with short options."$'\n'; WARNING+=$'\e[0m'; } CONF=/usr/share/rivendell/keys/edgegrid.conf declare -a AKA_PROPS=$( get_properties "${CONF}" ) usage() { cat << EOF usage: ${P_NAME} [OPTIONS] -o Purge the Akamai cache via CCU REST API v3. REMARKS Please create a config file in /usr/share/rivendell/keys ${WARNING} PARAMETERS: -o, --objects List of objects to purge (with comma separated values) -i, --input-file Input file that contain a list of objects. The separator value in the file mode is the carriage return Type | Comment -------------------------------------------------------- url | The addresses considered, depend of the domain | (see the option -d). If an address not have a | domain it's included in the purge procedure. -------------------------------------------------------- cpcode | List of the cpcodes. The items must be numbers | otherwise will be excluded. -------------------------------------------------------- tag | List of a tags OPTIONS: -t, --type Type of objects Possible values: url, cpcode or tag Default: ${TYPE} -d, --domain Domain site (es. your.domain.com). To use with type=url -a, --action The desired action to manage the cache Possible values: invalidate or delete Default: ${ACTION} -n, --network The network on which you want to invalidate or delete content Possible values: staging or production Default: ${NETWORK} -r, --show-quests Show the requests -h, --help Show this message -v, --version Show version CONFIG FILE: In the config file the following values have to been declared: client_secret = client_token = access_token = host = There is the possibility to set the default values: network = action = type = If no values are declared the default ones are: network = staging action = invalidate type = url For manage an error: n_retries = (default 3) t_retry =