From 0a7e112bb543e73dadb1b78a2ad9d1850c9c9d2e Mon Sep 17 00:00:00 2001 From: Aimee Ukasick Date: Wed, 17 May 2017 20:20:24 -0500 Subject: WIP Script and blueprint for demo that uses ONAP VNFs. JIRA: VES-11 Change-Id: I1f5d2c2bb87a1e24f5cc2eb788bfb3f1efed9e46 Signed-off-by: Aimee Ukasick --- .../blueprints/tosca-vnfd-onap-demo/blueprint.yaml | 292 ++++ .../blueprints/tosca-vnfd-onap-demo/evel_demo.c | 1516 ++++++++++++++++++++ .../blueprints/tosca-vnfd-onap-demo/favicon.ico | Bin 0 -> 1150 bytes .../blueprints/tosca-vnfd-onap-demo/logo.png | Bin 0 -> 4212 bytes .../blueprints/tosca-vnfd-onap-demo/monitor.py | 713 +++++++++ .../blueprints/tosca-vnfd-onap-demo/start.sh | 224 +++ tests/onap-demo/ves_onap_demo.sh | 599 ++++++++ 7 files changed, 3344 insertions(+) create mode 100644 tests/onap-demo/blueprints/tosca-vnfd-onap-demo/blueprint.yaml create mode 100644 tests/onap-demo/blueprints/tosca-vnfd-onap-demo/evel_demo.c create mode 100644 tests/onap-demo/blueprints/tosca-vnfd-onap-demo/favicon.ico create mode 100644 tests/onap-demo/blueprints/tosca-vnfd-onap-demo/logo.png create mode 100644 tests/onap-demo/blueprints/tosca-vnfd-onap-demo/monitor.py create mode 100644 tests/onap-demo/blueprints/tosca-vnfd-onap-demo/start.sh create mode 100644 tests/onap-demo/ves_onap_demo.sh diff --git a/tests/onap-demo/blueprints/tosca-vnfd-onap-demo/blueprint.yaml b/tests/onap-demo/blueprints/tosca-vnfd-onap-demo/blueprint.yaml new file mode 100644 index 0000000..6d9abf9 --- /dev/null +++ b/tests/onap-demo/blueprints/tosca-vnfd-onap-demo/blueprint.yaml @@ -0,0 +1,292 @@ +tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0 + +description: Hello VES ONAP + +metadata: + template_name: tosca-vnfd-onap-demo + +topology_template: + node_templates: + VDU1: + type: tosca.nodes.nfv.VDU.Tacker + properties: + image: models-xenial-server + flavor: onap.demo + availability_zone: nova + config_drive: true + user_data_format: RAW + user_data: | + #!/bin/bash + set -x + mkdir /home/ubuntu + chown -R ubuntu /home/ubuntu + mkdir /home/ubuntu/.ssh + cat << EOM >/home/ubuntu/.ssh/authorized_keys + + EOM + sudo mount /dev/sr0 /mnt/ + mkdir /tmp/www + cd /tmp/www + mkdir html + cat >Dockerfile <html/index.html + + + + Hello World! + + + + + Welcome to OPNFV @ $host!
+ +
+

Instance ID fom config drive file /mnt/openstack/latest/meta_data.json>

+
+          $id
+          
+

Server setup completed at $(date)

+
+ + EOM + wget -O /tmp/www/html/favicon.ico https://git.opnfv.org/models/plain/tests/blueprints/tosca-vnfd-3node-tacker/favicon.ico + sudo apt-get install apt-transport-https ca-certificates curl software-properties-common + curl -fsSL https://apt.dockerproject.org/gpg | sudo apt-key add - + sudo apt-key update + echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" >~/dockerrepo + sudo tee -a /etc/apt/sources.list.d/docker.list ~/dockerrepo + sudo add-apt-repository "deb https://apt.dockerproject.org/repo/ ubuntu-xenial main" + sudo apt-get update + sudo apt-get install -y docker-engine + sudo docker pull nginx + sudo docker build -t vhello . + sudo docker run --name vHello -d -p 80:80 vhello + config: | + param0: key1 + param1: key2 + + CP11: + type: tosca.nodes.nfv.CP.Tacker + properties: + management: true + anti_spoofing_protection: false + requirements: + - virtualLink: + node: VL1 + - virtualBinding: + node: VDU1 + + CP12: + type: tosca.nodes.nfv.CP.Tacker + properties: + anti_spoofing_protection: false + requirements: + - virtualLink: + node: VL2 + - virtualBinding: + node: VDU1 + + VDU2: + type: tosca.nodes.nfv.VDU.Tacker + properties: + image: models-xenial-server + flavor: onap.demo + availability_zone: nova + config_drive: true + user_data_format: RAW + user_data: | + #!/bin/bash + set -x + mkdir /home/ubuntu + chown -R ubuntu /home/ubuntu + mkdir /home/ubuntu/.ssh + cat << EOM >/home/ubuntu/.ssh/authorized_keys + + EOM + sudo mount /dev/sr0 /mnt/ + mkdir /tmp/www + cd /tmp/www + mkdir html + cat >Dockerfile <html/index.html + + + + Hello World! + + + + + Welcome to OPNFV @ $host!
+ +
+

Instance ID fom config drive file /mnt/openstack/latest/meta_data.json>

+
+          $id
+          
+

Server setup completed at $(date)

