summaryrefslogtreecommitdiffstats
path: root/datarouter-prov-client/misc/drprov-client.sh
blob: 71017954a0804101f3e3f3a647c523601b49633e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
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}