diff --git a/.gitignore b/.gitignore index 387cdb2..203be5a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ .ovhConsumerKey* libs/ profile/ - +contrib/test/*.json diff --git a/README.md b/README.md index ad3d4a2..865f7e8 100644 --- a/README.md +++ b/README.md @@ -74,3 +74,8 @@ To create a Consumer key for different account or usage (profile is created if m ./ovh-api-bash-client.sh --profile demo1 --init ./ovh-api-bash-client.sh --profile demo2 --init ``` + +Embedded lib for external scripts +--------------------------------- + +See **contrib/** directory diff --git a/contrib/README.md b/contrib/README.md new file mode 100644 index 0000000..a6e5777 --- /dev/null +++ b/contrib/README.md @@ -0,0 +1,104 @@ +## Embedded libs for external scripts + +### jsonsh-lib.sh + +#### Introduction + +Wrapper for JSON.sh, enhancing output : +- action on keys : transform original key (JSON array) to a friendly format +- action on values : trim double quotes and spaces + +**original JSON content** +``` +{ + "person": { + "name": "Foobar1", + "foo1": { "bar": "baz1" }, + "child": [ {"name":"bob1_1"}, {"name":"bob1_2"} ] + }, + "person": { + "name": "Foobar2", + "foo1": { "bar": "baz2" }, + "child": [ {"name":"bob2_2"}, {"name":"bob2_2"} ] + } +} +``` + +**JSON.sh output** +``` +["person","name"] "Foobar1" +["person","foo1","bar"] "baz1" +["person","child",0,"name"] "bob1_1" +["person","child",1,"name"] "bob1_2" +["person","name"] "Foobar2" +["person","foo1","bar"] "baz2" +["person","child",0,"name"] "bob2_2" +["person","child",1,"name"] "bob2_2" +``` + +**wrapper output** +``` +person.name Foobar1 +person.foo1.bar baz1 +person.child[0].name bob1_1 +person.child[1].name bob1_2 +person.name Foobar2 +person.foo1.bar baz2 +person.child[0].name bob2_2 +person.child[1].name bob2_2 +``` + +#### Functions + +- loadJSON() : forward JSON content to JSON.sh script if JSON is set, otherwise print JSON.sh output) +- getJSONKeys() : print JSON keys +- getJSONValue() : print JSON key's value +- getJSONValues() : print full result (json key and value) + +JSON.sh is called only one time + +From your script or commandline, you can set : +- JSONSH_DIR if JSON.sh is not installed on your system path (should be set before including the lib) +- JSONSH_SEPARATOR if you want a custom separator between JSON key and value (default is ":") +- JSONSHLIB_DEBUG to 1 to enable lib debugging + +#### Samples + +See **test/** directory : + +``` +JSONSHLIB_DEBUG=1 ./test/jsonshlib_test.sh +``` + +### ovh-api-lib.sh + +- OvhRequestApi() is wrapper for ovh-api-bash-client.sh +- use jsonsh-lib.sh ( just using loadJSON() ) + +**usage** +``` +OvhRequestApi url [method] [post_data] +``` + +From your script or commandline, you can set : +- OVHAPI_BASHCLIENT_PROFILE +- OVHAPI_TARGET +- OVHAPILIB_DEBUG to 1 to enable lib debugging + +This function set variables OVHAPI_HTTP_STATUS and OVHAPI_HTTP_RESPONSE + +OVHAPI_HTTP_RESPONSE is forwarded to loadJSON() to avoid user to put this line each time. + +#### Samples + +Once you've a valid OVH API authentication, you can use the library + +You can find some samples scripts in the **samples/** directory + +**sample usage** + +``` +OVHAPI_BASHCLIENT_PROFILE=demo samples/list-domains.sh +``` + +See **samples/** directory for more details diff --git a/contrib/jsonsh-lib.sh b/contrib/jsonsh-lib.sh new file mode 100644 index 0000000..755d651 --- /dev/null +++ b/contrib/jsonsh-lib.sh @@ -0,0 +1,209 @@ +#!/usr/bin/env bash + +# +# Lib for parsing https://github.com/dominictarr/JSON.sh output +# + +JSONSH_CACHE= +JSONSH_SOURCE_MD5= +JSONSH_SEPARATOR= + +JSONSHLIB_DEBUG=${JSONSHLIB_DEBUG:-0} + +### detect JSON.sh location +# JSON.sh searched in system path +readonly JSONSH_SYSTEM_DIR=$(dirname "$(which JSON.sh 2>/dev/null)" ) + +# can be overrided +JSONSH_DIR=${JSONSH_DIR:-"${JSONSH_SYSTEM_DIR}"} + +if [ -z "${JSONSH_DIR}" ]; then + echo "JSONSH_DIR should be set" >&2 + exit 1 +else + # to get absolte path + JSONSH_DIR=$(cd "${JSONSH_DIR}" && pwd) + if [ ! -f "${JSONSH_DIR}/JSON.sh" ]; then + echo "${JSONSH_DIR}/JSON.sh not found" >&2 + exit 1 + fi +fi + +readonly JSONSH_DIR + +# debug output if wanted +_jsonshlib_echo_debug() +{ + if [ "${JSONSHLIB_DEBUG}" == "1" ]; then + echo "[debug:${FUNCNAME[1]}] $*" >&2 + fi +} + +# +# single entry point with JSON.sh +# load json defined as argument, and set result to JSONSH_CACHE +# +# keep result in cache to avoid useless calls to JSON.sh +# +# usage : +# to set source json : loadJSON "json content" +# to get JSON.sh output, don't set argument +# +loadJSON() +{ + local json_source="$1" + local current_md5= + + if [ -z "${json_source}" ]; then + if [ -z "${JSONSH_CACHE}" ]; then + echo "JSON content is empty" >&2 + exit 1 + fi + _jsonshlib_echo_debug "get JSON.sh result from cache" + echo "${JSONSH_CACHE}" + else + # only follow to JSON.sh if JSon content differs + current_md5=$(echo "${json_source}" | md5sum | cut -d ' ' -f1) + if [ "${JSONSH_SOURCE_MD5}" != "${current_md5}" ]; then + _jsonshlib_echo_debug "new JSON source, build JSON.sh cache" + JSONSH_SOURCE_MD5=${current_md5} + JSONSH_CACHE=$("${JSONSH_DIR}/JSON.sh" -l <<< "${json_source}") + fi + fi + + return 0 + +} + +# +# convert JSON.sh key output format (JSON array) and trim value, through pipe +# +# sample : +# json.sh output : ["foo","bar",0,"baz"] " json value " +# new output : foo.bar[0].baz json value +# +# for each value, outside double quotes and spaces are removed +# +# _JSonSH_rewrite_output getKeys : print only keys +# _JSonSH_rewrite_output getValue : print only value for the field +# _JSonSH_rewrite_output getFull : print pair of key/value +# +# separator between key and value can be overrided if JSONSH_SEPARATOR is set (default = ":") +# +_JSonSH_rewrite_output() +{ + local action=$1 + local wanted_key=$2 + + if [[ "${action}" == "getValue" ]] && [[ -z "${wanted_key}" ]]; then + echo "key is required" >&2 + exit 1 + fi + + JSONSH_SEPARATOR=${JSONSH_SEPARATOR:-":"} + + awk -F '\t' \ + -v action="${action}" \ + -v wanted_key="${wanted_key}" \ + -v separator="${JSONSH_SEPARATOR}" \ + '{ + json_key = $1 + # drop the key from the line + $1 = "" + json_value=$0 + + ## Actions on json key : + # 1) remove some chars : brackets and double quotes + gsub(/\[|\]|\"/,"",json_key) + # 2) detect array index between comma, put digits between brackets + json_key = gensub(/(,([[:digit:]]+)(,|))/,"[\\2]\\3","g",json_key) + # 3) replace each comma with dot + gsub(/,/,".",json_key) + + ## Actions on json value : + # remove first/last double quotes if present + json_value = gensub(/"(.*)"$/,"\\1","g",json_value) + # trim first/last spaces of value + gsub(/^\s+|\s+$/,"",json_value) + + switch (action) { + case "getKeys": + print json_key + break + case "getValue": + # remove first/last double quotes if present + wanted_key = gensub(/"(.*)"$/,"\\1","g",wanted_key) + # the value for a key is wanted + if (json_key == wanted_key) + { + # display value if found and stop + print json_value + exit 0 + } + break + case "getFull": + if (json_key ~ /^[0-9]+$/ ) + { + # the key is a number, only value is needed + print json_value + } else { + # the key is a string, display key and value + print json_key separator json_value + } + break + default: + print "Bad action !" >"/dev/stderr" + exit 1 + break + } + }' &2 + fi +} + +# to override profile, define value in the variable OVHAPI_BASHCLIENT_PROFILE +# to override target, define value in the variable OVHAPI_TARGET +# OvhRequestApi url [method] [post_data] +# +# default method: get +# return response code in OVHAPI_HTTP_STATUS and content in OVHAPI_HTTP_RESPONSE +OvhRequestApi() +{ + local url=$1 + local method=$2 + local data=$3 + + local client_response= + local cmd_profile= + local cmd=(${OVHAPI_BASHCLIENT_BIN}) + + ## construct arguments array + if [ -n "${OVHAPI_BASHCLIENT_PROFILE}" ]; then + cmd+=(--profile ${OVHAPI_BASHCLIENT_PROFILE}) + fi + cmd_profile=${cmd[*]} + + if [ -n "${url}" ]; then + cmd+=(--url ${url}) + fi + + if [ -n "${method}" ]; then + cmd+=(--method ${method}) + fi + + if [ -n "${OVHAPI_TARGET}" ]; then + cmd+=(--target ${OVHAPI_TARGET}) + fi + + if [ "${method}" == "POST" ]; then + # double-quote data content for bash input + data=$(printf "%q" "${data}") + cmd+=(--data ${data}) + fi + + _ovhapilib_echo_debug "command: ${cmd[*]}" + + # best way found to correctly pass quoted arguments to a command called from a function + client_response=$(echo "${cmd[*]}" | bash) + + OVHAPI_HTTP_STATUS=$(echo "${client_response}" | cut -d ' ' -f1) + OVHAPI_HTTP_RESPONSE="$(echo "${client_response}" | cut -d ' ' -f2-)" + + # catch profile error + if [[ ! ${OVHAPI_HTTP_STATUS} =~ ^[0-9]+$ ]] && [[ ${OVHAPI_HTTP_RESPONSE} == *$'\n'* ]]; then + OVHAPI_HTTP_STATUS=500 + OVHAPI_HTTP_RESPONSE=$(cat <