X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=blobdiff_plain;f=ntsimulator%2Fsrc%2Fntsimulator-manager%2Fntsimulator-manager.c;fp=ntsimulator%2Fsrc%2Fntsimulator-manager%2Fntsimulator-manager.c;h=1e95497486b6c9a59bd658ce8ced2ea15404e96e;hb=29ce368a8b49cb41f3a1640581ff9958ea50ad8c;hp=0000000000000000000000000000000000000000;hpb=1d6c03fcfde03df735f82913ea795a75cd3068d9;p=sim%2Fo1-interface.git diff --git a/ntsimulator/src/ntsimulator-manager/ntsimulator-manager.c b/ntsimulator/src/ntsimulator-manager/ntsimulator-manager.c new file mode 100644 index 0000000..1e95497 --- /dev/null +++ b/ntsimulator/src/ntsimulator-manager/ntsimulator-manager.c @@ -0,0 +1,578 @@ +/* + * core-model.c + * + * Created on: Feb 19, 2019 + * Author: parallels + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include "sysrepo.h" +#include "sysrepo/values.h" + +#include "utils.h" +#include "simulator-operations.h" + +volatile int exit_application = 0; + +volatile unsigned int simulated_devices_config = 0; +volatile unsigned int mounted_devices_config = 0; + + +static device_stack_t *device_list = NULL; + +controller_t controller_details; + +#define XPATH_MAX_LEN 500 +#define CONTROLLER_LIST_MAX_LEN 1 + +static void +print_current_config(sr_session_ctx_t *session, const char *module_name) +{ + sr_val_t *values = NULL; + size_t count = 0; + int rc = SR_ERR_OK; + char xpath[XPATH_MAX_LEN] = {0}; + snprintf(xpath, XPATH_MAX_LEN, "/%s:*//.", module_name); + + sr_val_t *odl_ip = NULL; + sr_val_t *odl_port = NULL; + sr_val_t *odl_username = NULL; + sr_val_t *odl_password = NULL; + + rc = sr_get_items(session, xpath, &values, &count); + if (SR_ERR_OK != rc) { + printf("Error by sr_get_items: %s\n", sr_strerror(rc)); + return; + } + for (size_t i = 0; i < count; i++){ + + sr_print_val(&values[i]); + + if (sr_xpath_node_name_eq(values[i].xpath, "controller-ip")) + { + rc = sr_dup_val(&values[i], &odl_ip); + } + else if (sr_xpath_node_name_eq(values[i].xpath, "controller-port")) + { + rc = sr_dup_val(&values[i], &odl_port); + } + else if (sr_xpath_node_name_eq(values[i].xpath, "controller-username")) + { + rc = sr_dup_val(&values[i], &odl_username); + } + else if (sr_xpath_node_name_eq(values[i].xpath, "controller-password")) + { + rc = sr_dup_val(&values[i], &odl_password); + } + } + + //URL used for mounting/unmounting a device; the device name needs to be appended + char url[URL_AND_CREDENTIALS_MAX_LEN]; + sprintf(url, "http://%s:%d/restconf/config/network-topology:network-topology/topology/" + "topology-netconf/node/", + odl_ip->data.string_val, odl_port->data.uint32_val); + + char credentials[URL_AND_CREDENTIALS_MAX_LEN]; + sprintf(credentials, "%s:%s", odl_username->data.string_val, odl_password->data.string_val); + + //URLs used for adding key pair to ODL, for TLS connections + char url_for_keystore_add[URL_AND_CREDENTIALS_MAX_LEN]; + sprintf(url_for_keystore_add, "http://%s:%d/restconf/operations/netconf-keystore:add-keystore-entry", + odl_ip->data.string_val, odl_port->data.uint32_val); + + char url_for_private_key_add[URL_AND_CREDENTIALS_MAX_LEN]; + sprintf(url_for_private_key_add, "http://%s:%d/restconf/operations/netconf-keystore:add-private-key", + odl_ip->data.string_val, odl_port->data.uint32_val); + + char url_for_trusted_ca_add[URL_AND_CREDENTIALS_MAX_LEN]; + sprintf(url_for_trusted_ca_add, "http://%s:%d/restconf/operations/netconf-keystore:add-trusted-certificate", + odl_ip->data.string_val, odl_port->data.uint32_val); + + strcpy(controller_details.url, url); + strcpy(controller_details.credentials, credentials); + strcpy(controller_details.url_for_keystore_add, url_for_keystore_add); + strcpy(controller_details.url_for_private_key_add, url_for_private_key_add); + strcpy(controller_details.url_for_trusted_ca_add, url_for_trusted_ca_add); + + sr_free_val(odl_ip); + sr_free_val(odl_port); + sr_free_val(odl_username); + sr_free_val(odl_password); + + sr_free_values(values, count); +} + +static void clean_current_docker_configuration(void); + +static int simulated_devices_changed(int new_value) +{ + int rc = SR_ERR_OK; + + if (simulated_devices_config > new_value) + { + //we are configuring less elements that currently + for (int i = 0; i < simulated_devices_config - new_value; ++i) + { + rc = stop_device(device_list); + } + } + else if (simulated_devices_config < new_value) + { + //we are configuring more elements that currently + for (int i = 0; i < new_value - simulated_devices_config; ++i) + { + rc = start_device(device_list); + } + } + + simulated_devices_config = new_value; + + return rc; +} + +int mounted_devices_changed(sr_session_ctx_t *session, int new_value) +{ + int rc = SR_ERR_OK; + + if (mounted_devices_config > new_value) + { + //we need have less mounted elements + for (int i = 0; i < mounted_devices_config - new_value; ++i) + { + printf("Sending unmount device...\n"); + rc = unmount_device(device_list, controller_details); + } + } + else if (mounted_devices_config < new_value) + { + //we are configuring more elements that currently + for (int i = 0; i < new_value - mounted_devices_config; ++i) + { + printf("Sending mount device...\n"); + rc = mount_device(device_list, controller_details); + } + } + + mounted_devices_config = new_value; + + return rc; +} + +static int +simulator_config_change_cb(sr_session_ctx_t *session, const char *module_name, sr_notif_event_t event, void *private_ctx) +{ + int rc; + + printf("\n\n ========== CONFIG HAS CHANGED, CURRENT RUNNING CONFIG %s: ==========\n\n", module_name); + print_current_config(session, module_name); + + sr_val_t *val; + + /* get the value from sysrepo, we do not care if the value did not change in our case */ + rc = sr_get_item(session, "/network-topology-simulator:simulator-config/simulated-devices", &val); + if (rc != SR_ERR_OK) { + goto sr_error; + } + + rc = simulated_devices_changed(val->data.uint32_val); + if (rc != SR_ERR_OK) { + goto sr_error; + } + + sr_free_val(val); + + /* get the value from sysrepo, we do not care if the value did not change in our case */ + rc = sr_get_item(session, "/network-topology-simulator:simulator-config/mounted-devices", &val); + if (rc != SR_ERR_OK) { + goto sr_error; + } + + if (mounted_devices_config != val->data.uint32_val) + { + if (val->data.uint32_val > simulated_devices_config) + { + printf("Cannot set mount value greater than number of simulated devices.\n"); + sr_free_val(val); + return SR_ERR_OK; + } + + rc = mounted_devices_changed(session, val->data.uint32_val); + if (rc != SR_ERR_OK) { + goto sr_error; + } + } + + sr_free_val(val); + + /* get the value from sysrepo, we do not care if the value did not change in our case */ + rc = sr_get_item(session, "/network-topology-simulator:simulator-config/notification-config/fault-notification-delay-period", &val); + if (rc != SR_ERR_OK) { + goto sr_error; + } + + rc = notification_delay_period_changed(val->data.uint32_val); + if (rc != SR_ERR_OK) { + goto sr_error; + } + + sr_free_val(val); + + /* get the value from sysrepo, we do not care if the value did not change in our case */ + rc = sr_get_item(session, "/network-topology-simulator:simulator-config/notification-config/ves-heartbeat-period", &val); + if (rc != SR_ERR_OK) { + goto sr_error; + } + + rc = ves_heartbeat_period_changed(val->data.uint32_val); + if (rc != SR_ERR_OK) { + goto sr_error; + } + + sr_free_val(val); + + /* get the value from sysrepo, we do not care if the value did not change in our case */ + rc = sr_get_item(session, "/network-topology-simulator:simulator-config/ves-endpoint-details/ves-endpoint-ip", &val); + if (rc != SR_ERR_OK) { + goto sr_error; + } + + rc = ves_ip_changed(val->data.string_val); + if (rc != SR_ERR_OK) { + goto sr_error; + } + + sr_free_val(val); + + /* get the value from sysrepo, we do not care if the value did not change in our case */ + rc = sr_get_item(session, "/network-topology-simulator:simulator-config/ves-endpoint-details/ves-endpoint-port", &val); + if (rc != SR_ERR_OK) { + goto sr_error; + } + + rc = ves_port_changed(val->data.uint16_val); + if (rc != SR_ERR_OK) { + goto sr_error; + } + + sr_free_val(val); + + /* get the value from sysrepo, we do not care if the value did not change in our case */ + rc = sr_get_item(session, "/network-topology-simulator:simulator-config/ves-endpoint-details/ves-registration", &val); + if (rc != SR_ERR_OK) { + goto sr_error; + } + + rc = ves_registration_changed(val->data.bool_val); + if (rc != SR_ERR_OK) { + goto sr_error; + } + + sr_free_val(val); + + /* get the value from sysrepo, we do not care if the value did not change in our case */ + rc = sr_get_item(session, "/network-topology-simulator:simulator-config/notification-config/is-netconf-available", &val); + if (rc != SR_ERR_OK) { + goto sr_error; + } + + rc = is_netconf_available_changed(val->data.bool_val); + if (rc != SR_ERR_OK) { + goto sr_error; + } + + sr_free_val(val); + + /* get the value from sysrepo, we do not care if the value did not change in our case */ + rc = sr_get_item(session, "/network-topology-simulator:simulator-config/notification-config/is-ves-available", &val); + if (rc != SR_ERR_OK) { + goto sr_error; + } + + rc = is_ves_available_changed(val->data.bool_val); + if (rc != SR_ERR_OK) { + goto sr_error; + } + + sr_free_val(val); + + return SR_ERR_OK; + +sr_error: + printf("NTSimulator config change callback failed: %s.", sr_strerror(rc)); + return rc; +} + +static int +simulator_status_cb(const char *xpath, sr_val_t **values, size_t *values_cnt, + uint64_t request_id, const char *original_xpath, void *private_ctx) +{ + int rc; + + printf("\n\n ========== Called simulator_status_cb for xpath: %s ==========\n\n", xpath); + + if (sr_xpath_node_name_eq(xpath, "simulated-devices-list")) { + sr_val_t *v; + size_t current_num_of_values= 0; + + if (simulated_devices_config == 0) //nothing to return if no devices are running + { + *values = NULL; + *values_cnt = 0; + + return SR_ERR_OK; + } + + rc = get_docker_containers_operational_state_curl(device_list); + if (rc != SR_ERR_OK) + { + printf("Could not get the operational state for the devices simulated.\n"); + } + + device_t *current_device = device_list->head; + + while (current_device != NULL) + { + CREATE_NEW_VALUE(rc, v, current_num_of_values); + + sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/%s", xpath, current_device->device_id, "device-ip"); + v[current_num_of_values - 1].type = SR_STRING_T; + v[current_num_of_values - 1].data.string_val = getenv("NTS_IP"); + + for (int i = 0; i < NETCONF_CONNECTIONS_PER_DEVICE; ++i) + { + CREATE_NEW_VALUE(rc, v, current_num_of_values); + + sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/%s", xpath, current_device->device_id, "device-port"); + v[current_num_of_values - 1].type = SR_UINT32_T; + v[current_num_of_values - 1].data.uint32_val = current_device->netconf_port + i; + } + + CREATE_NEW_VALUE(rc, v, current_num_of_values); + + sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/%s", xpath, current_device->device_id, "is-mounted"); + v[current_num_of_values - 1].type = SR_BOOL_T; + v[current_num_of_values - 1].data.bool_val = current_device->is_mounted; + + char *operational_state = get_docker_container_operational_state(device_list, current_device->device_id); + + CREATE_NEW_VALUE(rc, v, current_num_of_values); + + sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/%s", xpath, current_device->device_id, "operational-state"); + sr_val_build_str_data(&v[current_num_of_values - 1], SR_ENUM_T, "%s", operational_state); + + current_device = current_device->next; + } + + //return the values that we have just created + *values = v; + *values_cnt = current_num_of_values; + } + else if (sr_xpath_node_name_eq(xpath, "simulation-usage-details")) + { + float cpu_usage = 0.0, mem_usage = 0.0; + + char *resource_usage_from_script = get_docker_container_resource_stats(); + + if (resource_usage_from_script != NULL) + { + printf("Received line: %s\n", resource_usage_from_script); + sscanf(resource_usage_from_script, "CPU=%f%%;RAM=%fMiB", &cpu_usage, &mem_usage); + printf("Read cpu=\"%f\" and mem=\"%f\"\n", cpu_usage, mem_usage); + free(resource_usage_from_script); + } + + sr_val_t *v; + /* convenient functions such as this can be found in sysrepo/values.h */ + size_t current_num_of_values= 0; + + CREATE_NEW_VALUE(rc, v, current_num_of_values); + + sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "running-simulated-devices"); + v[current_num_of_values - 1].type = SR_UINT32_T; + v[current_num_of_values - 1].data.uint32_val = get_current_number_of_devices(device_list); + + CREATE_NEW_VALUE(rc, v, current_num_of_values); + + sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "running-mounted-devices"); + v[current_num_of_values - 1].type = SR_UINT32_T; + v[current_num_of_values - 1].data.uint32_val = get_current_number_of_mounted_devices(device_list); + + CREATE_NEW_VALUE(rc, v, current_num_of_values); + + sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "base-netconf-port"); + v[current_num_of_values - 1].type = SR_UINT32_T; + v[current_num_of_values - 1].data.uint32_val = get_netconf_port_base(); + + CREATE_NEW_VALUE(rc, v, current_num_of_values); + + sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "cpu-usage"); + v[current_num_of_values - 1].type = SR_DECIMAL64_T; + v[current_num_of_values - 1].data.decimal64_val = cpu_usage; + + CREATE_NEW_VALUE(rc, v, current_num_of_values); + + sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "mem-usage"); + v[current_num_of_values - 1].type = SR_UINT32_T; + v[current_num_of_values - 1].data.uint32_val = (int)mem_usage; + + //return the values that we have just created + *values = v; + *values_cnt = current_num_of_values; + } + + return SR_ERR_OK; +} + +int odl_add_key_pair_cb(const char *xpath, const sr_val_t *input, const size_t input_cnt, + sr_val_t **output, size_t *output_cnt, void *private_ctx) +{ + int rc = SR_ERR_OK; + sr_session_ctx_t *session = (sr_session_ctx_t *)private_ctx; + controller_t controller_list[CONTROLLER_LIST_MAX_LEN]; + int controller_list_size = 0; + + controller_list[0] = controller_details; + controller_list_size++; + + for (int i = 0; i < controller_list_size; ++i) + { + printf("%d iteration: Got back url=%s and credentials=%s\n", i, controller_list[i].url, controller_list[i].credentials); + } + + rc = add_key_pair_to_odl(controller_list, controller_list_size); + if (rc != SR_ERR_OK) + { + printf("Failed to add key pair to ODL.\n"); + } + + return rc; +} + + +static void +sigint_handler(int signum) +{ + exit_application = 1; +} + +int +main(int argc, char **argv) +{ + sr_conn_ctx_t *connection = NULL; + sr_session_ctx_t *session = NULL; + sr_subscription_ctx_t *subscription = NULL; + int rc = SR_ERR_OK; + + setbuf(stdout, NULL); + + device_list = new_device_stack(); + rc = _init_curl(); + if (rc != SR_ERR_OK) + { + fprintf(stderr, "Could not initialize cURL: %s\n", sr_strerror(rc)); + } + + /* connect to sysrepo */ + rc = sr_connect("network-topology-simulator", SR_CONN_DEFAULT, &connection); + if (SR_ERR_OK != rc) { + fprintf(stderr, "Error by sr_connect: %s\n", sr_strerror(rc)); + goto cleanup; + } + + /* start session */ + rc = sr_session_start(connection, SR_DS_STARTUP, SR_SESS_DEFAULT, &session); + if (SR_ERR_OK != rc) { + fprintf(stderr, "Error by sr_session_start: %s\n", sr_strerror(rc)); + goto cleanup; + } + + /* read startup config */ + printf("\n\n ========== READING STARTUP CONFIG network-topology-simulator: ==========\n\n"); + print_current_config(session, "network-topology-simulator"); + + /* subscribe for changes in running config */ + rc = sr_module_change_subscribe(session, "network-topology-simulator", simulator_config_change_cb, NULL, + 0, SR_SUBSCR_DEFAULT | SR_SUBSCR_APPLY_ONLY, &subscription); + if (SR_ERR_OK != rc) { + fprintf(stderr, "Error by sr_module_change_subscribe: %s\n", sr_strerror(rc)); + goto cleanup; + } + + /* subscribe as state data provider for the ntsimulator state data */ + rc = sr_dp_get_items_subscribe(session, "/network-topology-simulator:simulator-status", simulator_status_cb, NULL, + SR_SUBSCR_CTX_REUSE, &subscription); + if (rc != SR_ERR_OK) { + goto cleanup; + } + + rc = notification_delay_period_changed(0); + if (rc != SR_ERR_OK) { + printf("Could not write the delay period to file!\n"); + goto cleanup; + } + + rc = _init_curl_odl(); + if (rc != SR_ERR_OK) + { + fprintf(stderr, "Could not initialize cURL for ODL connection: %s\n", sr_strerror(rc)); + } + + rc = sr_rpc_subscribe(session, "/network-topology-simulator:add-key-pair-to-odl", odl_add_key_pair_cb, (void *)session, + SR_SUBSCR_CTX_REUSE, &subscription); + + printf("\n\n ========== STARTUP CONFIG network-topology-simulator APPLIED AS RUNNING ==========\n\n"); + + /* loop until ctrl-c is pressed / SIGINT is received */ + signal(SIGINT, sigint_handler); + signal(SIGTERM, sigint_handler); + signal(SIGPIPE, SIG_IGN); + + while (!exit_application) { + + sleep(1); /* or do some more useful work... */ + } + + printf("Application exit requested, exiting.\n"); + +cleanup: + if (NULL != subscription) { + sr_unsubscribe(session, subscription); + } + if (NULL != session) { + sr_session_stop(session); + } + if (NULL != connection) { + sr_disconnect(connection); + } + + clean_current_docker_configuration(); + rc = cleanup_curl(); + rc = cleanup_curl_odl(); + + return rc; +} + +static void clean_current_docker_configuration(void) +{ + printf("Cleaning docker containers...\n"); + + if (device_list == NULL) + { + return; + } + + for (int i = 0; i < simulated_devices_config; ++i) + { + stop_device(device_list); + } + + printf("Cleaning completed!\n"); +}