Support for XApp configuration update
[ric-plt/appmgr.git] / scripts / appmgrcli
1 #!/bin/sh
2 #
3 # Copyright (c) 2019 AT&T Intellectual Property.
4 # Copyright (c) 2019 Nokia.
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
9 #
10 #     http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 #
16 # See the License for the specific language governing permissions and
17 # limitations under the License.
18 #
19 #############################
20 # Simple cli for xapp manager
21 #
22 # In addition to standard shell tools, requires packages "curl" and
23 # "yajl-tools" (the second provides json_reformat on Ubuntu; on Red Hat-style
24 # distributions install "yajl" instead).
25 #
26 myname=appmgrcli
27
28 usage() {
29   cat <<EOF1
30 usage: $myname [-h host] [-p port] [-v] command params...
31 - command is one of deploy, undeploy, status, subscriptions, health, help
32 - (abbreviations dep, undep, stat, subs, heal allowed)
33 - Parameters of the commands that may have parameters:
34 -- deploy: name of the xapp to deploy
35 -- undeploy: name of the xapp to undeploy
36 -- status:
37 ---- No parameters: Lists information about all deployed xapps
38 ---- xapp name as parameter: Prints information about the given xapp
39 ---- xapp name and instance: Lists information about the given instance only
40 -- subscriptions is followed by sub-command list, add, delete, or modify
41 ---(abbreviations del and mod for delete and modify are allowed):
42 ---- list without parameters lists all subscriptions
43 ---- list with subscription id prints that subscription
44 ---- add URL eventType maxRetry retryTimer
45 ------- URL is the URL to notify
46 ------- eventType one of created,deleted,all
47 ------- maxRetry and retryTimer are positive decimal numbers
48 ---- modify id URL eventType maxRetry retryTimer
49 ------- id is the subscription id (find out with the list command)
50 --------the rest of the parameters are like in add
51 ---- delete id
52 ------- id is the subscription id to delete (find out with the list command)
53 - Default values for host and port can be set in environment
54 - variables APPMGR_HOST and APPMGR_PORT
55 - Option -v sets verbose mode.
56 EOF1
57 }
58
59 # Defaults
60
61 host=localhost
62 port=8080
63 verbose=0
64
65 # Check for environment override
66 if [ "x$APPMGR_HOST" != "x" ]; then
67     host="$APPMGR_HOST"
68 fi
69 if [ "x$APPMGR_PORT" != "x" ]; then
70     port="$APPMGR_PORT"
71 fi
72
73 # Proper shell option parsing:
74 while getopts  "h:p:v" flag
75 do
76   # Curiously, getopts does not guard against an argument-requiring option
77   # eating the next option. It also does not handle the -- convention.
78   # Here is how to fix that.
79   if [ "X$OPTARG" = 'X--' ]; then
80     break # Explicit end of options
81   fi
82   if expr -- "$OPTARG" : '-.*' > /dev/null ; then
83     echo $myname: Option -$flag has no required value, or value begins with -,
84     echo - which is disallowed.
85     usage
86     exit 1
87   fi
88   case $flag in
89   (h) host="$OPTARG"
90       ;;
91   (p) port="$OPTARG"
92       ;;
93   (v) verbose=1
94       ;;
95   (*)
96       echo $myname: Bad option letter or required option argument missing.
97       usage
98       exit 1
99       ;;
100   esac
101 done
102 # Get rid of the option part
103 shift $((OPTIND-1))
104
105 if [ $verbose = 1 ]; then
106   echo "host = $host"
107   echo "port = $port"
108 fi
109
110 # Verify command
111
112 case $1 in
113   (deploy|dep)
114     cmd=deploy
115     ;;
116   (undeploy|undep)
117     cmd=undeploy
118     ;;
119   (status|stat)
120     cmd=status
121     ;;
122   (subscriptions|subs)
123     cmd=subscriptions
124     ;;
125   (health|heal)
126     cmd=health
127     ;;
128   (config|upload)
129     cmd=config
130     ;;
131   (help)
132     usage
133     exit 0
134     ;;
135   (*)
136     if [ "x$1" = "x" ]; then
137      echo "$myname: Missing command"
138     else
139      echo "$myname: Unrecognized command $1"
140     fi
141     usage
142     exit 1
143     ;;
144 esac
145
146 if [ $verbose = 1 ]; then
147   echo "Command $cmd params=$2"
148 fi
149
150 errfile=`mktemp /tmp/appmgr_e.XXXXXXXXXX`
151 resultfile=`mktemp /tmp/appmgr_r.XXXXXXXXXX`
152 # Variable status used for the return value of the whole script.
153 status=0
154
155 # Helper for command execution:
156 # Do a rest call with "curl": $1 = method, $2 = path (without host and port
157 # which come from variables), $3 data to POST if needed
158 # returns 0 if OK, and any returned data is in $resultfile
159 # else 1, and error message from curl is in $errfile, which is printed
160 # before returning the 1.
161 # Also sets $status to the return value.
162 #
163 # On curl options: --silent --show-error disables progress bar, but allows
164 # error messages. --connect-timeout 20 limits waiting for connection to
165 # 20 seconds. In practice connection will succeed almost immediately,
166 # or in the case of wrong address not at all.
167 #
168 rest() {
169   local data
170   if [ "x$3" != "x" ]; then
171     data="--data $3"
172   fi
173
174   if curl --silent --show-error --connect-timeout 20 --header "Content-Type: application/json" -X $1 -o $resultfile "http://${host}:${port}$2" $data 2> $errfile ;then
175     status=0
176   else
177     cat $errfile
178     status=1
179   fi
180   return $status
181 }
182
183 remove_temps () {
184   rm -f $errfile $resultfile
185 }
186
187 # Execute command ($cmd guaranteed to be valid)
188 # Assumes the API currently implemented.
189 # Functions for each command below (except health which is so simple).
190
191 base=/ric/v1
192 base_xapps=$base/xapps
193 base_health=$base/health
194 base_subs=$base/subscriptions
195 base_config=$base/config
196
197 do_deploy() {
198   if [ "x$1" != "x" ]; then
199     if rest POST $base_xapps \{\"name\":\"$1\"\} ; then
200       json_reformat < $resultfile
201     fi
202   else
203     echo Error: expected the name of xapp to deploy
204     status=1
205   fi
206 }
207
208 do_undeploy() {
209   local urlpath
210
211   urlpath=$base_xapps
212   if [ "x$1" != "x" ]; then
213     urlpath="$urlpath/$1"
214     if rest DELETE $urlpath; then
215       # Currently appmgr returns an empty result if
216       # undeploy is succesfull. Don't reformat file if empty.
217       if [ -s $resultfile ]; then
218         json_reformat < $resultfile
219       else
220         echo "$1 undeployed"
221       fi
222     fi
223   else
224     echo Error: expected the name of xapp to undeploy
225     status=1
226   fi
227 }
228
229 do_status() {
230   local urlpath
231
232   urlpath=$base_xapps
233   if [ "x$1" != "x" ]; then
234     urlpath="$urlpath/$1"
235   fi
236   if [ "x$2" != "x" ]; then
237     urlpath="$urlpath/instances/$2"
238   fi
239   if rest GET $urlpath; then
240     json_reformat < $resultfile
241   fi
242 }
243
244 # This is a bit more complex. $1 is sub-command: list, add, delete, modify
245
246 # Validate the subscription data that follows a subscription add or modify
247 # subcommand. $1=URL, $2=eventType, $3=maxRetries, $4=retryTimer
248 # URL must look like URL, event type must be one of created deleted all,
249 # maxRetries and retryTimer must be non-negative numbers.
250 # If errors, sets variable status=1 and prints errors, else leaves
251 # status unchanged.
252 #
253 validate_subscription() {
254    if ! expr "$1" : "^http://.*" \| "$1" : "^https://.*" >/dev/null; then
255      echo "$myname: bad URL $1"
256      status=1
257    fi
258    if ! [ "$2" = created -o "$2" = deleted -o "$2" = all ]; then
259      echo "$myname: unrecognized event $2"
260      status=1
261    fi
262    if ! expr "$3" : "^[0-9][0-9]*$" >/dev/null; then
263      echo "$myname: invalid maximum retries count $3"
264      status=1   
265    fi
266    if ! expr "$4" : "^[0-9][0-9]*$" >/dev/null; then
267      echo "$myname: invalid retry time $4"
268      status=1   
269    fi
270 }
271
272 do_subscriptions() {
273   local urlpath
274   urlpath=$base_subs
275   case $1 in
276     (list)
277       if [ "x$2" != "x" ]; then
278         urlpath="$urlpath/$2"
279       fi
280       if rest GET $urlpath; then
281         json_reformat < $resultfile
282       else
283         status=1
284       fi
285     ;;
286     (add)
287       validate_subscription "$2" "$3" "$4" "$5"
288       if [ $status = 0 ]; then
289         if rest POST $urlpath \{\"targetUrl\":\"$2\",\"eventType\":\"$3\",\"maxRetries\":$4,\"retryTimer\":$5\} ; then
290           json_reformat < $resultfile
291         else
292           status=1
293         fi
294       fi
295     ;;
296     (delete|del)
297       if [ "x$2" != "x" ]; then
298         urlpath="$urlpath/$2"
299       else
300         echo "$myname: Subscription id required"
301         status=1
302       fi
303       if [ $status = 0 ]; then
304         if rest DELETE $urlpath; then
305           # Currently appmgr returns an empty result if
306           # delete is succesfull. Don't reformat file if empty.
307           if [ -s $resultfile ]; then
308             json_reformat < $resultfile
309           else
310             echo "Subscription $2 deleted"
311           fi
312         else
313           status=1
314         fi        
315       fi
316     ;;
317     (modify|mod)
318       if [ "x$2" != "x" ]; then
319         urlpath="$urlpath/$2"
320       else
321         echo "$myname: Subscription id required"
322         status=1
323       fi
324       if [ $status = 0 ]; then
325         validate_subscription "$3" "$4" "$5" "$6"
326         if [ $status = 0 ]; then
327           if rest PUT $urlpath \{\"targetUrl\":\"$3\",\"eventType\":\"$4\",\"maxRetries\":$5,\"retryTimer\":$6\} ; then
328             json_reformat < $resultfile
329           else
330             status=1
331           fi
332         fi
333       fi
334     ;;
335     (*)
336       echo "$myname: unrecognized subscriptions subcommand $1"
337       status=1
338   esac
339 }
340
341 do_config() {
342   local urlpath
343   urlpath=$base_config
344   case $1 in
345     (get|list)
346       if [ "x$2" != "x" ]; then
347         urlpath="$urlpath/$2"
348       fi
349       if rest GET $urlpath; then
350         json_reformat < $resultfile
351       else
352         status=1
353       fi
354     ;;
355     (add|update)
356       if rest POST $urlpath "@$2" ; then
357         cat $resultfile
358       else
359         status=1
360     fi
361     ;;
362     (del|delete|remove|rem)
363       if rest DELETE $urlpath "@$2" ; then
364         cat $resultfile
365       else
366         status=1
367     fi
368     ;;
369     (*)
370       echo "$myname: unrecognized config subcommand $1"
371       status=1
372   esac
373 }
374
375 case $cmd in
376   (deploy)
377     do_deploy "$2"
378     ;;
379   (undeploy)
380     do_undeploy "$2"
381     ;;
382   (status)
383     do_status "$2" "$3"
384     ;;
385   (subscriptions)
386     do_subscriptions "$2" "$3" "$4" "$5" "$6" "$7"
387     ;;
388   (config)
389     do_config "$2" "$3"
390     ;;
391   (health)
392     if rest GET $base_health ; then
393       echo OK
394     else
395       echo NOT OK
396     fi
397     ;;
398 esac
399 remove_temps
400 exit $status
401
402 # An Emacs hack to set the indentation style of this file
403 # Local Variables:
404 # sh-indentation:2
405 # End: