Add DR provisioning client initContainer
[dmaap/datarouter.git] / datarouter-prov-client / misc / drprov-client.sh
1 #!/bin/sh
2
3 PROVURL=${PROVURL:-"http://dmaap-dr-prov:8080"}
4 DRCONFIGDIR=${DRCONFIGDIR:-"/opt/app/config"}
5 ONBEHALFHDR="X-DMAAP-DR-ON-BEHALF-OF: drprovclient"
6 FEEDTYPE="Content-Type: application/vnd.dmaap-dr.feed"
7 SUBTYPE="Content-Type: application/vnd.dmaap-dr.subscription"
8 APPCONFIGINPUT=${APPCONFIGINPUT:-"/config-input"}
9 APPCONFIG=${APPCONFIG:-"/config"}
10
11 function logit() {
12     # Direct log entries to stderr because to
13     # allow logging inside functions that use
14     # stdout to return values
15     echo $(date -u -Ins)\|"$@" >&2
16 }
17
18 function getFeedByNameVer() {
19 # Get feed info using name and version
20 #   $1 -- Feed name (arbitrary string without embedded '"')
21 #   $2 -- Feed version (arbitrary string without embedded '"')
22 #   Returns feed data and exits with 0 if
23 #   feed is found.
24 #   Returns empty string and exits with 1 in
25 #   any other case.
26
27     # Construct urlencoded query
28     local NAME="$(printf %s "$1" | tr -d '"' | jq -R -r @uri)"
29     local VER="$(printf %s "$2" | tr -d '"' | jq -R -r @uri)"
30     local QUERYURL="${PROVURL}"/?"name=${NAME}"\&version="${VER}"
31     local FEEDDATA
32
33     # Make the query
34     # Not checking exact cause for error,
35     # just looking for success or not.
36     local RV=1
37     if FEEDDATA=$(curl --fail -s -H "${ONBEHALFHDR}" "${QUERYURL}")
38     then
39             echo ${FEEDDATA}
40         RV=0
41     fi
42
43     return ${RV}
44 }
45
46 function subscriptionExists() {
47 #  See if there a subscription to the feed
48 #  that has the specified username, password,
49 #  and delivery URL.
50 #      $1 -- subscribe URL for the feed
51 #      $2 -- username for the subscription
52 #      $3 -- password for the subscription
53 #      $4 -- delivery URL for the subscription
54 # Sets a return value of 0 if a matching
55 # subscription is found and echoes the
56 # corresponding subscription URL.
57 # Others sets a return value of 1 and
58 # echoes an empty string.
59
60 local RV=1
61 local SUBRESP
62 local SUBDATA
63 local SUBLIST
64
65 # Query the feed's subscribe URL to get a
66 # list of the URLs for existing subscriptions
67 if SUBRESP=$(curl -s --fail -H "${ONBEHALFHDR}" "$1")
68 then
69     # Loop through the list of existing subscriptions
70     while read -r SUBURL   # read from $SUBRESP (see redirect on "done")
71     do
72         # Retrieve subscription data from the subscription's URL
73         if SUBDATA=$(curl -s --fail -H "${ONBEHALFHDR}" "${SUBURL}")
74         then
75             local SUBUSER=$(echo ${SUBDATA} | jq -r .delivery.user)
76             local SUBPASS=$(echo ${SUBDATA} | jq -r .delivery.password)
77             local SUBDELURL=$(echo ${SUBDATA} | jq -r .delivery.url)
78             if [ "$2" = "${SUBUSER}" -a "$3" = "${SUBPASS}" -a "$4" = "${SUBDELURL}" ]
79             then
80                 RV=0  #TRUE
81                 break
82             fi
83         else
84             # This will happen, for instance, if the name in
85             # in the "X-DMAAP-DR-ON-BEHALF-OF" header doesn't
86             # match the owner of the feed.  (Not likely in
87             # the ONAP use case, but possible.)  Could also be
88             # the result of connectivity issues, bad URL,...
89             logit "WARNING: Could not retrieve ${SUBURL}"
90         fi
91     done < <(echo ${SUBRESP} | jq -r .[])
92  else
93     logit "ERROR: failed to fetch subscription list from $1"
94 fi
95
96 echo ${SUBURL}
97 return ${RV}
98 }
99
100 function createFeedFromFile() {
101 # Create a feed using information from a JSON file
102 # Note that creating a feed also creates the publisher
103 #   $1 -- Path to JSON file
104 #   Returns feed data from the DR provisioning node
105 #   and exits with 0 if the feed is created.
106 #   Returns empty string and exits with 1 in
107 #   any other case.
108
109     local FEEDDATA
110     local RV=1
111
112     if test -f "$1"
113     then
114         # Substitute any environment variables in the subscription file
115         local FEEDREQUEST=$(envsubst < "$1")
116         if FEEDDATA=$(curl --fail -s --data-ascii "${FEEDREQUEST}" -H "${ONBEHALFHDR}" -H "$FEEDTYPE" ${PROVURL}/)
117         then
118             echo ${FEEDDATA}
119             RV=0
120         fi
121     fi
122
123 return ${RV}
124 }
125
126 function createSubscriptionFromFile() {
127 # Create a subscription to a feed from a JSON file
128 # if a subscription with the same username, password
129 # and delivery URL doesn't already exist.
130 # We don't want multiple subscriptions if for some
131 # reason a subscriber's pod is redeployed.
132 # $1 -- JSON file defining the subscription
133 #
134     local SUBURL
135     local SUBDATA
136     local EXISTINGSUB
137
138     local RV=1
139
140     if test -f "$1"
141     then
142         # Extract feed name and version from the JSON file
143         local FEEDNAME=$(jq '.feed.name' "$1")
144         local FEEDVER=$(jq '.feed.version' "$1")
145
146         # Extract subscription parameters from the JSON file
147         # (needed for checking if there's an existing subscription)
148         local SUBUSER=$(jq -r '.delivery.user' "$1")
149         local SUBPASS=$(jq -r '.delivery.password' "$1")
150         local SUBDELURL=$(jq -r '.delivery.url' "$1")
151
152         # Look up the feed and get the subscribe URL
153         if SUBURL=$(getFeedByNameVer "${FEEDNAME}" "${FEEDVER}" | jq -r .links.subscribe)
154         then
155             # Check whether a matching subscription already exists
156             if EXISTINGSUB=$(subscriptionExists ${SUBURL} ${SUBUSER} ${SUBPASS} ${SUBDELURL})
157             then
158                 logit "Using existing subscription: ${EXISTINGSUB}.  No new subscription created."
159                 RV=0
160             else
161                 # Substitute any environment variables in the subscription file
162                 local SUBREQUEST=$(envsubst < "$1")
163                 # Create the subscription
164                 if SUBDATA=$(curl --fail -s --data-ascii "${SUBREQUEST}" -H "${ONBEHALFHDR}" -H "${SUBTYPE}" ${SUBURL})
165                 then
166                     logit "Created new subscription: $(echo ${SUBDATA} | jq -r '.links.self')"
167                     RV=0
168                 fi
169             fi
170         fi
171     fi
172     return ${RV}
173 }
174
175 function createOrGetFeed() {
176 # Retrieve feed data from the DR provisioning node for
177 # the feed described in a JSON file.  If the feed
178 # does not exist, create the file.
179 #  $1 -- Path to JSON file
180 #  Returns feed data from the DR provisioning node
181 #  if the feed exists or if it has been successfully
182 #  created, and exits with 0.
183 #  Returns empty string and exits with 1 in
184 #  any other case.
185
186     local FEEDDATA
187
188     local RV=1
189
190     if test -f "$1"
191     then
192         # Extract feed name and version from file
193         local NAME=$(cat "$1" | jq .name)
194         local VER=$(cat "$1" | jq .version)
195
196         # Check whether feed already exists
197         # (DR does not allow two feeds with same name and version)
198         if FEEDDATA=$(getFeedByNameVer "${NAME}" "${VER}")
199         then
200             logit "Using existing feed: $(echo ${FEEDDATA} | jq -r '.links.self'). No new feed created."
201             RV=0
202         else
203             # Create feed
204             if FEEDDATA=$(createFeedFromFile "$1")
205             then
206                 logit "Created new feed:  $(echo ${FEEDDATA} | jq -r '.links.self')" >&2
207                 RV=0
208             fi
209         fi
210     fi
211
212     echo ${FEEDDATA}
213     return $RV
214 }
215
216 function provisionFeeds() {
217 # Create a feed for each JSON file in the
218 # directory specified in $1, unless the
219 # a feed with the same name and version
220 # already exists, in which case use the
221 # information for the existing feed.
222 # $1 -- Path to directory containing JSON
223 #       files defining DR feeds
224
225     local FEEDDATA
226     if test -d "$1"
227     then
228         for FEEDFILE in $(ls "$1"/*.json)
229         do
230             logit "Creating feed from ${FEEDFILE}"
231             if FEEDDATA=$(createOrGetFeed ${FEEDFILE})
232             then
233                 # Set environment variables with result data
234                 # Note that FEEDNUM is taken from the number that's embedded
235                 # in the file defining the feed.
236                 FEEDNUM=$(echo "${FEEDFILE}" | sed 's/^.*\/.*-\([0-9]\+\).json/\1/')
237                 export DR_FEED_PUBURL_${FEEDNUM}="$(echo ${FEEDDATA} | jq '.links.publish')"
238                 export DR_FEED_LOGURL_${FEEDNUM}="$(echo ${FEEDDATA} | jq '.links.log')"
239             fi
240         done
241     fi
242 }
243
244 function provisionSubscriptions() {
245 # Create a subscription for each JSON file in the
246 # directory specified in $1
247 # $1 -- Path to directory containing JSON
248 #       files definining DR subscriptions
249 # Note that when provisioning a subscription to a feed,
250 # the DR API doesn't return any additional information
251 # that the subscriber needs.  Hence no information is
252 # extracted from the DR API response, and no environment
253 # variables are exported (unlike the provisionFeeds function.)
254
255     if test -d "$1"
256     then
257         for SUBFILE in $(ls "$1"/*.json)
258         do
259             logit "Creating subscription from ${SUBFILE}"
260             createSubscriptionFromFile ${SUBFILE}
261         done
262     fi
263 }
264
265 function updateConfigurations() {
266 # Run envsubst against each file in $1 (the application
267 # configuration input directory) to create a corresponding
268 # file in $2 (the application configuration directory) with
269 # environment variables replaced by the values set in the
270 # provisioning steps.  The file(s) in $2 will be used by
271 # the application to get (among other things) the information
272 # needed to work with DR feeds.
273 # $1 -- path to application configuration input directory
274 # $2 -- path to application configuration directory
275     cd "$1"
276     for CONFFILE in $(ls -1)
277     do
278         logit "Substituting environment vars in ${CONFFILE}"
279         envsubst <${CONFFILE} > "$2"/${CONFFILE}
280     done
281 }
282 set -ue
283
284 provisionFeeds ${DRCONFIGDIR}/feeds
285 provisionSubscriptions ${DRCONFIGDIR}/dr_subs
286 updateConfigurations ${APPCONFIGINPUT} ${APPCONFIG}