blob: 4ea9c3f8f37d64383a3212fd4b090169ada5e08b [file] [log] [blame]
#!/usr/bin/perl -w
#
# Copyright (c) 2019 AT&T Intellectual Property.
# Copyright (c) 2019 Nokia.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# See the License for the specific language governing permissions and
# limitations under the License.
#
#############################
# Simple cli for xapp manager
#
# In addition to standard shell tools, requires basic Perl installation
# (Ubuntu package "perl-base", installed by default), packages "curl" and
# "yajl-tools" (the second provides json_reformat on Ubuntu; on Red Hat-style
# distributions install "yajl" instead).
#
use strict;
use Getopt::Long;
use Fcntl;
my $myname="appmgrcli";
sub usage {
print <<"EOF1";
usage: $myname [-h host] [-p port] [-v] [-c curlprog] command params...
- command is deploy, undeploy, status, subscriptions, health, config, help
- (abbreviations dep, undep, stat, subs, heal allowed)
- Parameters of the commands that may have parameters:
-- deploy: name of the xapp to deploy
---- Deployment parameters come from the Help chart but the following can be
---- overridden by option with the same name (for example --configName=cname):
----- helmVersion ReleaseName namespace podHost (host of pods).
-- undeploy: name of the xapp to undeploy
-- status:
---- No parameters: Lists information about all deployed xapps
---- xapp name as parameter: Prints information about the given xapp
---- xapp name and instance: Lists information about the given instance only
-- subscriptions is followed by sub-command list, add, delete, or modify
--- (abbreviations del and mod for delete and modify are allowed):
---- list without parameters lists all subscriptions
---- list with subscription id prints that subscription
---- add URL eventType maxRetry retryTimer
------- URL is the URL to notify
------- eventType one of created,deleted,all
------- maxRetry and retryTimer are positive decimal numbers
---- modify id URL eventType maxRetry retryTimer
------- id is the subscription id (find out with the list command)
--------the rest of the parameters are like in add
---- delete id
------- id is the subscription id to delete (find out with the list command)
-- config is followed by sub-command list, add, delete, or modify
--- (abbreviations del and mod for delete and modify are allowed):
---- list (no pars)
------ lists the configuration of all xapps
---- add jsonfile
------ Creates xapp configuration. the jsonfile must contain all data (see API)
---- add name configName namespace configSchemaFile configDataFile
------ Creates xapp configuration, but unlike in the 1-parameter form,
------ Xapp name, config map name and namespace are separate parameters.
------ The other data come from JSON files.
---- modify
------ Modifies existing configuration. Same parameters (1 or 5) as in add.
---- delete name configName namespace
------ Deletes the configuration identified by the parameters.
--------------------------------------------------------------
- Default values for host and port can be set in environment
- variables APPMGR_HOST and APPMGR_PORT
- Option -v sets verbose mode.
- Option -c overrides the used curl program name ("curl" by default).
- Exit code is 0 for success, 1 for any kind of failure.
EOF1
exit 0;
}
sub helphint {
print "run $myname help (or --help) for instructions\n";
}
# Defaults
my $host="localhost";
my $port=8080;
my $verbose=0;
my $showhelp = 0;
# API URLs
my $base="/ric/v1";
my $base_xapps="$base/xapps";
my $base_health="$base/health";
my $base_subs="$base/subscriptions";
my $base_config="$base/config";
# Check for environment override
if (exists $ENV{"APPMGR_HOST"}) {
$host=$ENV{"APPMGR_HOST"};
}
if (exists $ENV{"APPMGR_PORT"}) {
$port=$ENV{"APPMGR_PORT"};
}
# Overrides for some deploy parameters
my $configName = "";
my $namespace = "ricxapp";
# Check for environment override
if (exists $ENV{"XAPP_NAMESPACE"}) {
$namespace=$ENV{"XAPP_NAMESPACE"};
}
my $releaseName = "";
my $helmVersion = "0.0.1";
my $overrideFile = "";
my $podHost = "";
# The curl command can be overridden for testing with a dummy.
my $curl = "curl";
Getopt::Long::Configure("no_auto_abbrev", "permute");
if (! GetOptions("h=s" => \$host,
"p=i" => \$port,
"c=s" => \$curl,
"ConfigName=s" => \$configName,
"Namespace=s" => \$namespace,
"ReleaseName=s" => \$releaseName,
"HelmVersion=s" => \$helmVersion,
"OverrideFile=s" => \$overrideFile,
"podHost=s" => \$podHost,
"help" => \$showhelp,
"v" => \$verbose)) {
print "$myname: Error in options\n";
helphint();
exit 1;
}
if ($showhelp) {
usage();
exit 0;
}
if ($verbose) {
print "host = $host\n";
print "port = $port\n";
print "ConfigName = $configName\n";
print "Namespace = $namespace\n";
print "ReleaseName = $releaseName\n";
print "HelmVersion = $helmVersion\n";
print "OverrideFile = $overrideFile\n";
print "podHost = $podHost\n";
for (my $idx = 0; $idx <= $#ARGV; ++$idx) {
print "\$ARGV[$idx] = $ARGV[$idx]\n";
}
}
# Verify command and call handler function
my %commands = (
"deploy" => \&do_deploy,
"dep" => \&do_deploy,
"undeploy" => \&do_undeploy,
"undep" => \&do_undeploy,
"status" => \&do_status,
"stat" => \&do_status,
"subscriptions" => \&do_subscriptions,
"subs" => \&do_subscriptions,
"health" => \&do_health,
"heal" => \&do_health,
"config" => \&do_config,
"help" => \&usage
);
if ($#ARGV < 0) {
print "$myname: Missing command\n";
helphint();
exit 1;
}
# Variable status used for the return value of the whole script.
my $status = 0;
my $command = $ARGV[0];
shift;
if (exists $commands{$command}) {
# Call the handler function with the rest of the command line
$commands{$command}(@ARGV);
exit $status; # Default exit. A handler can exit also if more convenient
}
print "$myname: Unrecognised command $command\n";
helphint();
exit 1;
my $errfile;
my $resultfile;
sub make_temp_name($) {
my $tmpsuffix = "${$}${^T}";
return "$_[0].$tmpsuffix";
}
sub make_temps {
$errfile = make_temp_name("/tmp/appmgr_e");
$resultfile = make_temp_name("/tmp/appmgr_r");
}
sub remove_temps {
unlink ($errfile, $resultfile);
}
sub print_file($$) {
my $outputhandle = $_[0];
my $filename = $_[1];
my $buffer;
my $inhandle;
if (!open($inhandle, "<", $filename)) {
print $outputhandle "$myname print_file: cannot open $filename: $!\n";
return;
}
while (read($inhandle, $buffer, 4000) > 0) {
print $outputhandle $buffer;
}
close($inhandle);
}
# The HTTP protocol result code, filled in by rest().
my $http_code = "";
# Helper: Given a curl output file, extract the number from ##code line.
# return ERROR if file cannot be opened, or "" if no code found.
sub find_http_code($) {
my ($fh, $line, $code);
open($fh, "<", $_[0]) or return "ERROR";
while ($line = <$fh>) {
if ($line =~ /^##([0-9]+)/) {
return $1;
}
}
return "";
}
# Helper for command execution:
# Do a rest call with "curl": $1 = method, $2 = path (without host and port
# which come from variables), $3 data to POST if needed
# returns true (1) if OK, and any returned data is in $resultfile
# else 0, and error message from curl is in $errfile, which is printed
# before returning the 0.
#
# On curl options: --silent --show-error disables progress bar, but allows
# error messages. --connect-timeout 20 limits waiting for connection to
# 20 seconds. In practice connection will succeed almost immediately,
# or in the case of wrong address not at all.
# To get the http code, using -w with format. The result comes at the end
# of the output, so "decorating" it for easier filtering.
# The code is put to global $http_code.
#
sub rest($$_) {
my $method = $_[0];
my $path = $_[1];
my $data = $_[2] || "";
my $retval = 1;
my $http_status_file = make_temp_name("/tmp/appmgr_h");
# This redirects stderr (fd 2) to $errfile, but saving normal stderr
# so that if can be restored.
open(OLDERR, ">&", \*STDERR) or die "Can't dup STDERR: $!";
open(ERRFILE, ">", $errfile) or die "open errorfile failed";
open(STDERR, ">&", \*ERRFILE) or die "Can't dup ERRFILE: $!";
# This redirects stdout (fd 1) to $http_status_file, but saving original
# so that if can be restored.
open(OLDSTDOUT, ">&", \*STDOUT) or die "Can't dup STDOUT: $!";
open(HTTP_STATUS_FILE, ">", $http_status_file) or die "open http status file failed";
open(STDOUT, ">&", \*HTTP_STATUS_FILE) or die "Can't dup HTTP_STATUS_FILE: $!";
my @args = ($curl, "--silent", "--show-error", "--connect-timeout", "20",
"--header", "Content-Type: application/json", "-X", $method,
"-o", $resultfile, "-w", '\n##%{http_code}\n',
"http://${host}:${port}${path}");
if ($data ne "") {
push(@args, "--data");
push(@args, $data);
}
if ($verbose) {
print OLDSTDOUT "Running: " . join(" ", @args) . "\n";
}
if (system(@args) == -1) {
print OLDSTDOUT "$myname: failed to execute @args\n";
$retval = 0;
}
elsif ($? & 127) {
printf OLDSTDOUT "$myname: child died with signal %d, %s coredump\n",
($? & 127), ($? & 128) ? 'with' : 'without';
$retval = 0;
}
else {
my $curl_exit_code = $? >> 8;
if ($curl_exit_code == 0) {
seek HTTP_STATUS_FILE, 0, 0; # Ensures flushing
$http_code = find_http_code($http_status_file);
if ($http_code eq "ERROR") {
print OLDSTDOUT "$myname: failed to open temp file $http_status_file\n";
$retval = 0;
}
elsif ($http_code eq "") {
print OLDSTDOUT "$myname: curl failed to provide HTTP code\n";
$retval = 0;
}
else {
if ($verbose) {
print OLDSTDOUT "HTTP status code = $http_code\n";
}
$retval = 1; # Interaction OK from REST point of view
}
}
else {
print_file(\*OLDSTDOUT, $errfile);
$retval = 0;
}
}
open(STDOUT, ">&", \*OLDSTDOUT) or die "Can't dup OLDSTDOUT: $!";
open(STDERR, ">&", \*OLDERR) or die "Can't dup OLDERR: $!";
unlink($http_status_file);
return $retval;
}
# Pretty-print a JSON file to stdout.
# (currently uses json_reformat command)
# Skips the ##httpcode line we make "curl"
# add in order to get access to the HTTP status.
sub print_json($) {
my $filename = $_[0];
my ($line, $inhandle, $outhandle);
if (!open($inhandle, "<", $filename)) {
print "$myname print_json: cannot open $filename: $!\n";
return;
}
if (!open($outhandle, "|json_reformat")) {
print "$myname print_json: cannot pipe to json_reformat: $!\n";
return;
}
while ($line = <$inhandle>) {
if (! ($line =~ /^##[0-9]+/)) {
print $outhandle $line;
}
}
close($outhandle);
close($inhandle);
}
# Append an entry like ","name":"value" to the first parameter, if "name"
# names a variable with non-empty value.
# Else returns the unmodified first parameter.
sub append_option($$) {
my $result = $_[0];
my $var = $_[1];
my $val = eval("\$$var");
if ($val ne "") {
$result = "$result,\"$var\":\"$val\"";
}
return $result;
}
# Command handlers
# Assumes the API currently implemented.
# Functions for each command below
# Deploy:
# The deploy command has one mandatory parameter "name" in the API,
# and several optional ones. Used mainly internally for testing, because
# they all override Helm chart values:
# "helmVersion": Helm chart version to be used
# "releaseName": The releas name of xApp visible in K8s
# "namespace": Name of the namespace to which xApp is deployed.
# "overrideFile": The file content used to override values.yaml file
# this host from the host the xapp manager is running in, we use the term
# and variable name "podHost" here.
# The options come from options (see GetOptions() call).
sub do_deploy(@) {
my $name = $_[0] || "";
if ($name ne "") {
my $data = "{\"XappName\":\"$name\"";
$data = append_option($data, "helmVersion");
$data = append_option($data, "releaseName");
$data = append_option($data, "namespace");
$data = append_option($data, "overrideFile");
$data = $data . "}";
make_temps();
if (rest("POST", $base_xapps, $data)) {
if ($http_code eq "201") {
print_json $resultfile;
$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();
}
else {
print "$myname: Error: expected the name of xapp to deploy\n";
$status = 1;
}
}
sub do_undeploy(@) {
my $name = $_[0] || "";
my $urlpath = $base_xapps;
if ($name ne "") {
make_temps();
$urlpath = "$urlpath/$name";
if (rest("DELETE", $urlpath)) {
if ($http_code eq "204") {
print "SUCCESSFUL DELETION\n";
$status = 0;
}
else {
my $error;
if ($http_code eq "400") {
$error = "INVALID XAPP NAME 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();
}
else {
print "$myname: Error: expected the name of xapp to undeploy\n";
$status = 1;
}
}
sub do_status(@) {
my $name = $_[0] || "";
my $instance = $_[1] || "";
my $urlpath = $base_xapps;
if ($name ne "") {
$urlpath = "$urlpath/$name";
}
if ($instance ne "") {
$urlpath = "$urlpath/instances/$instance"
}
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 XAPP NAME SUPPLIED";
}
if ($http_code eq "404") {
$error = "XAPP 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();
}
# Helpers for subscription:
# Validate the subscription data that follows a subscription add or modify
# subcommand. $1=URL, $2=eventType, $3=maxRetries, $4=retryTimer
# URL must look like URL, event type must be one of created deleted all,
# maxRetries and retryTimer must be non-negative numbers.
# If errors, returns false (0) and prints errors, else returns 1.
#
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();
}
}