+
+ + EOM + wget -O /tmp/www/html/favicon.ico https://git.opnfv.org/models/plain/tests/blueprints/tosca-vnfd-3node-tacker/favicon.ico + sudo apt-get install apt-transport-https ca-certificates curl software-properties-common + curl -fsSL https://apt.dockerproject.org/gpg | sudo apt-key add - + sudo apt-key update + echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" >~/dockerrepo + sudo tee -a /etc/apt/sources.list.d/docker.list ~/dockerrepo + sudo add-apt-repository "deb https://apt.dockerproject.org/repo/ ubuntu-xenial main" + sudo apt-get update + sudo apt-get install -y docker-engine + sudo docker pull nginx + sudo docker build -t vhello . + sudo docker run --name vHello -d -p 80:80 vhello + config: | + param0: key1 + param1: key2 + + CP21: + type: tosca.nodes.nfv.CP.Tacker + properties: + management: true + anti_spoofing_protection: false + requirements: + - virtualLink: + node: VL1 + - virtualBinding: + node: VDU2 + + CP22: + type: tosca.nodes.nfv.CP.Tacker + properties: + anti_spoofing_protection: false + requirements: + - virtualLink: + node: VL2 + - virtualBinding: + node: VDU2 + + VDU3: + type: tosca.nodes.nfv.VDU.Tacker + properties: + image: models-xenial-server + flavor: onap.demo + availability_zone: nova + config_drive: true + user_data_format: RAW + user_data: | + #!/bin/bash + set -x + mkdir /home/ubuntu + chown -R ubuntu /home/ubuntu + mkdir /home/ubuntu/.ssh + cat << EOM >/home/ubuntu/.ssh/authorized_keys + + EOM + sudo mount /dev/sr0 /mnt/ + cat << EOF >/tmp/setup.sh + echo "1" | sudo tee /proc/sys/net/ipv4/ip_forward + sudo sysctl net.ipv4.ip_forward=1 + sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -m state \\ + --state NEW -m statistic --mode nth --every 2 --packet 0 \\ + -j DNAT --to-destination :80 + sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -m state \\ + --state NEW -m statistic --mode nth --every 2 --packet 0 \\ + -j DNAT --to-destination :80 + sudo iptables -t nat -A POSTROUTING -j MASQUERADE + EOF + bash /tmp/setup.sh + config: | + param0: key1 + param1: key2 + + config: | + param0: key1 + param1: key2 + + CP31: + type: tosca.nodes.nfv.CP.Tacker + properties: + management: true + anti_spoofing_protection: false + requirements: + - virtualLink: + node: VL1 + - virtualBinding: + node: VDU3 + + CP32: + type: tosca.nodes.nfv.CP.Tacker + properties: + anti_spoofing_protection: false + requirements: + - virtualLink: + node: VL2 + - virtualBinding: + node: VDU3 + + VDU4: + type: tosca.nodes.nfv.VDU.Tacker + properties: + image: models-xenial-server + flavor: onap.demo + availability_zone: nova + user_data_format: RAW + user_data: | + #!/bin/bash + set -x + mkdir /home/ubuntu + chown -R ubuntu /home/ubuntu + mkdir /home/ubuntu/.ssh + cat << EOM >/home/ubuntu/.ssh/authorized_keys + + EOM + config: | + param0: key1 + param1: key2 + + CP41: + type: tosca.nodes.nfv.CP.Tacker + properties: + management: true + anti_spoofing_protection: false + requirements: + - virtualLink: + node: VL1 + - virtualBinding: + node: VDU4 + + CP42: + type: tosca.nodes.nfv.CP.Tacker + properties: + anti_spoofing_protection: false + requirements: + - virtualLink: + node: VL2 + - virtualBinding: + node: VDU4 + + VL1: + type: tosca.nodes.nfv.VL + properties: + network_name: vnf_mgmt + vendor: Tacker + + VL2: + type: tosca.nodes.nfv.VL + properties: + network_name: vnf_private + vendor: Tacker diff --git a/tests/onap-demo/blueprints/tosca-vnfd-onap-demo/evel_demo.c b/tests/onap-demo/blueprints/tosca-vnfd-onap-demo/evel_demo.c new file mode 100644 index 0000000..fc244d8 --- /dev/null +++ b/tests/onap-demo/blueprints/tosca-vnfd-onap-demo/evel_demo.c @@ -0,0 +1,1516 @@ +/**************************************************************************//** + * @file + * Agent for the OPNFV VNF Event Stream (VES) vHello_VES test + * + * Copyright 2016-2017 AT&T Intellectual Property, Inc + * + * 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. + * + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "evel.h" +#include "evel_demo.h" +#include "evel_test_control.h" + +/**************************************************************************//** + * Definition of long options to the program. + * + * See the documentation for getopt_long() for details of the structure's use. + *****************************************************************************/ +static const struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {"id", required_argument, 0, 'i'}, + {"fqdn", required_argument, 0, 'f'}, + {"port", required_argument, 0, 'n'}, + {"path", required_argument, 0, 'p'}, + {"topic", required_argument, 0, 't'}, + {"https", no_argument, 0, 's'}, + {"verbose", no_argument, 0, 'v'}, + {"cycles", required_argument, 0, 'c'}, + {"username", required_argument, 0, 'u'}, + {"password", required_argument, 0, 'w'}, + {"nothrott", no_argument, 0, 'x'}, + {0, 0, 0, 0} + }; + +/**************************************************************************//** + * Definition of short options to the program. + *****************************************************************************/ +static const char* short_options = "hi:f:n:p:t:sc:u:w:vx"; + +/**************************************************************************//** + * Basic user help text describing the usage of the application. + *****************************************************************************/ +static const char* usage_text = +"evel_demo [--help]\n" +" --id \n" +" --fqdn \n" +" --port \n" +" [--path ]\n" +" [--topic ]\n" +" [--username ]\n" +" [--password ]\n" +" [--https]\n" +" [--cycles ]\n" +" [--nothrott]\n" +"\n" +"Demonstrate use of the ECOMP Vendor Event Listener API.\n" +"\n" +" -h Display this usage message.\n" +" --help\n" +"\n" +" -i The ID of the agent host.\n" +" --id\n" +"\n" +" -f The FQDN or IP address to the RESTful API.\n" +" --fqdn\n" +"\n" +" -n The port number the RESTful API.\n" +" --port\n" +"\n" +" -p The optional path prefix to the RESTful API.\n" +" --path\n" +"\n" +" -t The optional topic part of the RESTful API.\n" +" --topic\n" +"\n" +" -u The optional username for basic authentication of requests.\n" +" --username\n" +"\n" +" -w The optional password for basic authentication of requests.\n" +" --password\n" +"\n" +" -s Use HTTPS rather than HTTP for the transport.\n" +" --https\n" +"\n" +" -c Loop times round the main loop. Default = 1.\n" +" --cycles\n" +"\n" +" -v Generate much chattier logs.\n" +" --verbose\n" +"\n" +" -x Exclude throttling commands from demonstration.\n" +" --nothrott\n"; + +#define DEFAULT_SLEEP_SECONDS 3 +#define MINIMUM_SLEEP_SECONDS 1 + +unsigned long long epoch_start = 0; + +typedef enum { + SERVICE_CODEC, + SERVICE_TRANSCODING, + SERVICE_RTCP, + SERVICE_EOC_VQM, + SERVICE_MARKER +} SERVICE_EVENT; + +/*****************************************************************************/ +/* Local prototypes. */ +/*****************************************************************************/ +static void demo_heartbeat(void); +static void demo_fault(void); +static void demo_measurement(const int interval); +static void demo_mobile_flow(void); +static void demo_service(void); +static void demo_service_event(const SERVICE_EVENT service_event); +static void demo_signaling(void); +static void demo_state_change(void); +static void demo_syslog(void); +static void demo_other(void); + +/**************************************************************************//** + * Global flags related the applicaton. + *****************************************************************************/ + +char *app_prevstate = "Stopped"; + +/**************************************************************************//** + * Report app state change fault. + * + * Reports the change in app state. + * + * param[in] char *change The type of change ("Started", "Stopped") + *****************************************************************************/ +void report_app_statechange(char *change) +{ + printf("report_app_statechange(%s)\n", change); + EVENT_FAULT * fault = NULL; + EVEL_ERR_CODES evel_rc = EVEL_SUCCESS; + + fault = evel_new_fault("App state change", + change, + EVEL_PRIORITY_HIGH, + EVEL_SEVERITY_MAJOR); + + if (fault != NULL) { + evel_fault_type_set(fault, "App state change"); + evel_fault_addl_info_add(fault, "change", change); + evel_rc = evel_post_event((EVENT_HEADER *)fault); + if (evel_rc != EVEL_SUCCESS) { + EVEL_ERROR("Post failed %d (%s)", evel_rc, evel_error_string()); + } + else { + EVEL_ERROR("Unable to send new fault report"); + } + } +} + +/**************************************************************************//** + * Check status of the app container. + * + * Checks and reports any change in app state. + * + * param[in] none + *****************************************************************************/ +void check_app_container_state() { + printf("Checking status of app container\n"); + FILE *fp; + int status; + char state[100]; + + fp = popen("sudo docker inspect vHello | grep Status | sed -- 's/,//g' | sed -- 's/\"//g' | sed -- 's/ Status: //g'", "r"); + if (fp == NULL) { + EVEL_ERROR("popen failed to execute command"); + } + + fgets(state, 100, fp); + if (strstr(state, "running") != NULL) { + if (strcmp(app_prevstate,"Stopped") == 0) { + printf("App state change detected: Started\n"); + report_app_statechange("Started"); + app_prevstate = "Running"; + } + } + else { + if (strcmp(app_prevstate, "Running") == 0) { + printf("App state change detected: Stopped\n"); + report_app_statechange("Stopped"); + app_prevstate = "Stopped"; + } + } + status = pclose(fp); + if (status == -1) { + EVEL_ERROR("pclose returned an error"); + } +} + +/**************************************************************************//** + * Measure app traffic + * + * Reports transactions per second in the last second. + * + * param[in] none + *****************************************************************************/ + +double cpu() { + double a[4], b[4], loadavg; + FILE *fp; + int status; + + fp = fopen("/proc/stat","r"); + fscanf(fp,"%*s %lf %lf %lf %lf",&a[0],&a[1],&a[2],&a[3]); + fclose(fp); + sleep(1); + + fp = fopen("/proc/stat","r"); + fscanf(fp,"%*s %lf %lf %lf %lf",&b[0],&b[1],&b[2],&b[3]); + fclose(fp); + + loadavg = ((b[0]+b[1]+b[2]) - (a[0]+a[1]+a[2])) / ((b[0]+b[1]+b[2]+b[3]) - (a[0]+a[1]+a[2]+a[3])); + + return(loadavg); +} + +void measure_traffic() { + + printf("Checking app traffic\n"); + EVENT_FAULT * fault = NULL; + EVEL_ERR_CODES evel_rc = EVEL_SUCCESS; + EVENT_MEASUREMENT * measurement = NULL; + FILE *fp; + int status; + char count[10]; + time_t rawtime; + struct tm * timeinfo; + char period [21]; + char cmd [100]; + int concurrent_sessions = 0; + int configured_entities = 0; + double mean_request_latency = 0; + double measurement_interval = 1; + double memory_configured = 0; + double memory_used = 0; + int request_rate; + char secs [3]; + int sec; + double loadavg; + + time (&rawtime); + timeinfo = localtime (&rawtime); + strftime(period,21,"%d/%b/%Y:%H:%M:",timeinfo); + strftime(secs,3,"%S",timeinfo); + sec = atoi(secs); + if (sec == 0) sec = 59; + sprintf(secs, "%02d", sec); + strncat(period, secs, 21); + // ....x....1....x....2. + // 15/Oct/2016:17:51:19 + strcpy(cmd, "sudo docker logs vHello | grep -c "); + strncat(cmd, period, 100); + + fp = popen(cmd, "r"); + if (fp == NULL) { + EVEL_ERROR("popen failed to execute command"); + } + + if (fgets(count, 10, fp) != NULL) { + request_rate = atoi(count); + printf("Reporting request rate for second: %s as %d\n", period, request_rate); + measurement = evel_new_measurement(measurement_interval); + + if (measurement != NULL) { + cpu(); + evel_measurement_type_set(measurement, "HTTP request rate"); + evel_measurement_request_rate_set(measurement, request_rate); +// evel_measurement_agg_cpu_use_set(measurement, loadavg); +// evel_measurement_cpu_use_add(measurement, "cpu0", loadavg); + + evel_rc = evel_post_event((EVENT_HEADER *)measurement); + if (evel_rc != EVEL_SUCCESS) { + EVEL_ERROR("Post Measurement failed %d (%s)", + evel_rc, + evel_error_string()); + } + } + else { + EVEL_ERROR("New Measurement failed"); + } + printf("Processed measurement\n"); + } + status = pclose(fp); + if (status == -1) { + EVEL_ERROR("pclose returned an error"); + } +} + +/**************************************************************************//** + * Global flag to initiate shutdown. + *****************************************************************************/ +static int glob_exit_now = 0; + +static char * api_fqdn = NULL; +static int api_port = 0; +static int api_secure = 0; + +static void show_usage(FILE* fp) +{ + fputs(usage_text, fp); +} + +/**************************************************************************//** + * Main function. + * + * Parses the command-line then ... + * + * @param[in] argc Argument count. + * @param[in] argv Argument vector - for usage see usage_text. + *****************************************************************************/ +int main(int argc, char ** argv) +{ + sigset_t sig_set; + pthread_t thread_id; + int option_index = 0; + int param = 0; + char * api_vmid = NULL; + char * api_path = NULL; + char * api_topic = NULL; + char * api_username = ""; + char * api_password = ""; + int verbose_mode = 0; + int exclude_throttling = 0; + int cycles = 2147483647; + int cycle; + int measurement_interval = EVEL_MEASUREMENT_INTERVAL_UKNOWN; + EVENT_HEADER * heartbeat = NULL; + EVEL_ERR_CODES evel_rc = EVEL_SUCCESS; + + /***************************************************************************/ + /* We're very interested in memory management problems so check behavior. */ + /***************************************************************************/ + mcheck(NULL); + + if (argc < 2) + { + show_usage(stderr); + exit(-1); + } + param = getopt_long(argc, argv, + short_options, + long_options, + &option_index); + while (param != -1) + { + switch (param) + { + case 'h': + show_usage(stdout); + exit(0); + break; + + case 'i': + api_vmid = optarg; + break; + + case 'f': + api_fqdn = optarg; + break; + + case 'n': + api_port = atoi(optarg); + break; + + case 'p': + api_path = optarg; + break; + + case 't': + api_topic = optarg; + break; + + case 'u': + api_username = optarg; + break; + + case 'w': + api_password = optarg; + break; + + case 's': + api_secure = 1; + break; + + case 'c': + cycles = atoi(optarg); + break; + + case 'v': + verbose_mode = 1; + break; + + case 'x': + exclude_throttling = 1; + break; + + case '?': + /*********************************************************************/ + /* Unrecognized parameter - getopt_long already printed an error */ + /* message. */ + /*********************************************************************/ + break; + + default: + fprintf(stderr, "Code error: recognized but missing option (%d)!\n", + param); + exit(-1); + } + + /*************************************************************************/ + /* Extract next parameter. */ + /*************************************************************************/ + param = getopt_long(argc, argv, + short_options, + long_options, + &option_index); + } + + /***************************************************************************/ + /* All the command-line has parsed cleanly, so now check that the options */ + /* are meaningful. */ + /***************************************************************************/ + if (api_fqdn == NULL) + { + fprintf(stderr, "FQDN of the Vendor Event Listener API server must be " + "specified.\n"); + exit(1); + } + if (api_port <= 0 || api_port > 65535) + { + fprintf(stderr, "Port for the Vendor Event Listener API server must be " + "specified between 1 and 65535.\n"); + exit(1); + } + if (cycles <= 0) + { + fprintf(stderr, "Number of cycles around the main loop must be an" + "integer greater than zero.\n"); + exit(1); + } + + /***************************************************************************/ + /* Set up default signal behaviour. Block all signals we trap explicitly */ + /* on the signal_watcher thread. */ + /***************************************************************************/ + sigemptyset(&sig_set); + sigaddset(&sig_set, SIGALRM); + sigaddset(&sig_set, SIGINT); + pthread_sigmask(SIG_BLOCK, &sig_set, NULL); + + /***************************************************************************/ + /* Start the signal watcher thread. */ + /***************************************************************************/ + if (pthread_create(&thread_id, NULL, signal_watcher, &sig_set) != 0) + { + fprintf(stderr, "Failed to start signal watcher thread."); + exit(1); + } + pthread_detach(thread_id); + + /***************************************************************************/ + /* Version info */ + /***************************************************************************/ + printf("%s built %s %s\n", argv[0], __DATE__, __TIME__); + + /***************************************************************************/ + /* Initialize the EVEL interface. */ + /***************************************************************************/ + if (evel_initialize(api_fqdn, + api_port, + api_path, + api_topic, + api_secure, + api_username, + api_password, + EVEL_SOURCE_VIRTUAL_MACHINE, + "EVEL demo client", + verbose_mode)) + { + fprintf(stderr, "Failed to initialize the EVEL library!!!"); + exit(-1); + } + else + { + EVEL_INFO("Initialization completed"); + } + + /***************************************************************************/ + /* Work out a start time for measurements, and sleep for initial period. */ + /***************************************************************************/ + struct timeval tv_start; + gettimeofday(&tv_start, NULL); + epoch_start = tv_start.tv_usec + 1000000 * tv_start.tv_sec; + sleep(DEFAULT_SLEEP_SECONDS); + + /***************************************************************************/ + /* MAIN LOOP */ + /***************************************************************************/ + printf("Starting %d loops...\n", cycles); + cycle = 0; + while (cycle++ < cycles) + { + EVEL_INFO("MAI: Starting main loop"); + printf("\nStarting main loop %d\n", cycle); + + /*************************************************************************/ + /* A 20s-long repeating cycle of behaviour. */ + /*************************************************************************/ + if (exclude_throttling == 0) + { + switch (cycle % 20) + { + case 1: + printf(" 1 - Resetting throttle specification for all domains\n"); + evel_test_control_scenario(TC_RESET_ALL_DOMAINS, + api_secure, + api_fqdn, + api_port); + break; + + case 2: + printf(" 2 - Switching measurement interval to 2s\n"); + evel_test_control_meas_interval(2, + api_secure, + api_fqdn, + api_port); + break; + + case 3: + printf(" 3 - Suppressing fault domain\n"); + evel_test_control_scenario(TC_FAULT_SUPPRESS_FIELDS_AND_PAIRS, + api_secure, + api_fqdn, + api_port); + break; + + case 4: + printf(" 4 - Suppressing measurement domain\n"); + evel_test_control_scenario(TC_MEAS_SUPPRESS_FIELDS_AND_PAIRS, + api_secure, + api_fqdn, + api_port); + break; + + case 5: + printf(" 5 - Switching measurement interval to 5s\n"); + evel_test_control_meas_interval(5, + api_secure, + api_fqdn, + api_port); + break; + + case 6: + printf(" 6 - Suppressing mobile flow domain\n"); + evel_test_control_scenario(TC_MOBILE_SUPPRESS_FIELDS_AND_PAIRS, + api_secure, + api_fqdn, + api_port); + break; + + case 7: + printf(" 7 - Suppressing state change domain\n"); + evel_test_control_scenario(TC_STATE_SUPPRESS_FIELDS_AND_PAIRS, + api_secure, + api_fqdn, + api_port); + break; + + case 8: + printf(" 8 - Suppressing signaling domain\n"); + evel_test_control_scenario(TC_SIGNALING_SUPPRESS_FIELDS, + api_secure, + api_fqdn, + api_port); + break; + + case 9: + printf(" 9 - Suppressing service event domain\n"); + evel_test_control_scenario(TC_SERVICE_SUPPRESS_FIELDS_AND_PAIRS, + api_secure, + api_fqdn, + api_port); + break; + + case 10: + printf(" 10 - Switching measurement interval to 20s\n"); + evel_test_control_meas_interval(20, + api_secure, + api_fqdn, + api_port); + break; + + case 11: + printf(" 11 - Suppressing syslog domain\n"); + evel_test_control_scenario(TC_SYSLOG_SUPPRESS_FIELDS_AND_PAIRS, + api_secure, + api_fqdn, + api_port); + break; + + case 12: + printf(" 12 - Switching measurement interval to 10s\n"); + evel_test_control_meas_interval(10, + api_secure, + api_fqdn, + api_port); + break; + + case 15: + printf(" Requesting provide throttling spec\n"); + evel_test_control_scenario(TC_PROVIDE_THROTTLING_SPEC, + api_secure, + api_fqdn, + api_port); + break; + } + } + fflush(stdout); + + /*************************************************************************/ + /* Send a bunch of events. */ + /*************************************************************************/ + + printf("Sending heartbeat\n"); + heartbeat = evel_new_heartbeat(); + if (heartbeat != NULL) + { + evel_rc = evel_post_event(heartbeat); + if (evel_rc != EVEL_SUCCESS) + { + EVEL_ERROR("Post failed %d (%s)", evel_rc, evel_error_string()); + } + } + else + { + EVEL_ERROR("New heartbeat failed"); + } + + check_app_container_state(); + measure_traffic(); + +// demo_heartbeat(); +// demo_fault(); +// demo_measurement((measurement_interval == +// EVEL_MEASUREMENT_INTERVAL_UKNOWN) ? +// DEFAULT_SLEEP_SECONDS : measurement_interval); +// demo_mobile_flow(); +// demo_service(); +// demo_signaling(); +// demo_state_change(); +// demo_syslog(); +// demo_other(); + + /*************************************************************************/ + /* MAIN RETRY LOOP. Check and implement the measurement interval. */ + /*************************************************************************/ + if (cycle <= cycles) + { + int sleep_time; + + /***********************************************************************/ + /* We have a minimum loop time. */ + /***********************************************************************/ + sleep(MINIMUM_SLEEP_SECONDS); + + /***********************************************************************/ + /* Get the latest measurement interval and sleep for the remainder. */ + /***********************************************************************/ + measurement_interval = evel_get_measurement_interval(); + printf("Measurement Interval = %d\n", measurement_interval); + + if (measurement_interval == EVEL_MEASUREMENT_INTERVAL_UKNOWN) + { + sleep_time = DEFAULT_SLEEP_SECONDS - MINIMUM_SLEEP_SECONDS; + } + else + { + sleep_time = measurement_interval - MINIMUM_SLEEP_SECONDS; + } + sleep(sleep_time); + } + } + + /***************************************************************************/ + /* We are exiting, but allow the final set of events to be dispatched */ + /* properly first. */ + /***************************************************************************/ + sleep(2); + printf("All done - exiting!\n"); + return 0; +} + +/**************************************************************************//** + * Signal watcher. + * + * Signal catcher for incoming signal processing. Work out which signal has + * been received and process it accordingly. + * + * param[in] void_sig_set The signal mask to listen for. + *****************************************************************************/ +void *signal_watcher(void *void_sig_set) +{ + sigset_t *sig_set = (sigset_t *)void_sig_set; + int sig = 0; + int old_type = 0; + siginfo_t sig_info; + + /***************************************************************************/ + /* Set this thread to be cancellable immediately. */ + /***************************************************************************/ + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old_type); + + while (!glob_exit_now) + { + /*************************************************************************/ + /* Wait for a signal to be received. */ + /*************************************************************************/ + sig = sigwaitinfo(sig_set, &sig_info); + switch (sig) + { + case SIGALRM: + /*********************************************************************/ + /* Failed to do something in the given amount of time. Exit. */ + /*********************************************************************/ + EVEL_ERROR( "Timeout alarm"); + fprintf(stderr,"Timeout alarm - quitting!\n"); + exit(2); + break; + + case SIGINT: + EVEL_INFO( "Interrupted - quitting"); + printf("\n\nInterrupted - quitting!\n"); + glob_exit_now = 1; + break; + } + } + + evel_terminate(); + exit(0); + return(NULL); +} + +/**************************************************************************//** + * Create and send a heartbeat event. + *****************************************************************************/ +void demo_heartbeat(void) +{ + EVENT_HEADER * heartbeat = NULL; + EVEL_ERR_CODES evel_rc = EVEL_SUCCESS; + + /***************************************************************************/ + /* Heartbeat */ + /***************************************************************************/ + heartbeat = evel_new_heartbeat(); + if (heartbeat != NULL) + { + evel_rc = evel_post_event(heartbeat); + if (evel_rc != EVEL_SUCCESS) + { + EVEL_ERROR("Post failed %d (%s)", evel_rc, evel_error_string()); + } + } + else + { + EVEL_ERROR("New Heartbeat failed"); + } + printf(" Processed Heartbeat\n"); +} + +/**************************************************************************//** + * Create and send three fault events. + *****************************************************************************/ +void demo_fault(void) +{ + EVENT_FAULT * fault = NULL; + EVEL_ERR_CODES evel_rc = EVEL_SUCCESS; + + /***************************************************************************/ + /* Fault */ + /***************************************************************************/ + fault = evel_new_fault("An alarm condition", + "Things are broken", + EVEL_PRIORITY_NORMAL, + EVEL_SEVERITY_MAJOR); + if (fault != NULL) + { + evel_rc = evel_post_event((EVENT_HEADER *)fault); + if (evel_rc != EVEL_SUCCESS) + { + EVEL_ERROR("Post failed %d (%s)", evel_rc, evel_error_string()); + } + } + else + { + EVEL_ERROR("New Fault failed"); + } + printf(" Processed empty Fault\n"); + + fault = evel_new_fault("Another alarm condition", + "It broke badly", + EVEL_PRIORITY_NORMAL, + EVEL_SEVERITY_MAJOR); + if (fault != NULL) + { + evel_fault_type_set(fault, "Bad things happening"); + evel_fault_interface_set(fault, "An Interface Card"); + evel_rc = evel_post_event((EVENT_HEADER *)fault); + if (evel_rc != EVEL_SUCCESS) + { + EVEL_ERROR("Post failed %d (%s)", evel_rc, evel_error_string()); + } + } + else + { + EVEL_ERROR("New Fault failed"); + } + printf(" Processed partial Fault\n"); + + fault = evel_new_fault("My alarm condition", + "It broke very badly", + EVEL_PRIORITY_NORMAL, + EVEL_SEVERITY_MAJOR); + if (fault != NULL) + { + evel_fault_type_set(fault, "Bad things happen..."); + evel_fault_interface_set(fault, "My Interface Card"); + evel_fault_addl_info_add(fault, "name1", "value1"); + evel_fault_addl_info_add(fault, "name2", "value2"); + evel_rc = evel_post_event((EVENT_HEADER *)fault); + if (evel_rc != EVEL_SUCCESS) + { + EVEL_ERROR("Post failed %d (%s)", evel_rc, evel_error_string()); + } + } + else + { + EVEL_ERROR("New Fault failed"); + } + printf(" Processed full Fault\n"); +} + +/**************************************************************************//** + * Create and send a measurement event. + *****************************************************************************/ +void demo_measurement(const int interval) +{ + EVENT_MEASUREMENT * measurement = NULL; + MEASUREMENT_LATENCY_BUCKET * bucket = NULL; + MEASUREMENT_VNIC_USE * vnic_use = NULL; + EVEL_ERR_CODES evel_rc = EVEL_SUCCESS; + + /***************************************************************************/ + /* Measurement */ + /***************************************************************************/ + measurement = evel_new_measurement(interval); + if (measurement != NULL) + { + evel_measurement_type_set(measurement, "Perf management..."); + evel_measurement_conc_sess_set(measurement, 1); + evel_measurement_cfg_ents_set(measurement, 2); + evel_measurement_mean_req_lat_set(measurement, 4.4); + evel_measurement_mem_cfg_set(measurement, 6.6); + evel_measurement_mem_used_set(measurement, 3.3); + evel_measurement_request_rate_set(measurement, 6); + evel_measurement_agg_cpu_use_set(measurement, 8.8); + evel_measurement_cpu_use_add(measurement, "cpu1", 11.11); + evel_measurement_cpu_use_add(measurement, "cpu2", 22.22); + evel_measurement_fsys_use_add(measurement,"00-11-22",100.11, 100.22, 33, + 200.11, 200.22, 44); + evel_measurement_fsys_use_add(measurement,"33-44-55",300.11, 300.22, 55, + 400.11, 400.22, 66); + + bucket = evel_new_meas_latency_bucket(20); + evel_meas_latency_bucket_low_end_set(bucket, 0.0); + evel_meas_latency_bucket_high_end_set(bucket, 10.0); + evel_meas_latency_bucket_add(measurement, bucket); + + bucket = evel_new_meas_latency_bucket(30); + evel_meas_latency_bucket_low_end_set(bucket, 10.0); + evel_meas_latency_bucket_high_end_set(bucket, 20.0); + evel_meas_latency_bucket_add(measurement, bucket); + + vnic_use = evel_new_measurement_vnic_use("eth0", 100, 200, 3, 4); + evel_vnic_use_bcast_pkt_in_set(vnic_use, 1); + evel_vnic_use_bcast_pkt_out_set(vnic_use, 2); + evel_vnic_use_mcast_pkt_in_set(vnic_use, 5); + evel_vnic_use_mcast_pkt_out_set(vnic_use, 6); + evel_vnic_use_ucast_pkt_in_set(vnic_use, 7); + evel_vnic_use_ucast_pkt_out_set(vnic_use, 8); + evel_meas_vnic_use_add(measurement, vnic_use); + + vnic_use = evel_new_measurement_vnic_use("eth1", 110, 240, 13, 14); + evel_vnic_use_bcast_pkt_in_set(vnic_use, 11); + evel_vnic_use_bcast_pkt_out_set(vnic_use, 12); + evel_vnic_use_mcast_pkt_in_set(vnic_use, 15); + evel_vnic_use_mcast_pkt_out_set(vnic_use, 16); + evel_vnic_use_ucast_pkt_in_set(vnic_use, 17); + evel_vnic_use_ucast_pkt_out_set(vnic_use, 18); + evel_meas_vnic_use_add(measurement, vnic_use); + + evel_measurement_errors_set(measurement, 1, 0, 2, 1); + + evel_measurement_feature_use_add(measurement, "FeatureA", 123); + evel_measurement_feature_use_add(measurement, "FeatureB", 567); + + evel_measurement_codec_use_add(measurement, "G711a", 91); + evel_measurement_codec_use_add(measurement, "G729ab", 92); + + evel_measurement_media_port_use_set(measurement, 1234); + + evel_measurement_vnfc_scaling_metric_set(measurement, 1234.5678); + + evel_measurement_custom_measurement_add(measurement, + "Group1", "Name1", "Value1"); + evel_measurement_custom_measurement_add(measurement, + "Group2", "Name1", "Value1"); + evel_measurement_custom_measurement_add(measurement, + "Group2", "Name2", "Value2"); + + /*************************************************************************/ + /* Work out the time, to use as end of measurement period. */ + /*************************************************************************/ + struct timeval tv_now; + gettimeofday(&tv_now, NULL); + unsigned long long epoch_now = tv_now.tv_usec + 1000000 * tv_now.tv_sec; + evel_start_epoch_set(&measurement->header, epoch_start); + evel_last_epoch_set(&measurement->header, epoch_now); + epoch_start = epoch_now; + evel_reporting_entity_name_set(&measurement->header, "measurer"); + evel_reporting_entity_id_set(&measurement->header, "measurer_id"); + + evel_rc = evel_post_event((EVENT_HEADER *)measurement); + if (evel_rc != EVEL_SUCCESS) + { + EVEL_ERROR("Post Measurement failed %d (%s)", + evel_rc, + evel_error_string()); + } + } + else + { + EVEL_ERROR("New Measurement failed"); + } + printf(" Processed Measurement\n"); +} + +/**************************************************************************//** + * Create and send three mobile flow events. + *****************************************************************************/ +void demo_mobile_flow(void) +{ + MOBILE_GTP_PER_FLOW_METRICS * metrics = NULL; + EVENT_MOBILE_FLOW * mobile_flow = NULL; + EVEL_ERR_CODES evel_rc = EVEL_SUCCESS; + + /***************************************************************************/ + /* Mobile Flow */ + /***************************************************************************/ + metrics = evel_new_mobile_gtp_flow_metrics(12.3, + 3.12, + 100, + 2100, + 500, + 1470409421, + 987, + 1470409431, + 11, + (time_t)1470409431, + "Working", + 87, + 3, + 17, + 123654, + 4561, + 0, + 12, + 10, + 1, + 3, + 7, + 899, + 901, + 302, + 6, + 2, + 0, + 110, + 225); + if (metrics != NULL) + { + mobile_flow = evel_new_mobile_flow("Outbound", + metrics, + "TCP", + "IPv4", + "2.3.4.1", + 2341, + "4.2.3.1", + 4321); + if (mobile_flow != NULL) + { + evel_rc = evel_post_event((EVENT_HEADER *)mobile_flow); + if (evel_rc != EVEL_SUCCESS) + { + EVEL_ERROR("Post Mobile Flow failed %d (%s)", + evel_rc, + evel_error_string()); + } + } + else + { + EVEL_ERROR("New Mobile Flow failed"); + } + printf(" Processed empty Mobile Flow\n"); + } + else + { + EVEL_ERROR("New GTP Per Flow Metrics failed - skipping Mobile Flow"); + printf(" Skipped empty Mobile Flow\n"); + } + + metrics = evel_new_mobile_gtp_flow_metrics(132.0001, + 31.2, + 101, + 2101, + 501, + 1470409422, + 988, + 1470409432, + 12, + (time_t)1470409432, + "Inactive", + 88, + 4, + 18, + 123655, + 4562, + 1, + 13, + 11, + 2, + 4, + 8, + 900, + 902, + 303, + 7, + 3, + 1, + 111, + 226); + if (metrics != NULL) + { + mobile_flow = evel_new_mobile_flow("Inbound", + metrics, + "UDP", + "IPv6", + "2.3.4.2", + 2342, + "4.2.3.2", + 4322); + if (mobile_flow != NULL) + { + evel_mobile_flow_app_type_set(mobile_flow, "Demo application"); + evel_mobile_flow_app_prot_type_set(mobile_flow, "GSM"); + evel_mobile_flow_app_prot_ver_set(mobile_flow, "1"); + evel_mobile_flow_cid_set(mobile_flow, "65535"); + evel_mobile_flow_con_type_set(mobile_flow, "S1-U"); + evel_mobile_flow_ecgi_set(mobile_flow, "e65535"); + evel_mobile_flow_gtp_prot_type_set(mobile_flow, "GTP-U"); + evel_mobile_flow_gtp_prot_ver_set(mobile_flow, "1"); + evel_mobile_flow_http_header_set(mobile_flow, + "http://www.something.com"); + evel_mobile_flow_imei_set(mobile_flow, "209917614823"); + evel_mobile_flow_imsi_set(mobile_flow, "355251/05/850925/8"); + evel_mobile_flow_lac_set(mobile_flow, "1"); + evel_mobile_flow_mcc_set(mobile_flow, "410"); + evel_mobile_flow_mnc_set(mobile_flow, "04"); + evel_mobile_flow_msisdn_set(mobile_flow, "6017123456789"); + evel_mobile_flow_other_func_role_set(mobile_flow, "MME"); + evel_mobile_flow_rac_set(mobile_flow, "514"); + evel_mobile_flow_radio_acc_tech_set(mobile_flow, "LTE"); + evel_mobile_flow_sac_set(mobile_flow, "1"); + evel_mobile_flow_samp_alg_set(mobile_flow, 1); + evel_mobile_flow_tac_set(mobile_flow, "2099"); + evel_mobile_flow_tunnel_id_set(mobile_flow, "Tunnel 1"); + evel_mobile_flow_vlan_id_set(mobile_flow, "15"); + + evel_rc = evel_post_event((EVENT_HEADER *)mobile_flow); + if (evel_rc != EVEL_SUCCESS) + { + EVEL_ERROR("Post Mobile Flow failed %d (%s)", + evel_rc, + evel_error_string()); + } + } + else + { + EVEL_ERROR("New Mobile Flow failed"); + } + printf(" Processed partial Mobile Flow\n"); + } + else + { + EVEL_ERROR("New GTP Per Flow Metrics failed - skipping Mobile Flow"); + printf(" Skipped partial Mobile Flow\n"); + } + + metrics = evel_new_mobile_gtp_flow_metrics(12.32, + 3.122, + 1002, + 21002, + 5002, + 1470409423, + 9872, + 1470409433, + 112, + (time_t)1470409433, + "Failed", + 872, + 32, + 172, + 1236542, + 45612, + 2, + 122, + 102, + 12, + 32, + 72, + 8992, + 9012, + 3022, + 62, + 22, + 2, + 1102, + 2252); + if (metrics != NULL) + { + evel_mobile_gtp_metrics_dur_con_fail_set(metrics, 12); + evel_mobile_gtp_metrics_dur_tun_fail_set(metrics, 13); + evel_mobile_gtp_metrics_act_by_set(metrics, "Remote"); + evel_mobile_gtp_metrics_act_time_set(metrics, (time_t)1470409423); + evel_mobile_gtp_metrics_deact_by_set(metrics, "Remote"); + evel_mobile_gtp_metrics_con_status_set(metrics, "Connected"); + evel_mobile_gtp_metrics_tun_status_set(metrics, "Not tunneling"); + evel_mobile_gtp_metrics_iptos_set(metrics, 1, 13); + evel_mobile_gtp_metrics_iptos_set(metrics, 17, 1); + evel_mobile_gtp_metrics_iptos_set(metrics, 4, 99); + evel_mobile_gtp_metrics_large_pkt_rtt_set(metrics, 80); + evel_mobile_gtp_metrics_large_pkt_thresh_set(metrics, 600.0); + evel_mobile_gtp_metrics_max_rcv_bit_rate_set(metrics, 1357924680); + evel_mobile_gtp_metrics_max_trx_bit_rate_set(metrics, 235711); + evel_mobile_gtp_metrics_num_echo_fail_set(metrics, 1); + evel_mobile_gtp_metrics_num_tun_fail_set(metrics, 4); + evel_mobile_gtp_metrics_num_http_errors_set(metrics, 2); + evel_mobile_gtp_metrics_tcp_flag_count_add(metrics, EVEL_TCP_CWR, 10); + evel_mobile_gtp_metrics_tcp_flag_count_add(metrics, EVEL_TCP_URG, 121); + evel_mobile_gtp_metrics_qci_cos_count_add( + metrics, EVEL_QCI_COS_UMTS_CONVERSATIONAL, 11); + evel_mobile_gtp_metrics_qci_cos_count_add( + metrics, EVEL_QCI_COS_LTE_65, 122); + + mobile_flow = evel_new_mobile_flow("Outbound", + metrics, + "RTP", + "IPv8", + "2.3.4.3", + 2343, + "4.2.3.3", + 4323); + if (mobile_flow != NULL) + { + evel_mobile_flow_app_type_set(mobile_flow, "Demo application 2"); + evel_mobile_flow_app_prot_type_set(mobile_flow, "GSM"); + evel_mobile_flow_app_prot_ver_set(mobile_flow, "2"); + evel_mobile_flow_cid_set(mobile_flow, "1"); + evel_mobile_flow_con_type_set(mobile_flow, "S1-U"); + evel_mobile_flow_ecgi_set(mobile_flow, "e1"); + evel_mobile_flow_gtp_prot_type_set(mobile_flow, "GTP-U"); + evel_mobile_flow_gtp_prot_ver_set(mobile_flow, "1"); + evel_mobile_flow_http_header_set(mobile_flow, "http://www.google.com"); + evel_mobile_flow_imei_set(mobile_flow, "209917614823"); + evel_mobile_flow_imsi_set(mobile_flow, "355251/05/850925/8"); + evel_mobile_flow_lac_set(mobile_flow, "1"); + evel_mobile_flow_mcc_set(mobile_flow, "410"); + evel_mobile_flow_mnc_set(mobile_flow, "04"); + evel_mobile_flow_msisdn_set(mobile_flow, "6017123456789"); + evel_mobile_flow_other_func_role_set(mobile_flow, "MMF"); + evel_mobile_flow_rac_set(mobile_flow, "514"); + evel_mobile_flow_radio_acc_tech_set(mobile_flow, "3G"); + evel_mobile_flow_sac_set(mobile_flow, "1"); + evel_mobile_flow_samp_alg_set(mobile_flow, 2); + evel_mobile_flow_tac_set(mobile_flow, "2099"); + evel_mobile_flow_tunnel_id_set(mobile_flow, "Tunnel 2"); + evel_mobile_flow_vlan_id_set(mobile_flow, "4096"); + + evel_rc = evel_post_event((EVENT_HEADER *)mobile_flow); + if (evel_rc != EVEL_SUCCESS) + { + EVEL_ERROR("Post Mobile Flow failed %d (%s)", + evel_rc, + evel_error_string()); + } + } + else + { + EVEL_ERROR("New Mobile Flow failed"); + } + printf(" Processed full Mobile Flow\n"); + } + else + { + EVEL_ERROR("New GTP Per Flow Metrics failed - skipping Mobile Flow"); + printf(" Skipped full Mobile Flow\n"); + } +} + +/**************************************************************************//** + * Create and send a Service event. + *****************************************************************************/ +void demo_service() +{ + demo_service_event(SERVICE_CODEC); + demo_service_event(SERVICE_TRANSCODING); + demo_service_event(SERVICE_RTCP); + demo_service_event(SERVICE_EOC_VQM); + demo_service_event(SERVICE_MARKER); +} + +void demo_service_event(const SERVICE_EVENT service_event) +{ + EVENT_SERVICE * event = NULL; + EVEL_ERR_CODES evel_rc = EVEL_SUCCESS; + + event = evel_new_service("vendor_x_id", "vendor_x_event_id"); + if (event != NULL) + { + evel_service_type_set(event, "Service Event"); + evel_service_product_id_set(event, "vendor_x_product_id"); + evel_service_subsystem_id_set(event, "vendor_x_subsystem_id"); + evel_service_friendly_name_set(event, "vendor_x_frieldly_name"); + evel_service_correlator_set(event, "vendor_x_correlator"); + evel_service_addl_field_add(event, "Name1", "Value1"); + evel_service_addl_field_add(event, "Name2", "Value2"); + + switch (service_event) + { + case SERVICE_CODEC: + evel_service_codec_set(event, "PCMA"); + break; + case SERVICE_TRANSCODING: + evel_service_callee_codec_set(event, "PCMA"); + evel_service_caller_codec_set(event, "G729A"); + break; + case SERVICE_RTCP: + evel_service_rtcp_data_set(event, "some_rtcp_data"); + break; + case SERVICE_EOC_VQM: + evel_service_adjacency_name_set(event, "vendor_x_adjacency"); + evel_service_endpoint_desc_set(event, EVEL_SERVICE_ENDPOINT_CALLER); + evel_service_endpoint_jitter_set(event, 66); + evel_service_endpoint_rtp_oct_disc_set(event, 100); + evel_service_endpoint_rtp_oct_recv_set(event, 200); + evel_service_endpoint_rtp_oct_sent_set(event, 300); + evel_service_endpoint_rtp_pkt_disc_set(event, 400); + evel_service_endpoint_rtp_pkt_recv_set(event, 500); + evel_service_endpoint_rtp_pkt_sent_set(event, 600); + evel_service_local_jitter_set(event, 99); + evel_service_local_rtp_oct_disc_set(event, 150); + evel_service_local_rtp_oct_recv_set(event, 250); + evel_service_local_rtp_oct_sent_set(event, 350); + evel_service_local_rtp_pkt_disc_set(event, 450); + evel_service_local_rtp_pkt_recv_set(event, 550); + evel_service_local_rtp_pkt_sent_set(event, 650); + evel_service_mos_cqe_set(event, 12.255); + evel_service_packets_lost_set(event, 157); + evel_service_packet_loss_percent_set(event, 0.232); + evel_service_r_factor_set(event, 11); + evel_service_round_trip_delay_set(event, 15); + break; + case SERVICE_MARKER: + evel_service_phone_number_set(event, "0888888888"); + break; + } + + evel_rc = evel_post_event((EVENT_HEADER *) event); + if (evel_rc != EVEL_SUCCESS) + { + EVEL_ERROR("Post failed %d (%s)", evel_rc, evel_error_string()); + } + } + else + { + EVEL_ERROR("New Service failed"); + } + printf(" Processed Service Events\n"); +} + +/**************************************************************************//** + * Create and send a Signaling event. + *****************************************************************************/ +void demo_signaling(void) +{ + EVENT_SIGNALING * event = NULL; + EVEL_ERR_CODES evel_rc = EVEL_SUCCESS; + + event = evel_new_signaling("vendor_x_id", "vendor_x_event_id"); + if (event != NULL) + { + evel_signaling_type_set(event, "Signaling"); + evel_signaling_product_id_set(event, "vendor_x_product_id"); + evel_signaling_subsystem_id_set(event, "vendor_x_subsystem_id"); + evel_signaling_friendly_name_set(event, "vendor_x_frieldly_name"); + evel_signaling_correlator_set(event, "vendor_x_correlator"); + evel_signaling_local_ip_address_set(event, "1.0.3.1"); + evel_signaling_local_port_set(event, "1031"); + evel_signaling_remote_ip_address_set(event, "5.3.3.0"); + evel_signaling_remote_port_set(event, "5330"); + evel_signaling_compressed_sip_set(event, "compressed_sip"); + evel_signaling_summary_sip_set(event, "summary_sip"); + evel_rc = evel_post_event((EVENT_HEADER *) event); + if (evel_rc != EVEL_SUCCESS) + { + EVEL_ERROR("Post failed %d (%s)", evel_rc, evel_error_string()); + } + } + else + { + EVEL_ERROR("New Signaling failed"); + } + printf(" Processed Signaling\n"); +} + +/**************************************************************************//** + * Create and send a state change event. + *****************************************************************************/ +void demo_state_change(void) +{ + EVENT_STATE_CHANGE * state_change = NULL; + EVEL_ERR_CODES evel_rc = EVEL_SUCCESS; + + /***************************************************************************/ + /* State Change */ + /***************************************************************************/ + state_change = evel_new_state_change(EVEL_ENTITY_STATE_IN_SERVICE, + EVEL_ENTITY_STATE_OUT_OF_SERVICE, + "Interface"); + if (state_change != NULL) + { + evel_state_change_type_set(state_change, "State Change"); + evel_state_change_addl_field_add(state_change, "Name1", "Value1"); + evel_state_change_addl_field_add(state_change, "Name2", "Value2"); + evel_rc = evel_post_event((EVENT_HEADER *)state_change); + if (evel_rc != EVEL_SUCCESS) + { + EVEL_ERROR("Post failed %d (%s)", evel_rc, evel_error_string()); + } + } + else + { + EVEL_ERROR("New State Change failed"); + } + printf(" Processed State Change\n"); +} + +/**************************************************************************//** + * Create and send two syslog events. + *****************************************************************************/ +void demo_syslog(void) +{ + EVENT_SYSLOG * syslog = NULL; + EVEL_ERR_CODES evel_rc = EVEL_SUCCESS; + + /***************************************************************************/ + /* Syslog */ + /***************************************************************************/ + syslog = evel_new_syslog(EVEL_SOURCE_VIRTUAL_NETWORK_FUNCTION, + "EVEL library message", + "EVEL"); + if (syslog != NULL) + { + evel_rc = evel_post_event((EVENT_HEADER *)syslog); + if (evel_rc != EVEL_SUCCESS) + { + EVEL_ERROR("Post failed %d (%s)", evel_rc, evel_error_string()); + } + } + else + { + EVEL_ERROR("New Syslog failed"); + } + printf(" Processed empty Syslog\n"); + + syslog = evel_new_syslog(EVEL_SOURCE_VIRTUAL_MACHINE, + "EVEL library message", + "EVEL"); + if (syslog != NULL) + { + evel_syslog_event_source_host_set(syslog, "Virtual host"); + evel_syslog_facility_set(syslog, EVEL_SYSLOG_FACILITY_LOCAL0); + evel_syslog_proc_set(syslog, "vnf_process"); + evel_syslog_proc_id_set(syslog, 1423); + evel_syslog_version_set(syslog, 1); + evel_syslog_addl_field_add(syslog, "Name1", "Value1"); + evel_syslog_addl_field_add(syslog, "Name2", "Value2"); + evel_syslog_addl_field_add(syslog, "Name3", "Value3"); + evel_syslog_addl_field_add(syslog, "Name4", "Value4"); + evel_rc = evel_post_event((EVENT_HEADER *)syslog); + if (evel_rc != EVEL_SUCCESS) + { + EVEL_ERROR("Post failed %d (%s)", evel_rc, evel_error_string()); + } + } + else + { + EVEL_ERROR("New Syslog failed"); + } + printf(" Processed full Syslog\n"); +} + +/**************************************************************************//** + * Create and send two other events. + *****************************************************************************/ +void demo_other(void) +{ + EVENT_OTHER * other = NULL; + EVEL_ERR_CODES evel_rc = EVEL_SUCCESS; + + /***************************************************************************/ + /* Other */ + /***************************************************************************/ + other = evel_new_other(); + if (other != NULL) + { + evel_rc = evel_post_event((EVENT_HEADER *)other); + if (evel_rc != EVEL_SUCCESS) + { + EVEL_ERROR("Post failed %d (%s)", evel_rc, evel_error_string()); + } + } + else + { + EVEL_ERROR("New Other failed"); + } + printf(" Processed empty Other\n"); + + other = evel_new_other(); + if (other != NULL) + { + evel_other_field_add(other, + "Other field 1", + "Other value 1"); + evel_rc = evel_post_event((EVENT_HEADER *)other); + if (evel_rc != EVEL_SUCCESS) + { + EVEL_ERROR("Post failed %d (%s)", evel_rc, evel_error_string()); + } + } + else + { + EVEL_ERROR("New Other failed"); + } + printf(" Processed small Other\n"); + + other = evel_new_other(); + if (other != NULL) + { + evel_other_field_add(other, + "Other field A", + "Other value A"); + evel_other_field_add(other, + "Other field B", + "Other value B"); + evel_other_field_add(other, + "Other field C", + "Other value C"); + evel_rc = evel_post_event((EVENT_HEADER *)other); + if (evel_rc != EVEL_SUCCESS) + { + EVEL_ERROR("Post failed %d (%s)", evel_rc, evel_error_string()); + } + } + else + { + EVEL_ERROR("New Other failed"); + } + printf(" Processed large Other\n"); +} diff --git a/tests/onap-demo/blueprints/tosca-vnfd-onap-demo/favicon.ico b/tests/onap-demo/blueprints/tosca-vnfd-onap-demo/favicon.ico new file mode 100644 index 0000000..cd95189 Binary files /dev/null and b/tests/onap-demo/blueprints/tosca-vnfd-onap-demo/favicon.ico differ diff --git a/tests/onap-demo/blueprints/tosca-vnfd-onap-demo/logo.png b/tests/onap-demo/blueprints/tosca-vnfd-onap-demo/logo.png new file mode 100644 index 0000000..a4bf310 Binary files /dev/null and b/tests/onap-demo/blueprints/tosca-vnfd-onap-demo/logo.png differ diff --git a/tests/onap-demo/blueprints/tosca-vnfd-onap-demo/monitor.py b/tests/onap-demo/blueprints/tosca-vnfd-onap-demo/monitor.py new file mode 100644 index 0000000..9b16af3 --- /dev/null +++ b/tests/onap-demo/blueprints/tosca-vnfd-onap-demo/monitor.py @@ -0,0 +1,713 @@ +#!/usr/bin/env python +# +# Copyright 2016-2017 AT&T Intellectual Property, Inc +# +# 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. +# +# What this is: Monitor and closed-loop policy agent as part of the OPNFV VES +# vHello_VES demo. +# +# Status: this is a work in progress, under test. + +from rest_dispatcher import PathDispatcher, set_404_content +from wsgiref.simple_server import make_server +import sys +import os +import platform +import traceback +import time +from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter +import ConfigParser +import logging.handlers +from base64 import b64decode +import string +import json +import jsonschema +from functools import partial + +monitor_mode = "f" +vdu_id = ['','','',''] +summary_e = ['***** Summary of key stats *****','','',''] +summary_c = ['Collectd agents:'] +status = ['','Started','Started','Started'] +base_url = '' +template_404 = b'''POST {0}''' +columns = 0 +rows = 0 + +class JSONObject: + def __init__(self, d): + self.__dict__ = d + +_hello_resp = '''\ + + + Hello {name} + + +

