Abukar Mohamed | 8504f6a | 2019-04-03 11:07:48 +0000 | [diff] [blame^] | 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 | (help) |
| 129 | usage |
| 130 | exit 0 |
| 131 | ;; |
| 132 | (*) |
| 133 | if [ "x$1" = "x" ]; then |
| 134 | echo "$myname: Missing command" |
| 135 | else |
| 136 | echo "$myname: Unrecognized command $1" |
| 137 | fi |
| 138 | usage |
| 139 | exit 1 |
| 140 | ;; |
| 141 | esac |
| 142 | |
| 143 | if [ $verbose = 1 ]; then |
| 144 | echo "Command $cmd params=$2" |
| 145 | fi |
| 146 | |
| 147 | errfile=`mktemp /tmp/appmgr_e.XXXXXXXXXX` |
| 148 | resultfile=`mktemp /tmp/appmgr_r.XXXXXXXXXX` |
| 149 | # Variable status used for the return value of the whole script. |
| 150 | status=0 |
| 151 | |
| 152 | # Helper for command execution: |
| 153 | # Do a rest call with "curl": $1 = method, $2 = path (without host and port |
| 154 | # which come from variables), $3 data to POST if needed |
| 155 | # returns 0 if OK, and any returned data is in $resultfile |
| 156 | # else 1, and error message from curl is in $errfile, which is printed |
| 157 | # before returning the 1. |
| 158 | # Also sets $status to the return value. |
| 159 | # |
| 160 | # On curl options: --silent --show-error disables progress bar, but allows |
| 161 | # error messages. --connect-timeout 20 limits waiting for connection to |
| 162 | # 20 seconds. In practice connection will succeed almost immediately, |
| 163 | # or in the case of wrong address not at all. |
| 164 | # |
| 165 | rest() { |
| 166 | local data |
| 167 | if [ "x$3" != "x" ]; then |
| 168 | data="--data $3" |
| 169 | fi |
| 170 | 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 |
| 171 | status=0 |
| 172 | else |
| 173 | cat $errfile |
| 174 | status=1 |
| 175 | fi |
| 176 | return $status |
| 177 | } |
| 178 | |
| 179 | remove_temps () { |
| 180 | rm -f $errfile $resultfile |
| 181 | } |
| 182 | |
| 183 | # Execute command ($cmd guaranteed to be valid) |
| 184 | # Assumes the API currently implemented. |
| 185 | # Functions for each command below (except health which is so simple). |
| 186 | |
| 187 | base=/ric/v1 |
| 188 | base_xapps=$base/xapps |
| 189 | base_health=$base/health |
| 190 | base_subs=$base/subscriptions |
| 191 | |
| 192 | do_deploy() { |
| 193 | if [ "x$1" != "x" ]; then |
| 194 | if rest POST $base_xapps \{\"name\":\"$1\"\} ; then |
| 195 | json_reformat < $resultfile |
| 196 | fi |
| 197 | else |
| 198 | echo Error: expected the name of xapp to deploy |
| 199 | status=1 |
| 200 | fi |
| 201 | } |
| 202 | |
| 203 | do_undeploy() { |
| 204 | local urlpath |
| 205 | |
| 206 | urlpath=$base_xapps |
| 207 | if [ "x$1" != "x" ]; then |
| 208 | urlpath="$urlpath/$1" |
| 209 | if rest DELETE $urlpath; then |
| 210 | # Currently xapp_manager returns an empty result if |
| 211 | # undeploy is succesfull. Don't reformat file if empty. |
| 212 | if [ -s $resultfile ]; then |
| 213 | json_reformat < $resultfile |
| 214 | else |
| 215 | echo "$1 undeployed" |
| 216 | fi |
| 217 | fi |
| 218 | else |
| 219 | echo Error: expected the name of xapp to undeploy |
| 220 | status=1 |
| 221 | fi |
| 222 | } |
| 223 | |
| 224 | do_status() { |
| 225 | local urlpath |
| 226 | |
| 227 | urlpath=$base_xapps |
| 228 | if [ "x$1" != "x" ]; then |
| 229 | urlpath="$urlpath/$1" |
| 230 | fi |
| 231 | if [ "x$2" != "x" ]; then |
| 232 | urlpath="$urlpath/instances/$2" |
| 233 | fi |
| 234 | if rest GET $urlpath; then |
| 235 | json_reformat < $resultfile |
| 236 | fi |
| 237 | } |
| 238 | |
| 239 | # This is a bit more complex. $1 is sub-command: list, add, delete, modify |
| 240 | |
| 241 | # Validate the subscription data that follows a subscription add or modify |
| 242 | # subcommand. $1=URL, $2=eventType, $3=maxRetries, $4=retryTimer |
| 243 | # URL must look like URL, event type must be one of created deleted all, |
| 244 | # maxRetries and retryTimer must be non-negative numbers. |
| 245 | # If errors, sets variable status=1 and prints errors, else leaves |
| 246 | # status unchanged. |
| 247 | # |
| 248 | validate_subscription() { |
| 249 | if ! expr "$1" : "^http://.*" \| "$1" : "^https://.*" >/dev/null; then |
| 250 | echo "$myname: bad URL $1" |
| 251 | status=1 |
| 252 | fi |
| 253 | if ! [ "$2" = created -o "$2" = deleted -o "$2" = all ]; then |
| 254 | echo "$myname: unrecognized event $2" |
| 255 | status=1 |
| 256 | fi |
| 257 | if ! expr "$3" : "^[0-9][0-9]*$" >/dev/null; then |
| 258 | echo "$myname: invalid maximum retries count $3" |
| 259 | status=1 |
| 260 | fi |
| 261 | if ! expr "$4" : "^[0-9][0-9]*$" >/dev/null; then |
| 262 | echo "$myname: invalid retry time $4" |
| 263 | status=1 |
| 264 | fi |
| 265 | } |
| 266 | |
| 267 | do_subscriptions() { |
| 268 | local urlpath |
| 269 | urlpath=$base_subs |
| 270 | case $1 in |
| 271 | (list) |
| 272 | if [ "x$2" != "x" ]; then |
| 273 | urlpath="$urlpath/$2" |
| 274 | fi |
| 275 | if rest GET $urlpath; then |
| 276 | json_reformat < $resultfile |
| 277 | else |
| 278 | status=1 |
| 279 | fi |
| 280 | ;; |
| 281 | (add) |
| 282 | validate_subscription "$2" "$3" "$4" "$5" |
| 283 | if [ $status = 0 ]; then |
| 284 | if rest POST $urlpath \{\"targetUrl\":\"$2\",\"eventType\":\"$3\",\"maxRetries\":$4,\"retryTimer\":$5\} ; then |
| 285 | json_reformat < $resultfile |
| 286 | else |
| 287 | status=1 |
| 288 | fi |
| 289 | fi |
| 290 | ;; |
| 291 | (delete|del) |
| 292 | if [ "x$2" != "x" ]; then |
| 293 | urlpath="$urlpath/$2" |
| 294 | else |
| 295 | echo "$myname: Subscription id required" |
| 296 | status=1 |
| 297 | fi |
| 298 | if [ $status = 0 ]; then |
| 299 | if rest DELETE $urlpath; then |
| 300 | # Currently xapp_manager returns an empty result if |
| 301 | # delete is succesfull. Don't reformat file if empty. |
| 302 | if [ -s $resultfile ]; then |
| 303 | json_reformat < $resultfile |
| 304 | else |
| 305 | echo "Subscription $2 deleted" |
| 306 | fi |
| 307 | else |
| 308 | status=1 |
| 309 | fi |
| 310 | fi |
| 311 | ;; |
| 312 | (modify|mod) |
| 313 | if [ "x$2" != "x" ]; then |
| 314 | urlpath="$urlpath/$2" |
| 315 | else |
| 316 | echo "$myname: Subscription id required" |
| 317 | status=1 |
| 318 | fi |
| 319 | if [ $status = 0 ]; then |
| 320 | validate_subscription "$3" "$4" "$5" "$6" |
| 321 | if [ $status = 0 ]; then |
| 322 | if rest PUT $urlpath \{\"targetUrl\":\"$3\",\"eventType\":\"$4\",\"maxRetries\":$5,\"retryTimer\":$6\} ; then |
| 323 | json_reformat < $resultfile |
| 324 | else |
| 325 | status=1 |
| 326 | fi |
| 327 | fi |
| 328 | fi |
| 329 | ;; |
| 330 | (*) |
| 331 | echo "$myname: unrecognized subscriptions subcommand $1" |
| 332 | status=1 |
| 333 | esac |
| 334 | } |
| 335 | |
| 336 | case $cmd in |
| 337 | (deploy) |
| 338 | do_deploy "$2" |
| 339 | ;; |
| 340 | (undeploy) |
| 341 | do_undeploy "$2" |
| 342 | ;; |
| 343 | (status) |
| 344 | do_status "$2" "$3" |
| 345 | ;; |
| 346 | (subscriptions) |
| 347 | do_subscriptions "$2" "$3" "$4" "$5" "$6" "$7" |
| 348 | ;; |
| 349 | (health) |
| 350 | if rest GET $base_health ; then |
| 351 | echo OK |
| 352 | else |
| 353 | echo NOT OK |
| 354 | fi |
| 355 | ;; |
| 356 | esac |
| 357 | remove_temps |
| 358 | exit $status |
| 359 | |
| 360 | # An Emacs hack to set the indentation style of this file |
| 361 | # Local Variables: |
| 362 | # sh-indentation:2 |
| 363 | # End: |