Add DR provisioning client initContainer
[dmaap/datarouter.git] / datarouter-prov-client / misc / drprov-client.sh
diff --git a/datarouter-prov-client/misc/drprov-client.sh b/datarouter-prov-client/misc/drprov-client.sh
new file mode 100755 (executable)
index 0000000..7101795
--- /dev/null
@@ -0,0 +1,286 @@
+#!/bin/sh
+
+PROVURL=${PROVURL:-"http://dmaap-dr-prov:8080"}
+DRCONFIGDIR=${DRCONFIGDIR:-"/opt/app/config"}
+ONBEHALFHDR="X-DMAAP-DR-ON-BEHALF-OF: drprovclient"
+FEEDTYPE="Content-Type: application/vnd.dmaap-dr.feed"
+SUBTYPE="Content-Type: application/vnd.dmaap-dr.subscription"
+APPCONFIGINPUT=${APPCONFIGINPUT:-"/config-input"}
+APPCONFIG=${APPCONFIG:-"/config"}
+
+function logit() {
+    # Direct log entries to stderr because to
+    # allow logging inside functions that use
+    # stdout to return values
+    echo $(date -u -Ins)\|"$@" >&2
+}
+
+function getFeedByNameVer() {
+# Get feed info using name and version
+#   $1 -- Feed name (arbitrary string without embedded '"')
+#   $2 -- Feed version (arbitrary string without embedded '"')
+#   Returns feed data and exits with 0 if
+#   feed is found.
+#   Returns empty string and exits with 1 in
+#   any other case.
+
+    # Construct urlencoded query
+    local NAME="$(printf %s "$1" | tr -d '"' | jq -R -r @uri)"
+    local VER="$(printf %s "$2" | tr -d '"' | jq -R -r @uri)"
+    local QUERYURL="${PROVURL}"/?"name=${NAME}"\&version="${VER}"
+    local FEEDDATA
+
+    # Make the query
+    # Not checking exact cause for error,
+    # just looking for success or not.
+    local RV=1
+    if FEEDDATA=$(curl --fail -s -H "${ONBEHALFHDR}" "${QUERYURL}")
+    then
+           echo ${FEEDDATA}
+        RV=0
+    fi
+
+    return ${RV}
+}
+
+function subscriptionExists() {
+#  See if there a subscription to the feed
+#  that has the specified username, password,
+#  and delivery URL.
+#      $1 -- subscribe URL for the feed
+#      $2 -- username for the subscription
+#      $3 -- password for the subscription
+#      $4 -- delivery URL for the subscription
+# Sets a return value of 0 if a matching
+# subscription is found and echoes the
+# corresponding subscription URL.
+# Others sets a return value of 1 and
+# echoes an empty string.
+
+local RV=1
+local SUBRESP
+local SUBDATA
+local SUBLIST
+
+# Query the feed's subscribe URL to get a
+# list of the URLs for existing subscriptions
+if SUBRESP=$(curl -s --fail -H "${ONBEHALFHDR}" "$1")
+then
+    # Loop through the list of existing subscriptions
+    while read -r SUBURL   # read from $SUBRESP (see redirect on "done")
+    do
+        # Retrieve subscription data from the subscription's URL
+        if SUBDATA=$(curl -s --fail -H "${ONBEHALFHDR}" "${SUBURL}")
+        then
+            local SUBUSER=$(echo ${SUBDATA} | jq -r .delivery.user)
+            local SUBPASS=$(echo ${SUBDATA} | jq -r .delivery.password)
+            local SUBDELURL=$(echo ${SUBDATA} | jq -r .delivery.url)
+            if [ "$2" = "${SUBUSER}" -a "$3" = "${SUBPASS}" -a "$4" = "${SUBDELURL}" ]
+            then
+                RV=0  #TRUE
+                break
+            fi
+        else
+            # This will happen, for instance, if the name in
+            # in the "X-DMAAP-DR-ON-BEHALF-OF" header doesn't
+            # match the owner of the feed.  (Not likely in
+            # the ONAP use case, but possible.)  Could also be
+            # the result of connectivity issues, bad URL,...
+            logit "WARNING: Could not retrieve ${SUBURL}"
+        fi
+    done < <(echo ${SUBRESP} | jq -r .[])
+ else
+    logit "ERROR: failed to fetch subscription list from $1"
+fi
+
+echo ${SUBURL}
+return ${RV}
+}
+
+function createFeedFromFile() {
+# Create a feed using information from a JSON file
+# Note that creating a feed also creates the publisher
+#   $1 -- Path to JSON file
+#   Returns feed data from the DR provisioning node
+#   and exits with 0 if the feed is created.
+#   Returns empty string and exits with 1 in
+#   any other case.
+
+    local FEEDDATA
+    local RV=1
+
+    if test -f "$1"
+    then
+        # Substitute any environment variables in the subscription file
+        local FEEDREQUEST=$(envsubst < "$1")
+        if FEEDDATA=$(curl --fail -s --data-ascii "${FEEDREQUEST}" -H "${ONBEHALFHDR}" -H "$FEEDTYPE" ${PROVURL}/)
+        then
+            echo ${FEEDDATA}
+            RV=0
+        fi
+    fi
+
+return ${RV}
+}
+
+function createSubscriptionFromFile() {
+# Create a subscription to a feed from a JSON file
+# if a subscription with the same username, password
+# and delivery URL doesn't already exist.
+# We don't want multiple subscriptions if for some
+# reason a subscriber's pod is redeployed.
+# $1 -- JSON file defining the subscription
+#
+    local SUBURL
+    local SUBDATA
+    local EXISTINGSUB
+
+    local RV=1
+
+    if test -f "$1"
+    then
+        # Extract feed name and version from the JSON file
+        local FEEDNAME=$(jq '.feed.name' "$1")
+        local FEEDVER=$(jq '.feed.version' "$1")
+
+        # Extract subscription parameters from the JSON file
+        # (needed for checking if there's an existing subscription)
+        local SUBUSER=$(jq -r '.delivery.user' "$1")
+        local SUBPASS=$(jq -r '.delivery.password' "$1")
+        local SUBDELURL=$(jq -r '.delivery.url' "$1")
+
+        # Look up the feed and get the subscribe URL
+        if SUBURL=$(getFeedByNameVer "${FEEDNAME}" "${FEEDVER}" | jq -r .links.subscribe)
+        then
+            # Check whether a matching subscription already exists
+            if EXISTINGSUB=$(subscriptionExists ${SUBURL} ${SUBUSER} ${SUBPASS} ${SUBDELURL})
+            then
+                logit "Using existing subscription: ${EXISTINGSUB}.  No new subscription created."
+                RV=0
+            else
+                # Substitute any environment variables in the subscription file
+                local SUBREQUEST=$(envsubst < "$1")
+                # Create the subscription
+                if SUBDATA=$(curl --fail -s --data-ascii "${SUBREQUEST}" -H "${ONBEHALFHDR}" -H "${SUBTYPE}" ${SUBURL})
+                then
+                    logit "Created new subscription: $(echo ${SUBDATA} | jq -r '.links.self')"
+                    RV=0
+                fi
+            fi
+        fi
+    fi
+    return ${RV}
+}
+
+function createOrGetFeed() {
+# Retrieve feed data from the DR provisioning node for
+# the feed described in a JSON file.  If the feed
+# does not exist, create the file.
+#  $1 -- Path to JSON file
+#  Returns feed data from the DR provisioning node
+#  if the feed exists or if it has been successfully
+#  created, and exits with 0.
+#  Returns empty string and exits with 1 in
+#  any other case.
+
+    local FEEDDATA
+
+    local RV=1
+
+    if test -f "$1"
+    then
+        # Extract feed name and version from file
+        local NAME=$(cat "$1" | jq .name)
+        local VER=$(cat "$1" | jq .version)
+
+        # Check whether feed already exists
+        # (DR does not allow two feeds with same name and version)
+        if FEEDDATA=$(getFeedByNameVer "${NAME}" "${VER}")
+        then
+            logit "Using existing feed: $(echo ${FEEDDATA} | jq -r '.links.self'). No new feed created."
+            RV=0
+        else
+            # Create feed
+            if FEEDDATA=$(createFeedFromFile "$1")
+            then
+                logit "Created new feed:  $(echo ${FEEDDATA} | jq -r '.links.self')" >&2
+                RV=0
+            fi
+        fi
+    fi
+
+    echo ${FEEDDATA}
+    return $RV
+}
+
+function provisionFeeds() {
+# Create a feed for each JSON file in the
+# directory specified in $1, unless the
+# a feed with the same name and version
+# already exists, in which case use the
+# information for the existing feed.
+# $1 -- Path to directory containing JSON
+#       files defining DR feeds
+
+    local FEEDDATA
+    if test -d "$1"
+    then
+        for FEEDFILE in $(ls "$1"/*.json)
+        do
+            logit "Creating feed from ${FEEDFILE}"
+            if FEEDDATA=$(createOrGetFeed ${FEEDFILE})
+            then
+                # Set environment variables with result data
+                # Note that FEEDNUM is taken from the number that's embedded
+                # in the file defining the feed.
+                FEEDNUM=$(echo "${FEEDFILE}" | sed 's/^.*\/.*-\([0-9]\+\).json/\1/')
+                export DR_FEED_PUBURL_${FEEDNUM}="$(echo ${FEEDDATA} | jq '.links.publish')"
+                export DR_FEED_LOGURL_${FEEDNUM}="$(echo ${FEEDDATA} | jq '.links.log')"
+            fi
+        done
+    fi
+}
+
+function provisionSubscriptions() {
+# Create a subscription for each JSON file in the
+# directory specified in $1
+# $1 -- Path to directory containing JSON
+#       files definining DR subscriptions
+# Note that when provisioning a subscription to a feed,
+# the DR API doesn't return any additional information
+# that the subscriber needs.  Hence no information is
+# extracted from the DR API response, and no environment
+# variables are exported (unlike the provisionFeeds function.)
+
+    if test -d "$1"
+    then
+        for SUBFILE in $(ls "$1"/*.json)
+        do
+            logit "Creating subscription from ${SUBFILE}"
+            createSubscriptionFromFile ${SUBFILE}
+        done
+    fi
+}
+
+function updateConfigurations() {
+# Run envsubst against each file in $1 (the application
+# configuration input directory) to create a corresponding
+# file in $2 (the application configuration directory) with
+# environment variables replaced by the values set in the
+# provisioning steps.  The file(s) in $2 will be used by
+# the application to get (among other things) the information
+# needed to work with DR feeds.
+# $1 -- path to application configuration input directory
+# $2 -- path to application configuration directory
+    cd "$1"
+    for CONFFILE in $(ls -1)
+    do
+        logit "Substituting environment vars in ${CONFFILE}"
+        envsubst <${CONFFILE} > "$2"/${CONFFILE}
+    done
+}
+set -ue
+
+provisionFeeds ${DRCONFIGDIR}/feeds
+provisionSubscriptions ${DRCONFIGDIR}/dr_subs
+updateConfigurations ${APPCONFIGINPUT} ${APPCONFIG}