-validate_subscription() {
- if ! expr "$1" : "^http://.*" \| "$1" : "^https://.*" >/dev/null; then
- echo "$myname: bad URL $1"
- status=1
- fi
- if ! [ "$2" = created -o "$2" = deleted -o "$2" = all ]; then
- echo "$myname: unrecognized event $2"
- status=1
- fi
- if ! expr "$3" : "^[0-9][0-9]*$" >/dev/null; then
- echo "$myname: invalid maximum retries count $3"
- status=1
- fi
- if ! expr "$4" : "^[0-9][0-9]*$" >/dev/null; then
- echo "$myname: invalid retry time $4"
- status=1
- fi
-}
-
-do_subscriptions() {
- local urlpath
- urlpath=$base_subs
- case $1 in
- (list)
- if [ "x$2" != "x" ]; then
- urlpath="$urlpath/$2"
- fi
- if rest GET $urlpath; then
- json_reformat < $resultfile
- else
- status=1
- fi
- ;;
- (add)
- validate_subscription "$2" "$3" "$4" "$5"
- if [ $status = 0 ]; then
- if rest POST $urlpath \{\"targetUrl\":\"$2\",\"eventType\":\"$3\",\"maxRetries\":$4,\"retryTimer\":$5\} ; then
- json_reformat < $resultfile
- else
- status=1
- fi
- fi
- ;;
- (delete|del)
- if [ "x$2" != "x" ]; then
- urlpath="$urlpath/$2"
- else
- echo "$myname: Subscription id required"
- status=1
- fi
- if [ $status = 0 ]; then
- if rest DELETE $urlpath; then
- # Currently appmgr returns an empty result if
- # delete is succesfull. Don't reformat file if empty.
- if [ -s $resultfile ]; then
- json_reformat < $resultfile
- else
- echo "Subscription $2 deleted"
- fi
- else
- status=1
- fi
- fi
- ;;
- (modify|mod)
- if [ "x$2" != "x" ]; then
- urlpath="$urlpath/$2"
- else
- echo "$myname: Subscription id required"
- status=1
- fi
- if [ $status = 0 ]; then
- validate_subscription "$3" "$4" "$5" "$6"
- if [ $status = 0 ]; then
- if rest PUT $urlpath \{\"targetUrl\":\"$3\",\"eventType\":\"$4\",\"maxRetries\":$5,\"retryTimer\":$6\} ; then
- json_reformat < $resultfile
- else
- status=1
- fi
- fi
- fi
- ;;
- (*)
- echo "$myname: unrecognized subscriptions subcommand $1"
- status=1
- esac
-}
-
-do_config() {
- local urlpath
- urlpath=$base_config
- case $1 in
- (get|list)
- if [ "x$2" != "x" ]; then
- urlpath="$urlpath/$2"
- fi
- if rest GET $urlpath; then
- json_reformat < $resultfile
- else
- status=1
- fi
- ;;
- (add|update)
- if rest POST $urlpath "@$2" ; then
- cat $resultfile
- else
- status=1
- fi
- ;;
- (del|delete|remove|rem)
- if rest DELETE $urlpath "@$2" ; then
- cat $resultfile
- else
- status=1
- fi
- ;;
- (*)
- echo "$myname: unrecognized config subcommand $1"
- status=1
- esac
-}
-
-case $cmd in
- (deploy)
- do_deploy "$2"
- ;;
- (undeploy)
- do_undeploy "$2"
- ;;
- (status)
- do_status "$2" "$3"
- ;;
- (subscriptions)
- do_subscriptions "$2" "$3" "$4" "$5" "$6" "$7"
- ;;
- (config)
- do_config "$2" "$3"
- ;;
- (health)
- if rest GET $base_health ; then
- echo OK
- else
- echo NOT OK
- fi
- ;;
-esac
-remove_temps
-exit $status
-
-# An Emacs hack to set the indentation style of this file
-# Local Variables:
-# sh-indentation:2
-# End:
+sub validate_subscription(@) {
+ # Using the API parameter names
+ my $targetUrl = $_[0] || "";
+ my $eventType = $_[1] || "";
+ my $maxRetries = $_[2] || "";
+ my $retryTimer = $_[3] || "";
+ my $retval = 1;
+
+ if (! ($targetUrl =~ /^http:\/\/.*/ or $targetUrl =~ /^https:\/\/.*/)) {
+ print "$myname: bad URL $targetUrl\n";
+ $retval = 0;
+ }
+ if ($eventType ne "created" and $eventType ne "deleted" and
+ $eventType ne "all") {
+ print "$myname: unrecognized event $eventType\n";
+ $retval = 0;
+ }
+ if (! ($maxRetries =~ /^[0-9]+$/)) {
+ print "$myname: invalid maximum retries count $maxRetries\n";
+ $retval = 0;
+ }
+ if (! ($retryTimer =~ /^[0-9]+$/)) {
+ print "$myname: invalid retry time $retryTimer\n";
+ $retval = 0;
+ }
+ return $retval;
+}
+
+# Format a subscriptionRequest JSON object
+
+sub make_subscriptionRequest(@) {
+ my $targetUrl = $_[0];
+ my $eventType = $_[1];
+ my $maxRetries = $_[2];
+ my $retryTimer = $_[3];
+ return "{\"Data\": {\"TargetUrl\":\"$targetUrl\",\"EventType\":\"$eventType\",\"MaxRetries\":$maxRetries,\"RetryTimer\":$retryTimer}}";
+}
+
+# Subscriptions:
+# $1 is sub-command: list, add, delete, modify
+
+sub do_subscriptions(@) {
+ my $subcommand = $_[0] || "";
+ shift;
+
+ my %subcommands = (
+ "list" => \&do_subscription_list,
+ "add" => \&do_subscription_add,
+ "delete" => \&do_subscription_delete,
+ "del" => \&do_subscription_delete,
+ "modify" => \&do_subscription_modify,
+ "mod" => \&do_subscription_modify
+ );
+ if (exists $subcommands{$subcommand}) {
+ $subcommands{$subcommand}(@_);
+ }
+ else {
+ print "$myname: unrecognized subscriptions subcommand $subcommand\n";
+ helphint();
+ $status=1
+ }
+}
+
+# list: With empty parameter, list all, else the parameter is
+# a subscriptionId
+
+sub do_subscription_list(@) {
+ my $urlpath=$base_subs;
+ my $subscriptionId = $_[0] || "";
+ if ($subscriptionId ne "") {
+ $urlpath = "$urlpath/$subscriptionId";
+ }
+ make_temps();
+ if (rest("GET", $urlpath)) {
+ if ($http_code eq "200") {
+ print_json $resultfile;
+ $status = 0;
+ }
+ else {
+ my $error;
+ if ($http_code eq "400") {
+ $error = "INVALID SUBSCRIPTION ID $subscriptionId";
+ }
+ elsif ($http_code eq "404") {
+ $error = "SUBSCRIPTION $subscriptionId NOT FOUND";
+ }
+ elsif ($http_code eq "500") {
+ $error = "INTERNAL ERROR";
+ }
+ else {
+ $error = "UNKNOWN STATUS $http_code";
+ }
+ print "$error\n";
+ $status = 1;
+ }
+ }
+ else {
+ $status=1;
+ }
+ remove_temps();
+}
+
+sub do_subscription_add(@) {
+ my $urlpath=$base_subs;
+
+ if (validate_subscription(@_)) {
+ make_temps();
+ if (rest("POST", $urlpath, make_subscriptionRequest(@_))) {
+ if ($http_code eq "201") {
+ print_json $resultfile;
+ $status = 0;
+ }
+ else {
+ my $error;
+ if ($http_code eq "400") {
+ $error = "INVALID INPUT";
+ }
+ elsif ($http_code eq "500") {
+ $error = "INTERNAL ERROR";
+ }
+ else {
+ $error = "UNKNOWN STATUS $http_code";
+ }
+ print "$error\n";
+ $status = 1;
+ }
+ }
+ else {
+ $status=1;
+ }
+ remove_temps();
+ }
+ else {
+ $status = 1;
+ }
+}
+
+sub do_subscription_delete(@) {
+ my $urlpath=$base_subs;
+ my $subscriptionId = $_[0] || "";
+ if ($subscriptionId ne "") {
+ $urlpath = "$urlpath/$subscriptionId";
+ }
+ else {
+ print "$myname: delete: Subscription id required\n";
+ $status=1;
+ return;
+ }
+ make_temps();
+ if (rest("DELETE", $urlpath)) {
+ if ($http_code eq "204") {
+ print "SUBSCRIPTION $subscriptionId DELETED\n";
+ $status = 0;
+ }
+ else {
+ my $error;
+ if ($http_code eq "400") {
+ $error = "INVALID SUBSCRIPTION ID $subscriptionId";
+ }
+ elsif ($http_code eq "500") {
+ $error = "INTERNAL ERROR";
+ }
+ else {
+ $error = "UNKNOWN STATUS $http_code";
+ }
+ print "$error\n";
+ $status = 1;
+ }
+ }
+ else {
+ $status = 1;
+ }
+ remove_temps();
+}
+
+sub do_subscription_modify(@) {
+ my $urlpath=$base_subs;
+ if (defined $_[0]) {
+ $urlpath = "$urlpath/$_[0]";
+ }
+ else {
+ print "$myname: modify: Subscription id required\n";
+ $status=1;
+ return;
+ }
+ shift;
+ if (validate_subscription(@_)) {
+ make_temps();
+ if (rest("PUT", $urlpath, make_subscriptionRequest(@_))) {
+ if ($http_code eq "200") {
+ print_json $resultfile;
+ $status = 0;
+ }
+ else {
+ my $error;
+ if ($http_code eq "400") {
+ $error = "INVALID INPUT";
+ }
+ elsif ($http_code eq "500") {
+ $error = "INTERNAL ERROR";
+ }
+ else {
+ $error = "UNKNOWN STATUS $http_code";
+ }
+ print "$error\n";
+ $status = 1;
+ }
+ }
+ else {
+ $status=1;
+ }
+ remove_temps();
+ }
+ else {
+ $status = 1;
+ }
+}
+
+sub do_health(@) {
+ my $urlpath=$base_health;
+ my $check = $_[0] || "";
+ # API now defines two types of checks, either of
+ # which must be specified.
+ if ($check ne "alive" and $check ne "ready") {
+ print "$myname: health check type required (alive or ready)\n";
+ $status=1;
+ return;
+ }
+ $urlpath = "$urlpath/$check";
+ make_temps();
+ if (rest("GET", $urlpath)) {
+ my $res;
+ if ($check eq "alive") {
+ # If GET succeeds at all, the xapp manager is alive, no
+ # need to check the HTTP code.
+ $res = "ALIVE";
+ }
+ else {
+ if ($http_code eq "200") {
+ $res = "READY";
+ }
+ elsif ($http_code eq "503") {
+ $res = "NOT READY";
+ }
+ elsif ($http_code eq "500") {
+ $res = "INTERNAL ERROR";
+ }
+ else {
+ $res = "UNKNOWN STATUS $http_code";
+ }
+ }
+ print "$res\n";
+ }
+ else {
+ $status = 1;
+ print "$myname: health check failed to contact appmgr\n";
+ }
+ remove_temps();
+}
+
+sub do_config(@) {
+ my $subcommand = $_[0] || "";
+ shift;
+
+ my %subcommands = (
+ "list" => \&do_config_list,
+ "add" => \&do_config_add,
+ "delete" => \&do_config_delete,
+ "del" => \&do_config_delete,
+ "modify" => \&do_config_modify,
+ "mod" => \&do_config_modify
+ );
+ if (exists $subcommands{$subcommand}) {
+ $subcommands{$subcommand}(@_);
+ }
+ else {
+ print "$myname: unrecognized config subcommand $subcommand\n";
+ helphint();
+ $status=1
+ }
+}
+
+sub do_config_list(@) {
+ if (defined $_[0]) {
+ print "$myname: \"config list\" has no parameters\n";
+ $status = 1;
+ return;
+ }
+ make_temps();
+ if (rest("GET", $base_config)) {
+ if ($http_code eq "200") {
+ print_json $resultfile;
+ $status = 0;
+ }
+ else {
+ my $error;
+ if ($http_code eq "500") {
+ $error = "INTERNAL ERROR";
+ }
+ else {
+ $error = "UNKNOWN STATUS $http_code";
+ }
+ print "$error\n";
+ $status = 1;
+ }
+ }
+ else {
+ $status=1;
+ }
+ remove_temps();
+}
+
+# validate_config() checks configuration commmand line.
+# "config add" and "config modify" expect either single parameter which
+# must be a JSON file that contains the whole thing to send (see API),
+# or 5 parameters, where the first three are
+# $_[0] = name
+# $_[1] = configName (name of the configMap)
+# $_[2] = namespace
+# Followed by two file names:
+# $_[3] = file containing configSchema
+# $_[4] = file containing data for configMap
+# Giving the last two literally on the command line does not make much sense,
+# since they are arbitrary JSON data.
+# On success, returns parameter count (1 or 5), depending on which kind of
+# command line found.
+# 0 if errors.
+
+# Check only the 3 names at the beginning of config add/modify/delete
+sub validate_config_names(@) {
+ my $retval = 1;
+ # Names in the Kubernetes world consist of lowercase alphanumerics
+ # and - and . as specified in
+ # https://kubernetes.io/docs/concepts/overview/working-with-objects/name
+ for (my $idx = 0; $idx <= 2; ++$idx) {
+ if (! ($_[$idx] =~ /^[a-z][-a-z0-9.]*$/)) {
+ print "$myname: invalid characters in name $_[$idx]\n";
+ $retval = 0;
+ }
+ }
+ return $retval;
+}
+
+sub validate_config(@) {
+ my $retval = 1;
+ print "validate_config args @_\n";
+ if ($#_ == 0) {
+ if (! -r $_[0]) {
+ print "$myname: config file $_[0] cannot be read: $!\n";
+ $retval = 0;
+ }
+ }
+ elsif ($#_ == 4) {
+ $retval = 5;
+ if (! validate_config_names(@_)) {
+ $retval = 0;
+ }
+ for (my $idx = 3; $idx <= 4; ++$idx) {
+ if (! -r $_[$idx]) {
+ print "$myname: cannot read file $_[$idx]\n";
+ $retval = 0;
+ }
+ }
+ }
+ else {
+ print "$myname: config add: 1 or 5 parameter expected\n";
+ $retval = 0;
+ }
+ return $retval;
+}
+
+# Generate JSON for the xAppConfig element (see API).
+
+sub make_xAppConfigInfo($$$) {
+ return "{\"xAppName\":\"$_[0]\",\"configMapName\":\"$_[1]\",\"namespace\":\"$_[2]\"}";
+}
+
+sub make_xAppConfig(@) {
+ my $retval = "{\"xAppConfigInfo\":" . make_xAppConfigInfo($_[0],$_[1],$_[2]);
+ my $fh;
+ open($fh, "<", $_[3]) or die "failed to open $_[3]";
+ my @obj = <$fh>;
+ close($fh);
+ $retval = $retval . ",\"configSchema\":" . join("", @obj);
+ open($fh, "<", $_[4]) or die "failed to open $_[4]";
+ @obj = <$fh>;
+ close($fh);
+ $retval = $retval . ",\"configMap\":" . join("", @obj) . "}";
+}
+
+sub do_config_add(@) {
+ my $paramCount;
+
+ $paramCount = validate_config(@_);
+ if ($paramCount > 0) {
+ my $xAppConfig;
+ if ($paramCount == 1) {
+ $xAppConfig = "\@$_[0]";
+ }
+ else {
+ $xAppConfig = make_xAppConfig(@_);
+ }
+ make_temps();
+ if (rest("POST", $base_config, $xAppConfig)) {
+ if ($http_code eq "201") {
+ print_json $resultfile;
+ $status = 0;
+ }
+ elsif ($http_code eq "422") { # Validation failed, details in result
+ print_json $resultfile;
+ $status = 1;
+ }
+ else {
+ my $error;
+ if ($http_code eq "400") {
+ $error = "INVALID INPUT";
+ }
+ elsif ($http_code eq "500") {
+ $error = "INTERNAL ERROR";
+ }
+ else {
+ $error = "UNKNOWN STATUS $http_code";
+ }
+ print "$error\n";
+ $status = 1;
+ }
+ }
+ else {
+ $status=1;
+ }
+ remove_temps();
+ }
+ else {
+ $status = 1;
+ }
+}
+
+sub do_config_modify(@) {
+ my $paramCount;
+
+ $paramCount = validate_config(@_);
+ if ($paramCount > 0) {
+ my $xAppConfig;
+ if ($paramCount == 1) {
+ $xAppConfig = "\@$_[0]";
+ }
+ else {
+ $xAppConfig = make_xAppConfig(@_);
+ }
+ make_temps();
+ if (rest("PUT", $base_config, $xAppConfig)) {
+ if ($http_code eq "200") {
+ print_json $resultfile;
+ $status = 0;
+ }
+ elsif ($http_code eq "422") { # Validation failed, details in result
+ print_json $resultfile;
+ $status = 1;
+ }
+ else {
+ my $error;
+ if ($http_code eq "400") {
+ $error = "INVALID INPUT";
+ }
+ elsif ($http_code eq "500") {
+ $error = "INTERNAL ERROR";
+ }
+ else {
+ $error = "UNKNOWN STATUS $http_code";
+ }
+ print "$error\n";
+ $status = 1;
+ }
+ }
+ else {
+ $status=1;
+ }
+ remove_temps();
+ }
+ else {
+ $status = 1;
+ }
+}
+
+# In config delete, allow either 1 parameter naming a file that contains
+# a JSON xAppConfigInfo object, or 3 parameters giving the
+# components (xAppName, configMapName, namespace), same as
+# in add and modify operations.
+
+sub do_config_delete(@) {
+ my $xAppConfigInfo = "";
+
+ if ($#_ != 0 and $#_ != 2) {
+ print "$myname: wrong number of parameters for config delete\n";
+ $status = 1;
+ }
+ elsif ($#_ == 0) {
+ if (-r $_[0]) {
+ $xAppConfigInfo = "\@$_[0]";
+ }
+ else {
+ print "$myname: config file $_[0] cannot be read: $!\n";
+ $status = 1;
+ }
+ }
+ elsif (($#_ == 2) && validate_config_names(@_)) {
+ $xAppConfigInfo = make_xAppConfigInfo($_[0],$_[1],$_[2]);
+ }
+ else {
+ print "$myname: bad parameters for config delete\n";
+ $status = 1;
+ }
+ if ($xAppConfigInfo ne "") {
+ make_temps();
+ if (rest("DELETE", $base_config, $xAppConfigInfo)) {
+ if ($http_code eq "204") {
+ print "SUCCESFUL DELETION OF CONFIG\n";
+ $status = 0;
+ }
+ else {
+ my $error;
+ if ($http_code eq "400") {
+ $error = "INVALID PARAMETERS SUPPLIED";
+ }
+ elsif ($http_code eq "500") {
+ $error = "INTERNAL ERROR";
+ }
+ else {
+ $error = "UNKNOWN STATUS $http_code";
+ }
+ print "$error\n";
+ $status = 1;
+ }
+ }
+ else {
+ $status=1;
+ }
+ remove_temps();
+ }
+}