Hello {name}!

+ +''' + +_localtime_resp = '''\ + +''' + +__all__ = [] +__version__ = 0.1 +__date__ = '2015-12-04' +__updated__ = '2015-12-04' + +TESTRUN = False +DEBUG = False +PROFILE = False + +#------------------------------------------------------------------------------ +# Credentials we expect clients to authenticate themselves with. +#------------------------------------------------------------------------------ +vel_username = '' +vel_password = '' + +#------------------------------------------------------------------------------ +# The JSON schema which we will use to validate events. +#------------------------------------------------------------------------------ +vel_schema = None + +#------------------------------------------------------------------------------ +# The JSON schema which we will use to validate client throttle state. +#------------------------------------------------------------------------------ +throttle_schema = None + +#------------------------------------------------------------------------------ +# The JSON schema which we will use to provoke throttling commands for testing. +#------------------------------------------------------------------------------ +test_control_schema = None + +#------------------------------------------------------------------------------ +# Pending command list from the testControl API +# This is sent as a response commandList to the next received event. +#------------------------------------------------------------------------------ +pending_command_list = None + +#------------------------------------------------------------------------------ +# Logger for this module. +#------------------------------------------------------------------------------ +logger = None + +def listener(environ, start_response, schema): + ''' + Handler for the Vendor Event Listener REST API. + + Extract headers and the body and check that: + + 1) The client authenticated themselves correctly. + 2) The body validates against the provided schema for the API. + + ''' + logger.info('Got a Vendor Event request') + print('==== ' + time.asctime() + ' ' + '=' * 49) + + #-------------------------------------------------------------------------- + # Extract the content from the request. + #-------------------------------------------------------------------------- + length = int(environ.get('CONTENT_LENGTH', '0')) + logger.debug('Content Length: {0}'.format(length)) + body = environ['wsgi.input'].read(length) + logger.debug('Content Body: {0}'.format(body)) + + mode, b64_credentials = string.split(environ.get('HTTP_AUTHORIZATION', + 'None None')) + # logger.debug('Auth. Mode: {0} Credentials: {1}'.format(mode, + # b64_credentials)) + logger.debug('Auth. Mode: {0} Credentials: ****'.format(mode)) + if (b64_credentials != 'None'): + credentials = b64decode(b64_credentials) + else: + credentials = None + + # logger.debug('Credentials: {0}'.format(credentials)) + logger.debug('Credentials: ****') + + #-------------------------------------------------------------------------- + # If we have a schema file then check that the event matches that expected. + #-------------------------------------------------------------------------- + if (schema is not None): + logger.debug('Attempting to validate data: {0}\n' + 'Against schema: {1}'.format(body, schema)) + try: + decoded_body = json.loads(body) + jsonschema.validate(decoded_body, schema) + logger.info('Event is valid!') + print('Valid body decoded & checked against schema OK:\n' + '{0}'.format(json.dumps(decoded_body, + sort_keys=True, + indent=4, + separators=(',', ': ')))) + + except jsonschema.SchemaError as e: + logger.error('Schema is not valid! {0}'.format(e)) + print('Schema is not valid! {0}'.format(e)) + + except jsonschema.ValidationError as e: + logger.warn('Event is not valid against schema! {0}'.format(e)) + print('Event is not valid against schema! {0}'.format(e)) + print('Bad JSON body decoded:\n' + '{0}'.format(json.dumps(decoded_body, + sort_keys=True, + indent=4, + separators=(',', ': ')))) + + except Exception as e: + logger.error('Event invalid for unexpected reason! {0}'.format(e)) + print('Schema is not valid for unexpected reason! {0}'.format(e)) + else: + logger.debug('No schema so just decode JSON: {0}'.format(body)) + try: + decoded_body = json.loads(body) + print('Valid JSON body (no schema checking) decoded:\n' + '{0}'.format(json.dumps(decoded_body, + sort_keys=True, + indent=4, + separators=(',', ': ')))) + logger.info('Event is valid JSON but not checked against schema!') + + except Exception as e: + logger.error('Event invalid for unexpected reason! {0}'.format(e)) + print('JSON body not valid for unexpected reason! {0}'.format(e)) + + #-------------------------------------------------------------------------- + # See whether the user authenticated themselves correctly. + #-------------------------------------------------------------------------- + if (credentials == (vel_username + ':' + vel_password)): + logger.debug('Authenticated OK') + print('Authenticated OK') + + #---------------------------------------------------------------------- + # Respond to the caller. If we have a pending commandList from the + # testControl API, send it in response. + #---------------------------------------------------------------------- + global pending_command_list + if pending_command_list is not None: + start_response('202 Accepted', + [('Content-type', 'application/json')]) + response = pending_command_list + pending_command_list = None + + print('\n'+ '='*80) + print('Sending pending commandList in the response:\n' + '{0}'.format(json.dumps(response, + sort_keys=True, + indent=4, + separators=(',', ': ')))) + print('='*80 + '\n') + yield json.dumps(response) + else: + start_response('202 Accepted', []) + yield '' + else: + logger.warn('Failed to authenticate OK') + print('Failed to authenticate agent credentials: ', credentials) + + #---------------------------------------------------------------------- + # Respond to the caller. + #---------------------------------------------------------------------- + start_response('401 Unauthorized', [ ('Content-type', + 'application/json')]) + req_error = { 'requestError': { + 'policyException': { + 'messageId': 'POL0001', + 'text': 'Failed to authenticate' + } + } + } + yield json.dumps(req_error) + + process_event(body) + +#-------------------------------------------------------------------------- +# Event processing +#-------------------------------------------------------------------------- +def process_event(body): + global status + global summary_e + global summary_c + global vdu_id + vdu = 0 + + e = json.loads(body, object_hook=JSONObject) + + epoch = e.event.commonEventHeader.lastEpochMicrosec + sourceId = e.event.commonEventHeader.sourceId + + report_time = time.strftime('%Y-%m-%d %H:%M:%S', + time.localtime(int(epoch)/1000000)) + + host = e.event.commonEventHeader.reportingEntityName + if 'VDU1' in host or 'vdu1' in host: vdu = 1 + if 'VDU2' in host or 'vdu2' in host: vdu = 2 + if 'VDU3' in host or 'vdu3' in host: vdu = 3 + + domain = e.event.commonEventHeader.domain + + if domain == 'measurementsForVfScaling': + if vdu >= 1: + requestRate = e.event.measurementsForVfScalingFields.requestRate + summary_e[vdu] = host + ": state=" + status[vdu] + ", tps=" + str(requestRate) + else: + aggregateCpuUsage = e.event.measurementsForVfScalingFields.aggregateCpuUsage + vNicUsageArray = e.event.measurementsForVfScalingFields.vNicUsageArray + s = "" + for i in range(1,len(vdu_id)): + if sourceId.upper() in vdu_id[i].upper(): + s = "(VDU"+ str(i) + ") " + if s: + s += host + ": cpu=" + str(aggregateCpuUsage) + found = False + for i in range(1,len(summary_c)): + if host in summary_c[i]: + summary_c[i] = s + found = True + break + if not found: + summary_c.extend([s]) + + for s in summary_e: + print '{0}'.format(s) + for s in summary_c: + print '{0}'.format(s) + + if domain == 'fault' and vdu >= 1: + alarmCondition = e.event.faultFields.alarmCondition + specificProblem = e.event.faultFields.specificProblem +# status[vdu] = e.event.faultFields.vfStatus + status[vdu] = e.event.faultFields.specificProblem + +def test_listener(environ, start_response, schema): + ''' + Handler for the Test Collector Test Control API. + + There is no authentication on this interface. + + This simply stores a commandList which will be sent in response to the next + incoming event on the EVEL interface. + ''' + global pending_command_list + logger.info('Got a Test Control input') + print('============================') + print('==== TEST CONTROL INPUT ====') + + #-------------------------------------------------------------------------- + # GET allows us to get the current pending request. + #-------------------------------------------------------------------------- + if environ.get('REQUEST_METHOD') == 'GET': + start_response('200 OK', [('Content-type', 'application/json')]) + yield json.dumps(pending_command_list) + return + + #-------------------------------------------------------------------------- + # Extract the content from the request. + #-------------------------------------------------------------------------- + length = int(environ.get('CONTENT_LENGTH', '0')) + logger.debug('TestControl Content Length: {0}'.format(length)) + body = environ['wsgi.input'].read(length) + logger.debug('TestControl Content Body: {0}'.format(body)) + + #-------------------------------------------------------------------------- + # If we have a schema file then check that the event matches that expected. + #-------------------------------------------------------------------------- + if (schema is not None): + logger.debug('Attempting to validate data: {0}\n' + 'Against schema: {1}'.format(body, schema)) + try: + decoded_body = json.loads(body) + jsonschema.validate(decoded_body, schema) + logger.info('TestControl is valid!') + print('TestControl:\n' + '{0}'.format(json.dumps(decoded_body, + sort_keys=True, + indent=4, + separators=(',', ': ')))) + + except jsonschema.SchemaError as e: + logger.error('TestControl Schema is not valid: {0}'.format(e)) + print('TestControl Schema is not valid: {0}'.format(e)) + + except jsonschema.ValidationError as e: + logger.warn('TestControl input not valid: {0}'.format(e)) + print('TestControl input not valid: {0}'.format(e)) + print('Bad JSON body decoded:\n' + '{0}'.format(json.dumps(decoded_body, + sort_keys=True, + indent=4, + separators=(',', ': ')))) + + except Exception as e: + logger.error('TestControl input not valid: {0}'.format(e)) + print('TestControl Schema not valid: {0}'.format(e)) + else: + logger.debug('Missing schema just decode JSON: {0}'.format(body)) + try: + decoded_body = json.loads(body) + print('Valid JSON body (no schema checking) decoded:\n' + '{0}'.format(json.dumps(decoded_body, + sort_keys=True, + indent=4, + separators=(',', ': ')))) + logger.info('TestControl input not checked against schema!') + + except Exception as e: + logger.error('TestControl input not valid: {0}'.format(e)) + print('TestControl input not valid: {0}'.format(e)) + + #-------------------------------------------------------------------------- + # Respond to the caller. If we received otherField 'ThrottleRequest', + # generate the appropriate canned response. + #-------------------------------------------------------------------------- + pending_command_list = decoded_body + print('===== TEST CONTROL END =====') + print('============================') + start_response('202 Accepted', []) + yield '' + +def main(argv=None): + ''' + Main function for the collector start-up. + + Called with command-line arguments: + * --config ** + * --section *
* + * --verbose + + Where: + + ** specifies the path to the configuration file. + + *
* specifies the section within that config file. + + *verbose* generates more information in the log files. + + The process listens for REST API invocations and checks them. Errors are + displayed to stdout and logged. + ''' + + if argv is None: + argv = sys.argv + else: + sys.argv.extend(argv) + + program_name = os.path.basename(sys.argv[0]) + program_version = 'v{0}'.format(__version__) + program_build_date = str(__updated__) + program_version_message = '%%(prog)s {0} ({1})'.format(program_version, + program_build_date) + if (__import__('__main__').__doc__ is not None): + program_shortdesc = __import__('__main__').__doc__.split('\n')[1] + else: + program_shortdesc = 'Running in test harness' + program_license = '''{0} + + Created on {1}. + Copyright 2015 Metaswitch Networks Ltd. All rights reserved. + + Distributed on an "AS IS" basis without warranties + or conditions of any kind, either express or implied. + +USAGE +'''.format(program_shortdesc, str(__date__)) + + try: + #---------------------------------------------------------------------- + # Setup argument parser so we can parse the command-line. + #---------------------------------------------------------------------- + parser = ArgumentParser(description=program_license, + formatter_class=ArgumentDefaultsHelpFormatter) + parser.add_argument('-v', '--verbose', + dest='verbose', + action='count', + help='set verbosity level') + parser.add_argument('-V', '--version', + action='version', + version=program_version_message, + help='Display version information') + parser.add_argument('-a', '--api-version', + dest='api_version', + default='3', + help='set API version') + parser.add_argument('-c', '--config', + dest='config', + default='/etc/opt/att/collector.conf', + help='Use this config file.', + metavar='') + parser.add_argument('-s', '--section', + dest='section', + default='default', + metavar='
', + help='section to use in the config file') + + #---------------------------------------------------------------------- + # Process arguments received. + #---------------------------------------------------------------------- + args = parser.parse_args() + verbose = args.verbose + api_version = args.api_version + config_file = args.config + config_section = args.section + + #---------------------------------------------------------------------- + # Now read the config file, using command-line supplied values as + # overrides. + #---------------------------------------------------------------------- + defaults = {'log_file': 'collector.log', + 'vel_port': '12233', + 'vel_path': '', + 'vel_topic_name': '' + } + overrides = {} + config = ConfigParser.SafeConfigParser(defaults) + config.read(config_file) + + #---------------------------------------------------------------------- + # extract the values we want. + #---------------------------------------------------------------------- + log_file = config.get(config_section, 'log_file', vars=overrides) + vel_port = config.get(config_section, 'vel_port', vars=overrides) + vel_path = config.get(config_section, 'vel_path', vars=overrides) + vel_topic_name = config.get(config_section, + 'vel_topic_name', + vars=overrides) + global vel_username + global vel_password + vel_username = config.get(config_section, + 'vel_username', + vars=overrides) + vel_password = config.get(config_section, + 'vel_password', + vars=overrides) + vel_schema_file = config.get(config_section, + 'schema_file', + vars=overrides) + base_schema_file = config.get(config_section, + 'base_schema_file', + vars=overrides) + throttle_schema_file = config.get(config_section, + 'throttle_schema_file', + vars=overrides) + test_control_schema_file = config.get(config_section, + 'test_control_schema_file', + vars=overrides) + + #---------------------------------------------------------------------- + # Finally we have enough info to start a proper flow trace. + #---------------------------------------------------------------------- + global logger + print('Logfile: {0}'.format(log_file)) + logger = logging.getLogger('collector') + if verbose > 0: + print('Verbose mode on') + logger.setLevel(logging.DEBUG) + else: + logger.setLevel(logging.INFO) + handler = logging.handlers.RotatingFileHandler(log_file, + maxBytes=1000000, + backupCount=10) + if (platform.system() == 'Windows'): + date_format = '%Y-%m-%d %H:%M:%S' + else: + date_format = '%Y-%m-%d %H:%M:%S.%f %z' + formatter = logging.Formatter('%(asctime)s %(name)s - ' + '%(levelname)s - %(message)s', + date_format) + handler.setFormatter(formatter) + logger.addHandler(handler) + logger.info('Started') + + #---------------------------------------------------------------------- + # Log the details of the configuration. + #---------------------------------------------------------------------- + logger.debug('Log file = {0}'.format(log_file)) + logger.debug('Event Listener Port = {0}'.format(vel_port)) + logger.debug('Event Listener Path = {0}'.format(vel_path)) + logger.debug('Event Listener Topic = {0}'.format(vel_topic_name)) + logger.debug('Event Listener Username = {0}'.format(vel_username)) + # logger.debug('Event Listener Password = {0}'.format(vel_password)) + logger.debug('Event Listener JSON Schema File = {0}'.format( + vel_schema_file)) + logger.debug('Base JSON Schema File = {0}'.format(base_schema_file)) + logger.debug('Throttle JSON Schema File = {0}'.format( + throttle_schema_file)) + logger.debug('Test Control JSON Schema File = {0}'.format( + test_control_schema_file)) + + #---------------------------------------------------------------------- + # Perform some basic error checking on the config. + #---------------------------------------------------------------------- + if (int(vel_port) < 1024 or int(vel_port) > 65535): + logger.error('Invalid Vendor Event Listener port ({0}) ' + 'specified'.format(vel_port)) + raise RuntimeError('Invalid Vendor Event Listener port ({0}) ' + 'specified'.format(vel_port)) + + if (len(vel_path) > 0 and vel_path[-1] != '/'): + logger.warning('Event Listener Path ({0}) should have terminating ' + '"/"! Adding one on to configured string.'.format( + vel_path)) + vel_path += '/' + + #---------------------------------------------------------------------- + # Load up the vel_schema, if it exists. + #---------------------------------------------------------------------- + if not os.path.exists(vel_schema_file): + logger.warning('Event Listener Schema File ({0}) not found. ' + 'No validation will be undertaken.'.format( + vel_schema_file)) + else: + global vel_schema + global throttle_schema + global test_control_schema + vel_schema = json.load(open(vel_schema_file, 'r')) + logger.debug('Loaded the JSON schema file') + + #------------------------------------------------------------------ + # Load up the throttle_schema, if it exists. + #------------------------------------------------------------------ + if (os.path.exists(throttle_schema_file)): + logger.debug('Loading throttle schema') + throttle_fragment = json.load(open(throttle_schema_file, 'r')) + throttle_schema = {} + throttle_schema.update(vel_schema) + throttle_schema.update(throttle_fragment) + logger.debug('Loaded the throttle schema') + + #------------------------------------------------------------------ + # Load up the test control _schema, if it exists. + #------------------------------------------------------------------ + if (os.path.exists(test_control_schema_file)): + logger.debug('Loading test control schema') + test_control_fragment = json.load( + open(test_control_schema_file, 'r')) + test_control_schema = {} + test_control_schema.update(vel_schema) + test_control_schema.update(test_control_fragment) + logger.debug('Loaded the test control schema') + + #------------------------------------------------------------------ + # Load up the base_schema, if it exists. + #------------------------------------------------------------------ + if (os.path.exists(base_schema_file)): + logger.debug('Updating the schema with base definition') + base_schema = json.load(open(base_schema_file, 'r')) + vel_schema.update(base_schema) + logger.debug('Updated the JSON schema file') + + #---------------------------------------------------------------------- + # We are now ready to get started with processing. Start-up the various + # components of the system in order: + # + # 1) Create the dispatcher. + # 2) Register the functions for the URLs of interest. + # 3) Run the webserver. + #---------------------------------------------------------------------- + root_url = '/{0}eventListener/v{1}{2}'.\ + format(vel_path, + api_version, + '/' + vel_topic_name + if len(vel_topic_name) > 0 + else '') + throttle_url = '/{0}eventListener/v{1}/clientThrottlingState'.\ + format(vel_path, api_version) + set_404_content(root_url) + dispatcher = PathDispatcher() + vendor_event_listener = partial(listener, schema = vel_schema) + dispatcher.register('GET', root_url, vendor_event_listener) + dispatcher.register('POST', root_url, vendor_event_listener) + vendor_throttle_listener = partial(listener, schema = throttle_schema) + dispatcher.register('GET', throttle_url, vendor_throttle_listener) + dispatcher.register('POST', throttle_url, vendor_throttle_listener) + + #---------------------------------------------------------------------- + # We also add a POST-only mechanism for test control, so that we can + # send commands to a single attached client. + #---------------------------------------------------------------------- + test_control_url = '/testControl/v{0}/commandList'.format(api_version) + test_control_listener = partial(test_listener, + schema = test_control_schema) + dispatcher.register('POST', test_control_url, test_control_listener) + dispatcher.register('GET', test_control_url, test_control_listener) + + httpd = make_server('', int(vel_port), dispatcher) + print('Serving on port {0}...'.format(vel_port)) + httpd.serve_forever() + + logger.error('Main loop exited unexpectedly!') + return 0 + + except KeyboardInterrupt: + #---------------------------------------------------------------------- + # handle keyboard interrupt + #---------------------------------------------------------------------- + logger.info('Exiting on keyboard interrupt!') + return 0 + + except Exception as e: + #---------------------------------------------------------------------- + # Handle unexpected exceptions. + #---------------------------------------------------------------------- + if DEBUG or TESTRUN: + raise(e) + indent = len(program_name) * ' ' + sys.stderr.write(program_name + ': ' + repr(e) + '\n') + sys.stderr.write(indent + ' for help use --help\n') + sys.stderr.write(traceback.format_exc()) + logger.critical('Exiting because of exception: {0}'.format(e)) + logger.critical(traceback.format_exc()) + return 2 + +#------------------------------------------------------------------------------ +# MAIN SCRIPT ENTRY POINT. +#------------------------------------------------------------------------------ +if __name__ == '__main__': + if TESTRUN: + #---------------------------------------------------------------------- + # Running tests - note that doctest comments haven't been included so + # this is a hook for future improvements. + #---------------------------------------------------------------------- + import doctest + doctest.testmod() + + if PROFILE: + #---------------------------------------------------------------------- + # Profiling performance. Performance isn't expected to be a major + # issue, but this should all work as expected. + #---------------------------------------------------------------------- + import cProfile + import pstats + profile_filename = 'collector_profile.txt' + cProfile.run('main()', profile_filename) + statsfile = open('collector_profile_stats.txt', 'wb') + p = pstats.Stats(profile_filename, stream=statsfile) + stats = p.strip_dirs().sort_stats('cumulative') + stats.print_stats() + statsfile.close() + sys.exit(0) + + #-------------------------------------------------------------------------- + # Normal operation - call through to the main function. + #-------------------------------------------------------------------------- + sys.exit(main()) diff --git a/tests/onap-demo/blueprints/tosca-vnfd-onap-demo/start.sh b/tests/onap-demo/blueprints/tosca-vnfd-onap-demo/start.sh new file mode 100644 index 0000000..0f27dd3 --- /dev/null +++ b/tests/onap-demo/blueprints/tosca-vnfd-onap-demo/start.sh @@ -0,0 +1,224 @@ +#!/bin/bash +# Copyright 2016 AT&T Intellectual Property, Inc +# +# 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. +# +# What this is: Startup script for a simple web server as part of the +# ves_onap_demo test of the OPNFV VES project. +# +# Status: this is a work in progress, under test. +# +# How to use: +# Intended to be invoked from ves_onap_demo.sh +# $ bash start.sh type params +# type: type of VNF component [monitor|collectd] +# collector params: ID CollectorIP username password +# monitor params: VDU1_ID VDU1_ID VDU1_ID username password +# ID: VM ID +# CollectorIP: IP address of the collector +# username: Username for Collector RESTful API authentication +# password: Password for Collector RESTful API authentication + +setup_collectd () { + guest=$1 + echo "$0: Install prerequisites" + dist=`grep DISTRIB_ID /etc/*-release | awk -F '=' '{print $2}'` + if [ "$dist" == "Ubuntu" ]; then + conf="/etc/collectd/collectd.conf" + else + conf="/etc/collectd.conf" + fi + + if [ "$dist" == "Ubuntu" ]; then + sudo apt-get update + sudo apt-get install -y collectd + else + sudo yum update -y + sudo yum install -y epel-release + sudo yum install -y collectd + sudo yum install -y collectd-virt + fi + cd ~ + + echo "$0: Install VES collectd plugin" + git clone https://git.opnfv.org/barometer + sudo sed -i -- "s/v1/v3/" barometer/3rd_party/collectd-ves-plugin/ves_plugin/ves_plugin.py + + sudo sed -i -- "s/FQDNLookup true/FQDNLookup false/" $conf + sudo sed -i -- "s/#LoadPlugin cpu/LoadPlugin cpu/" $conf + sudo sed -i -- "s/#LoadPlugin disk/LoadPlugin disk/" $conf + sudo sed -i -- "s/#LoadPlugin interface/LoadPlugin interface/" $conf + sudo sed -i -- "s/#LoadPlugin memory/LoadPlugin memory/" $conf + + if [[ "$guest" == true ]]; then + cat < + Globals true + + + ModulePath "/home/$USER/barometer/3rd_party/collectd-ves-plugin/ves_plugin/" + LogTraces true + Interactive false + Import "ves_plugin" + + Domain "$collector_ip" + Port 30000 + Path "" + Topic "" + UseHttps false + Username "hello" + Password "world" + FunctionalRole "Collectd VES Agent" + GuestRunning true + + + + ReportByCpu false + ValuesPercentage true + +LoadPlugin aggregation + + + Plugin "cpu" + Type "percent" + GroupBy "Host" + GroupBy "TypeInstance" + SetPlugin "cpu-aggregation" + CalculateAverage true + + +LoadPlugin uuid +EOF + else + cat < + Globals true + + + ModulePath "/home/$USER/barometer/3rd_party/collectd-ves-plugin/ves_plugin/" + LogTraces true + Interactive false + Import "ves_plugin" + + Domain "$collector_ip" + Port 30000 + Path "" + Topic "" + UseHttps false + Username "hello" + Password "world" + FunctionalRole "Collectd VES Agent" + GuestRunning false + + +LoadPlugin virt + + Connection "qemu:///system" + RefreshInterval 60 + HostnameFormat uuid + + + ReportByCpu false + ValuesPercentage true + +LoadPlugin aggregation + + + Plugin "cpu" + Type "percent" + GroupBy "Host" + GroupBy "TypeInstance" + SetPlugin "cpu-aggregation" + CalculateAverage true + + +LoadPlugin uuid +EOF + fi + sudo service collectd restart +} + +setup_agent () { + echo "$0: Install prerequisites" + sudo apt-get install -y gcc + # NOTE: force is required as some packages can't be authenticated... + sudo apt-get install -y --force-yes libcurl4-openssl-dev + sudo apt-get install -y make + + echo "$0: Clone agent library" + cd /home/ubuntu + git clone https://github.com/att/evel-library.git + + echo "$0: Clone VES repo" + git clone https://gerrit.opnfv.org/gerrit/ves + + echo "$0: Use ves_onap_demo blueprint version of agent_demo.c" + cp ves/tests/blueprints/tosca-vnfd-onap-demo/evel_demo.c evel-library/code/evel_demo/evel_demo.c + + echo "$0: Build evel_demo agent" + cd evel-library/bldjobs + make + export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/ubuntu/evel-library/libs/x86_64 + + echo "$0: Start evel_demo agent" + id=$(cut -d ',' -f 3 /mnt/openstack/latest/meta_data.json | cut -d '"' -f 4) + nohup ../output/x86_64/evel_demo --id $id --fqdn $collector_ip --port 30000 --username $username --password $password -x > /dev/null 2>&1 & + + echo "$0: Start collectd agent running in the VM" + setup_collectd true +} + +setup_monitor () { + echo "$0: setup VES Monitor" + echo "$0: install dependencies" + # Note below: python (2.7) is required due to dependency on module 'ConfigParser' + sudo apt-get update + sudo apt-get upgrade -y + sudo apt-get install -y python python-jsonschema + + echo "$0: setup VES Monitor config" + sudo mkdir /var/log/att + sudo chown ubuntu /var/log/att + touch /var/log/att/collector.log + sudo chown ubuntu /home/ubuntu/ + cd /home/ubuntu/ + git clone https://github.com/att/evel-test-collector.git + sed -i -- "s/vel_username = /vel_username = $username/" evel-test-collector/config/collector.conf + sed -i -- "s/vel_password = /vel_password = $password/" evel-test-collector/config/collector.conf + sed -i -- "s~vel_path = vendor_event_listener/~vel_path = ~" evel-test-collector/config/collector.conf + sed -i -- "s/vel_topic_name = example_vnf/vel_topic_name = /" evel-test-collector/config/collector.conf + sed -i -- "/vel_topic_name = /a vdu3_id = $vdu3_id" evel-test-collector/config/collector.conf + sed -i -- "/vel_topic_name = /a vdu2_id = $vdu2_id" evel-test-collector/config/collector.conf + sed -i -- "/vel_topic_name = /a vdu1_id = $vdu1_id" evel-test-collector/config/collector.conf + + cp monitor.py evel-test-collector/code/collector/monitor.py + nohup python evel-test-collector/code/collector/monitor.py --config evel-test-collector/config/collector.conf --section default > /home/ubuntu/monitor.log +} + +type=$1 + +if [[ "$type" == "monitor" ]]; then + vdu1_id=$2 + vdu2_id=$3 + vdu3_id=$4 + username=$5 + password=$6 +else + vm_id=$2 + collector_ip=$3 + username=$4 + password=$5 +fi + +setup_$type $1 +exit 0 diff --git a/tests/onap-demo/ves_onap_demo.sh b/tests/onap-demo/ves_onap_demo.sh new file mode 100644 index 0000000..c4ee2e4 --- /dev/null +++ b/tests/onap-demo/ves_onap_demo.sh @@ -0,0 +1,599 @@ +#!/bin/bash +# Copyright 2016-2017 AT&T Intellectual Property, Inc +# +# 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. +# +# What this is: Deployment test for the VES agent and collector based +# upon the Tacker Hello World blueprint, designed as a manual demo of the VES +# concept using ONAP VNFs and integrating with the Barometer project collectd +# agent. +# Typical demo procedure is to execute the following actions from the OPNFV +# jumphost or some host wth access to the OpenStack controller +# (see below for details): +# setup: install Tacker in a Docker container. Note: only needs to be done +# once per session and can be reused across OPNFV VES and Models tests, +# i.e. you can start another test at the "start" step below. +# start: install blueprint and start the VNF, including the app (load-balanced +# web server) and VES agents running on the VMs. Installs the VES +# monitor code but does not start the monitor (see below). +# start_collectd: start the collectd daemon on bare metal hypervisor hosts +# monitor: start the VES monitor, typically run in a second shell session. +# pause: pause the app at one of the web server VDUs (VDU1 or VDU2) +# stop: stop the VNF and uninstall the blueprint +# start_collectd: start the collectd daemon on bare metal hypervisor hosts +# clean: remove the tacker container and service (if desired, when done) +# +# +# Note: if you want to try this on DevStack, your DevStack VM needs at minimum +# 20 GB RAM and 20 GB hard drive. +# +# +# Status: this is a work in progress, under test. +# +# How to use: +# $ git clone https://gerrit.opnfv.org/gerrit/ves +# $ cd ves/tests/onap-demo +# $ bash ves_onap_demo.sh setup [branch] +# setup: setup test environment +# : location of OpenStack openrc file +# branch: OpenStack branch of Tacker to install (default: master) +# $ bash ves_onap_demo.sh start +# start: install blueprint and run test +# $ bash ves_onap_demo.sh start_collectd|stop_collectd +# start_collectd: install and start collectd daemon on hypervisor +# stop_collectd: stop and uninstall collectd daemon on hypervisor +# : hypervisor ip +# : username on hypervisor hosts, for ssh (user must be setup for +# key-based auth on the hosts) +# : IP address of VES monitor +# $ bash ves_onap_demo.sh monitor +# monitor: attach to the collector VM and run the VES Monitor +# : IP address of VDU4 (monitor VM) +# $ bash ves_onap_demo.sh traffic +# traffic: generate some traffic +# : address of server +# $ bash ves_onap_demo.sh pause +# pause: pause the VNF (web server) for a minute to generate a state change +# : address of server +# $ bash ves_onap_demo.sh stop +# stop: stop test and uninstall blueprint +# $ bash ves_onap_demo.sh clean +# clean: cleanup after test +# : username on hypervisor +# : password on hypervisor + +trap 'fail' ERR + +pass() { + echo "$0: $(date) Hooray!" + end=`date +%s` + runtime=$((end-test_start)) + echo "$0: $(date) Test Duration = $runtime seconds" + exit 0 +} + +fail() { + echo "$0: $(date) Test Failed!" + end=`date +%s` + runtime=$((end-test_start)) + runtime=$((runtime/60)) + echo "$0: $(date) Test Duration = $runtime seconds" + exit 1 +} + +assert() { + if [[ $2 == true ]]; then echo "$0 test assertion passed: $1" + else + echo "$0 test assertion failed: $1" + fail + fi +} + +get_floating_net () { + echo "$0: $(date) get_floating_net start" + network_ids=($(neutron net-list | grep -v "+" | grep -v name | awk '{print $2}')) + for id in "${network_ids[@]}"; do + [[ $(neutron net-show ${id} | grep 'router:external' | grep -i "true") != "" ]] && FLOATING_NETWORK_ID=${id} + done + if [[ $FLOATING_NETWORK_ID ]]; then + FLOATING_NETWORK_NAME=$(neutron net-show $FLOATING_NETWORK_ID | awk "/ name / { print \$4 }") + echo "$0: $(date) floating network name is $FLOATING_NETWORK_NAME" + else + echo "$0: $(date) Floating network not found" + exit 1 + fi + echo "$0: $(date) get_floating_net end" +} + +try () { + count=$1 + $3 + while [[ $? == 1 && $count -gt 0 ]]; do + sleep $2 + let count=$count-1 + $3 + done + if [[ $count -eq 0 ]]; then echo "$0: $(date) Command \"$3\" was not successful after $1 tries"; fi +} + +setup () { + trap 'fail' ERR + + echo "$0: $(date) Setup shared test folder /opt/tacker" + if [ -d /opt/tacker ]; then sudo rm -rf /opt/tacker; fi + sudo mkdir -p /opt/tacker + sudo chown $USER /opt/tacker + chmod 777 /opt/tacker/ + + echo "$0: $(date) copy test script and openrc to /opt/tacker" + cp $0 /opt/tacker/. + cp $1 /opt/tacker/admin-openrc.sh + + source /opt/tacker/admin-openrc.sh + chmod 755 /opt/tacker/*.sh + + echo "$0: $(date) tacker-setup part 1 fetching script from Models" + wget https://git.opnfv.org/models/plain/tests/utils/tacker-setup.sh -O /tmp/tacker-setup.sh + bash /tmp/tacker-setup.sh init + if [ $? -eq 1 ]; then fail; fi + + echo "$0: $(date) tacker-setup part 2" + dist=`grep DISTRIB_ID /etc/*-release | awk -F '=' '{print $2}'` + if [ "$dist" == "Ubuntu" ]; then + echo "$0: $(date) Execute tacker-setup.sh in the container" + sudo docker exec -it tacker /bin/bash /opt/tacker/tacker-setup.sh setup $2 + if [ $? -eq 1 ]; then fail; fi + else + echo "$0: $(date) Execute tacker-setup.sh in the container" + sudo docker exec -i -t tacker /bin/bash /opt/tacker/tacker-setup.sh setup $2 + if [ $? -eq 1 ]; then fail; fi + fi + + assert "ves-onap-demo-tacker-001 (Tacker installation in a Docker container on the jumphost)" true +} + +say_hello() { + echo "$0: $(date) Testing $1" + pass=false + count=10 + while [[ $count -gt 0 && $pass != true ]] + do + sleep 30 + let count=$count-1 + if [[ $(curl $1 | grep -c "Hello World") -gt 0 ]]; then + echo "$0: $(date) Hello World found at $1" + pass=true + fi + done + if [[ $pass != true ]]; then fail; fi +} + +copy_blueprint() { + echo "$0: $(date) copy test script to /opt/tacker" + cp $0 /opt/tacker/. + + echo "$0: $(date) reset blueprints folder" + if [[ -d /opt/tacker/blueprints/tosca-vnfd-onap-demo ]]; then + rm -rf /opt/tacker/blueprints/tosca-vnfd-onap-demo + fi + + echo "$0: $(date) copy tosca-vnfd-onap-demo to blueprints folder" + if [[ ! -d /opt/tacker/blueprints ]]; then mkdir /opt/tacker/blueprints; fi + cp -r blueprints/tosca-vnfd-onap-demo /opt/tacker/blueprints/tosca-vnfd-onap-demo +} + +start() { +# Disable trap for now, need to test to ensure premature fail does not occur +# trap 'fail' ERR + + echo "$0: $(date) setup OpenStack CLI environment" + source /opt/tacker/admin-openrc.sh + + echo "$0: $(date) create flavor to use in blueprint" + openstack flavor create onap.demo --id auto --ram 1024 --disk 3 --vcpus 1 + + echo "$0: $(date) Create Nova key pair" + if [[ -f /opt/tacker/onap-demo ]]; then rm /opt/tacker/onap-demo; fi + ssh-keygen -t rsa -N "" -f /opt/tacker/onap-demo -C ubuntu@onap-demo + chmod 600 /opt/tacker/onap-demo + openstack keypair create --public-key /opt/tacker/onap-demo.pub onap-demo + assert "onap-demo-nova-001 (Keypair creation)" true + + echo "$0: $(date) Inject public key into blueprint" + pubkey=$(cat /opt/tacker/onap-demo.pub) + sed -i -- "s~~$pubkey~" /opt/tacker/blueprints/tosca-vnfd-onap-demo/blueprint.yaml + + vdus="VDU1 VDU2 VDU3 VDU4" + vdui="1 2 3 4" + vnf_vdui="1 2 3" + declare -a vdu_id=() + declare -a vdu_ip=() + declare -a vdu_url=() + + # Setup for workarounds + echo "$0: $(date) allocate floating IPs no loop no array assignment" + get_floating_net + + # stack@us16-newton:~$ (openstack floating ip create public | awk "NR==7 { print \$4 }") + # 172.24.4.11 + # stack@us16-newton:~$ (openstack floating ip create public | awk "/floating_ip_address/ { print \$4 }") + # 172.24.4.7 + + for i in $vdui; do + vdu_ip[$i]=$(nova floating-ip-create $FLOATING_NETWORK_NAME | awk "/$FLOATING_NETWORK_NAME/ { print \$4 }") + echo "$0: $(date) Pre-allocated ${vdu_ip[$i]} to VDU$i" + done + + + echo "$0: $(date) Inject web server floating IPs into LB code in blueprint" + sed -i -- "s//${vdu_ip[1]}/" /opt/tacker/blueprints/tosca-vnfd-onap-demo/blueprint.yaml + sed -i -- "s//${vdu_ip[1]}/" /opt/tacker/blueprints/tosca-vnfd-onap-demo/blueprint.yaml + # End setup for workarounds + + echo "$0: $(date) create VNFD named onap-demo-vnfd" + cd /opt/tacker/blueprints/tosca-vnfd-onap-demo + # newton: NAME (was "--name") is now a positional parameter + tacker vnfd-create --vnfd-file blueprint.yaml onap-demo-vnfd + if [[ $? -eq 0 ]]; then + assert "onap-demo-tacker-002 (VNFD creation onap-demo-vnfd)" true + else + assert "onap-demo-tacker-002 (VNFD creation onap-demo-vnfd)" false + fi + + echo "$0: $(date) create VNF named onap-demo-vnf" + # newton: NAME (was "--name") is now a positional parameter + tacker vnf-create --vnfd-name onap-demo-vnfd onap-demo-vnf + if [ $? -eq 1 ]; then fail; fi + + echo "$0: $(date) wait for onap-demo-vnf to go ACTIVE" + active="" + count=24 + while [[ -z $active && $count -gt 0 ]] + do + active=$(tacker vnf-show onap-demo-vnf | grep ACTIVE) + if [[ $(tacker vnf-show onap-demo-vnf | grep -c ERROR) -gt 0 ]]; then + echo "$0: $(date) onap-demo-vnf VNF creation failed with state ERROR" + assert "onap-demo-tacker-002 (onap-demo-vnf creation)" false + fi + let count=$count-1 + sleep 30 + echo "$0: $(date) wait for onap-demo-vnf to go ACTIVE" + done + if [[ $count == 0 ]]; then + echo "$0: $(date) onap-demo-vnf VNF creation failed - timed out" + assert "onap-demo-tacker-002 (VNF creation)" false + fi + + # Setup for workarounds + echo "$0: $(date) directly set port security on ports (unsupported in Mitaka Tacker)" + # Alternate method + # HEAT_ID=$(tacker vnf-show onap-demo-vnfd | awk "/instance_id/ { print \$4 }") + # SERVER_ID=$(openstack stack resource list $HEAT_ID | awk "/VDU1 / { print \$4 }") + for vdu in $vdus; do + echo "$0: $(date) Setting port security on $vdu" + SERVER_ID=$(openstack server list | awk "/$vdu/ { print \$2 }") + id=($(neutron port-list -F id -f value)) + for id in "${id[@]}"; do + if [[ $(neutron port-show $id | grep $SERVER_ID) ]]; then neutron port-update ${id} --port-security-enabled=True; fi + done + done + + echo "$0: $(date) directly assign security group (unsupported in Mitaka Tacker)" + if [[ $(neutron security-group-list | awk "/ onap-demo / { print \$2 }") ]]; then neutron security-group-delete onap-demo; fi + neutron security-group-create onap-demo + neutron security-group-rule-create --direction ingress --protocol TCP --port-range-min 22 --port-range-max 22 onap-demo + neutron security-group-rule-create --direction ingress --protocol TCP --port-range-min 80 --port-range-max 80 onap-demo + neutron security-group-rule-create --direction ingress --protocol TCP --port-range-min 30000 --port-range-max 30000 onap-demo + for i in $vdui; do + vdu_id[$i]=$(openstack server list | awk "/VDU$i/ { print \$2 }") + echo "$0: $(date) Assigning security groups to VDU$i (${vdu_id[$i]})" + openstack server add security group ${vdu_id[$i]} onap-demo + openstack server add security group ${vdu_id[$i]} default + done + + echo "$0: $(date) associate floating IPs" + # openstack server add floating ip INSTANCE_NAME_OR_ID FLOATING_IP_ADDRESS + for i in $vdui; do + openstack server add floating ip ${vdu_id[$i]} ${vdu_ip[$i]} + done + + echo "$0: $(date) get web server addresses" + vdu_url[1]="http://${vdu_ip[1]}" + vdu_url[2]="http://${vdu_ip[2]}" + vdu_url[3]="http://${vdu_ip[3]}" + vdu_url[4]="http://${vdu_ip[4]}:30000/eventListener/v3" + + apt-get install -y curl + + echo "$0: $(date) wait for VNF web service to be ready" + count=0 + resp=$(curl http://${vdu_ip[1]}) + echo $resp + while [[ $count -gt 10 && "$resp" == "" ]]; do + echo "$0: $(date) waiting for HTTP response from LB" + sleep 60 + let count=$count+1 + resp=$(curl http://${vdu_ip[3]}) + echo $resp + done + + echo "$0: $(date) verify onap-demo server is running at each web server and via the LB" + say_hello http://${vdu_ip[1]} + say_hello http://${vdu_ip[2]} + say_hello http://${vdu_ip[3]} + + assert "onap-demo-onap-demo-vnf-001 (onap-demo VNF creation)" true + assert "onap-demo-tacker-003 (VNF creation)" true + assert "onap-demo-tacker-vnfd-002 (artifacts creation)" true + assert "onap-demo-tacker-vnfd-003 (user_data creation)" true + + echo "$0: $(date) setup Monitor in VDU4 at ${vdu_ip[4]}" + scp -i /opt/tacker/onap-demo -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no /opt/tacker/blueprints/tosca-vnfd-onap-demo/start.sh ubuntu@${vdu_ip[4]}:/home/ubuntu/start.sh + scp -i /opt/tacker/onap-demo -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no /opt/tacker/blueprints/tosca-vnfd-onap-demo/monitor.py ubuntu@${vdu_ip[4]}:/home/ubuntu/monitor.py + ssh -i /opt/tacker/onap-demo -x -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ubuntu@${vdu_ip[4]} "nohup bash /home/ubuntu/start.sh monitor ${vdu_id[1]} ${vdu_id[2]} ${vdu_id[3]} hello world > /dev/null 2>&1 &" + + echo "$0: $(date) Execute agent startup script in the VNF VMs" + for i in $vnf_vdui; do + ssh -i /opt/tacker/onap-demo -x -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ubuntu@${vdu_ip[$i]} "sudo chown ubuntu /home/ubuntu" + scp -i /opt/tacker/onap-demo -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no /opt/tacker/blueprints/tosca-vnfd-onap-demo/start.sh ubuntu@${vdu_ip[$i]}:/home/ubuntu/start.sh + ssh -i /opt/tacker/onap-demo -x -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no \ + ubuntu@${vdu_ip[$i]} "nohup bash /home/ubuntu/start.sh agent ${vdu_id[$i]} ${vdu_ip[4]} hello world > /dev/null 2>&1 &" + done + + echo "$0: $(date) Startup complete. VDU addresses:" + echo "web server 1: ${vdu_ip[1]}" + echo "web server 2: ${vdu_ip[2]}" + echo "load balancer: ${vdu_ip[3]}" + echo "monitor : ${vdu_ip[4]}" +} + +stop() { + trap 'fail' ERR + + echo "$0: $(date) setup OpenStack CLI environment" + source /opt/tacker/admin-openrc.sh + + if [[ "$(tacker vnf-list | grep onap-demo-vnf | awk '{print $2}')" != '' ]]; then + echo "$0: $(date) uninstall onap-demo-vnf blueprint via CLI" + try 12 10 "tacker vnf-delete onap-demo-vnf" + # It can take some time to delete a VNF - thus wait 2 minutes + count=12 + while [[ $count -gt 0 && "$(tacker vnf-list | grep onap-demo-vnfd | awk '{print $2}')" != '' ]]; do + echo "$0: $(date) waiting for onap-demo-vnf VNF delete to complete" + sleep 10 + let count=$count-1 + done + if [[ "$(tacker vnf-list | grep onap-demo-vnf | awk '{print $2}')" == '' ]]; then + assert "onap-demo-tacker-004 (VNF onap-demo-vnf deletion)" true + else + assert "onap-demo-tacker-004 (VNF onap-demo-vnf deletion)" false + fi + fi + + # It can take some time to delete a VNFD - thus wait 2 minutes + if [[ "$(tacker vnfd-list | grep onap-demo-vnfd | awk '{print $2}')" != '' ]]; then + echo "$0: $(date) trying to delete the onap-demo-vnfd VNFD" + try 12 10 "tacker vnfd-delete onap-demo-vnfd" + if [[ "$(tacker vnfd-list | grep onap-demo-vnfd | awk '{print $2}')" == '' ]]; then + assert "onap-demo-tacker-005 (VNFD deletion onap-demo-vnfd)" true + else + assert "onap-demo-tacker-005 (VNFD deletion onap-demo-vnfd)" false + fi + fi + +# This part will apply for tests that dynamically create the VDU base image +# iid=($(openstack image list|grep VNFImage|awk '{print $2}')); for id in ${iid[@]}; do openstack image delete ${id}; done +# if [[ "$(openstack image list|grep VNFImage|awk '{print $2}')" == '' ]]; then +# assert "models-tacker-vnfd-004 (artifacts deletion)" true +# else +# assert "models-tacker-vnfd-004 (artifacts deletion)" false +# fi + + # Cleanup for workarounds + fip=($(neutron floatingip-list | grep -v "+" | grep -v id | awk '{print $2}')); for id in "${fip[@]}"; do neutron floatingip-delete ${id}; done + sg=($(openstack security group list | grep onap-demo |awk '{print $2}')) + for id in "${sg[@]}"; do try 5 5 "openstack security group delete ${id}"; done + kid=($(openstack keypair list | grep onap-demo | awk '{print $2}')); for id in "${kid[@]}"; do openstack keypair delete ${id}; done + + openstack flavor delete onap.demo +} + +start_collectd() { + # NOTE: ensure hypervisor hostname is resolvable e.g. thru /etc/hosts + echo "$0: $(date) update start.sh script in case it changed" + cp -r blueprints/tosca-vnfd-onap-demo/start.sh /opt/tacker/blueprints/tosca-vnfd-onap-demo + echo "$0: $(date) start collectd agent on bare metal hypervisor host" + scp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no /opt/tacker/blueprints/tosca-vnfd-onap-demo/start.sh $2@$1:/home/$2/start.sh + ssh -x -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no $2@$1 \ + "nohup bash /home/$2/start.sh collectd $1 $3 hello world > /dev/null 2>&1 &" +} + +stop_collectd() { + echo "$0: $(date) remove collectd agent on bare metal hypervisor hosts" + ssh -x -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no $2@$1 <<'EOF' +dist=`grep DISTRIB_ID /etc/*-release | awk -F '=' '{print $2}'` +if [ "$dist" == "Ubuntu" ]; then + sudo service collectd stop + sudo apt-get remove -y collectd +else + sudo service collectd stop + sudo yum remove -y collectd collectd-virt +fi +rm -rf $HOME/barometer +EOF +} + +# +# Test tools and scenarios +# + +get_vdu_ip () { + source /opt/tacker/admin-openrc.sh + + echo "$0: $(date) find VM IP for $1" + ip=$(openstack server list | awk "/$1/ { print \$10 }") +} + +monitor () { + echo "$0: $(date) Start the VES Monitor in VDU4 - Stop first if running" + sudo ssh -t -t -i /opt/tacker/onap-demo -x -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ubuntu@$1 << 'EOF' +sudo kill $(ps -ef | grep evel-test-collector | awk '{print $2}') +nohup python evel-test-collector/code/collector/monitor.py --config evel-test-collector/config/collector.conf --section default > /home/ubuntu/monitor.log & +tail -f monitor.log +EOF +} + +traffic () { + echo "$0: $(date) Generate some traffic, somewhat randomly" + ns="0 00 000" + while true + do + for n in $ns; do + sleep .$n$[ ( $RANDOM % 10 ) + 1 ]s + curl -s http://$1 > /dev/null + done + done +} + +pause () { + echo "$0: $(date) Pause the VNF (web server) in $1 for 30 seconds to generate a state change fault report (Stopped)" + $1 + sudo ssh -t -t -i /opt/tacker/onap-demo -x -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ubuntu@$1 "sudo docker pause onap-demo" + sleep 20 + echo "$0: $(date) Unpausing the VNF to generate a state change fault report (Started)" + sudo ssh -t -t -i /opt/tacker/onap-demo -x -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ubuntu@$1 "sudo docker unpause onap-demo" +} + +forward_to_container () { + echo "$0: $(date) pass $1 command to ves_onap_demo in tacker container" + sudo docker exec tacker /bin/bash /opt/tacker/ves_onap_demo.sh $1 + if [ $? -eq 1 ]; then fail; fi +} + +dist=`grep DISTRIB_ID /etc/*-release | awk -F '=' '{print $2}'` +case "$1" in + setup) + setup $2 $3 + if [ $? -eq 1 ]; then fail; fi + pass + ;; + run) + setup $2 $3 + copy_blueprint + forward_to_container start + if [ $? -eq 1 ]; then fail; fi + pass + ;; + start) + if [[ -f /.dockerenv ]]; then + start + else + copy_blueprint + forward_to_container start + fi + pass + ;; + start_collectd) + start_collectd $2 $3 $4 + if [ $? -eq 1 ]; then fail; fi + pass + ;; + stop_collectd) + stop_collectd $2 $3 + if [ $? -eq 1 ]; then fail; fi + pass + ;; + monitor) + monitor $2 + if [ $? -eq 1 ]; then fail; fi + pass + ;; + traffic) + traffic $2 + pass + ;; + pause) + pause $2 + ;; + stop) + if [[ -f /.dockerenv ]]; then + stop + else + forward_to_container stop + fi + if [ $? -eq 1 ]; then fail; fi + pass + ;; + clean) + echo "$0: $(date) Uninstall Tacker and test environment" + sudo docker exec -it tacker /bin/bash /opt/tacker/tacker-setup.sh clean + sudo docker stop tacker + sudo docker rm -v tacker + sudo rm -rf /opt/tacker + pass + ;; + *) + cat < [branch] + setup: setup test environment + : location of OpenStack openrc file + branch: OpenStack branch to install (default: master) + $ bash ves_onap_demo.sh start + start: install blueprint and run test + : username on hypervisor hosts, for ssh (user must be setup for + key-based auth on the hosts) + $ bash ves_onap_demo.sh start_collectd|stop_collectd + start_collectd: install and start collectd daemon on hypervisor + stop_collectd: stop and uninstall collectd daemon on hypervisor + : hypervisor ip + : username on hypervisor hosts, for ssh (user must be setup for + key-based auth on the hosts) + : IP address of VES monitor + $ bash ves_onap_demo.sh monitor + monitor: attach to the collector VM and run the VES Monitor + : IP address of VDU4 (monitor VM) + $ bash ves_onap_demo.sh traffic + traffic: generate some traffic + : address of server + $ bash ves_onap_demo.sh pause + pause: pause the VNF (web server) for a minute to generate a state change + : address of server + $ bash ves_onap_demo.sh stop + stop: stop test and uninstall blueprint + $ bash ves_onap_demo.sh clean + clean: cleanup after test + : username on hypervisor hosts, for ssh (user must be setup for + key-based auth on the hosts) +EOF +esac -- cgit 1.2.3-korg