#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
+#include <pthread.h>
#include "core/framework.h"
-#include "core/docker.h"
#include "core/session.h"
-#include "utils/nc_client.h"
-#include "utils/http_client.h"
-#include "utils/nts_utils.h"
-static uint16_t manager_start_port = 0;
-static uint8_t manager_port[65536];
+static manager_operation_t *manager_operations;
+static pthread_mutex_t manager_operations_mutex;
+static sem_t manager_operations_sem;
-void manager_operations_init(void) {
- manager_start_port = framework_environment.host_base_port;
- for(int i = 0; i < 65536; i++) {
- manager_port[i] = 0;
- }
-}
+manager_protocol_type_t manager_port[65536];
-int manager_start_instance(manager_network_function_type *function_type) {
- assert(function_type);
- assert_session();
+static int manager_operations_execute(manager_operation_t *oper);
- function_type->started_instances++;
- function_type->instance = (manager_network_function_instance_t *)realloc(function_type->instance, sizeof(manager_network_function_instance_t) * function_type->started_instances);
- if(function_type->instance == 0) {
- log_error("realloc failed");
- function_type->started_instances--;
- return NTS_ERR_FAILED;
+int manager_operations_init(void) {
+ manager_operations = 0;
+ if(pthread_mutex_init(&manager_operations_mutex, NULL) != 0) {
+ log_error("mutex init has failed\n");
+ return NTS_ERR_FAILED;
}
- manager_network_function_instance_t *instance = &function_type->instance[function_type->started_instances - 1];
- instance->is_configured = false;
- instance->is_mounted = false;
-
- asprintf(&instance->name, "%s-%d", function_type->docker_instance_name, function_type->started_instances - 1);
-
- instance->mount_point_addressing_method = strdup(function_type->mount_point_addressing_method);
- instance->docker_port = STANDARD_NETCONF_PORT;
- instance->host_ip = strdup(framework_environment.host_ip);
- instance->host_port = 0;
-
- //find start host port
- for(int i = manager_start_port; i < 65536 - (framework_environment.ssh_connections + framework_environment.tls_connections + framework_environment.ftp_connections + framework_environment.sftp_connections); i += (framework_environment.ssh_connections + framework_environment.tls_connections + framework_environment.ftp_connections + framework_environment.sftp_connections)) {
- if(manager_port[i] == 0) {
- manager_port[i] = 1;
- instance->host_port = i;
- break;
- }
+ if(sem_init(&manager_operations_sem, 0, 0) != 0) {
+ log_error("sem init has failed\n");
+ return NTS_ERR_FAILED;
}
- if(instance->host_port == 0) {
- log_error("no ports available for operation");
- free(instance->name);
- free(instance->mount_point_addressing_method);
- free(instance->host_ip);
- function_type->started_instances--;
- return NTS_ERR_FAILED;
+ //checkAL ar fi misto sa stim ce porturi sunt si ce porturi nu sunt available...
+ for(int i = 0; i < 1000; i++) {
+ manager_port[i] = MANAGER_PROTOCOL_UNAVAILABLE;
}
- int rc = docker_device_start(function_type, instance);
- if(rc != NTS_ERR_OK) {
- log_error("docker_device_start failed");
- free(instance->name);
- free(instance->mount_point_addressing_method);
- free(instance->host_ip);
- manager_port[instance->host_port] = 0;
- function_type->started_instances--;
- return NTS_ERR_FAILED;
+ for(int i = 1000; i < 65536; i++) {
+ manager_port[i] = MANAGER_PROTOCOL_UNUSED;
}
return NTS_ERR_OK;
}
-int manager_config_instance(manager_network_function_type *function_type, manager_network_function_instance_t *instance) {
- assert(function_type);
- assert(instance);
+void manager_operations_loop(void) {
+ int rc;
+
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ts.tv_sec += 1;
+
+ if(sem_timedwait(&manager_operations_sem, &ts) == 0) {
+ int retries = 10;
+ while(retries) {
+ rc = sr_lock(session_running, NTS_MANAGER_MODULE);
+ if(rc == SR_ERR_OK) {
+ break;
+ }
+ else {
+ sleep(1);
+ }
+ retries--;
+ }
- //first wait for the nc server to be up and running
- while(check_port_open(instance->docker_ip, instance->docker_port) == false) {
- usleep(10000);
- }
+ if(retries == 0) {
+ log_error("sr_lock failed\n");
+ //checkAL ce facem acum ?
+ }
- //populate sdn-controller and ves-endpoint
- struct lyd_node *local_tree = 0;
- int rc = lyd_utils_dup(session_running, "/nts-manager:simulation/sdn-controller", "/nts-network-function:simulation/sdn-controller", &local_tree);
- if(rc != NTS_ERR_OK) {
- log_error("lyd_utils_dup failed");
- return NTS_ERR_FAILED;
+ pthread_mutex_lock(&manager_operations_mutex);
+
+ const char *status = "SUCCESS";
+ char errmsg[256];
+ errmsg[0] = 0;
+
+ while(manager_operations) {
+ //pop operation from list
+ manager_operation_t *oper = manager_operations;
+ manager_operations = manager_operations->next;
+
+ //if operation is RPC first update any *other* fields
+
+ rc = manager_operations_execute(oper);
+ if(rc != NTS_ERR_OK) {
+ log_error("manager_operations_execute failed\n");
+ status = "FAILED";
+ strcpy(errmsg, oper->errmsg);
+ manager_operations_free_oper(oper);
+ break;
+ }
+
+ manager_operations_free_oper(oper);
+ }
+
+ for(int i = 0; i < docker_context_count; i++) {
+ //do any reconfig necesarry
+ for(int j = 0; j < manager_context[i].started_instances; j++) {
+ if(manager_context[i].instance[j].is_configured == false) {
+ rc = manager_actions_config_instance(&manager_context[i], &manager_context[i].instance[j]);
+ if(rc != NTS_ERR_OK) {
+ status = "reconfig FAILED";
+ sprintf(errmsg, "reconfig FAILED - instance %s", manager_context[i].instance[j].container.name);
+ log_error("%s\n", errmsg);
+ }
+ }
+ }
+ }
+
+ rc = manager_sr_on_last_operation_status(status, errmsg);
+ if(rc != NTS_ERR_OK) {
+ log_error("manager_sr_on_last_operation_status failed\n");
+ }
+
+ pthread_mutex_unlock(&manager_operations_mutex);
+ rc = sr_unlock(session_running, NTS_MANAGER_MODULE); //release datastore
+ if(rc != SR_ERR_OK) {
+ log_error("sr_unlock failed\n");
+ }
}
+}
- rc = lyd_utils_dup(session_running, "/nts-manager:simulation/ves-endpoint", "/nts-network-function:simulation/ves-endpoint", &local_tree);
- if(rc != NTS_ERR_OK) {
- log_error("lyd_utils_dup failed");
- lyd_free_withsiblings(local_tree);
- return NTS_ERR_FAILED;
+void manager_operations_free(void) {
+ //terminate all containers
+ for(int i = 0; i < docker_context_count; i++) {
+ while(manager_context[i].started_instances) {
+ manager_actions_stop(&manager_context[i]);
+ }
}
- char *xpath_s = 0;
- asprintf(&xpath_s, "/nts-manager:simulation/network-functions/network-function[function-type='%s']", function_type->function_type_string);
- rc = lyd_utils_dup(session_running, xpath_s, "/nts-network-function:simulation/network-function", &local_tree);
- free(xpath_s);
- if(rc != NTS_ERR_OK) {
- log_error("lyd_utils_dup failed");
- lyd_free_withsiblings(local_tree);
- return NTS_ERR_FAILED;
- }
+ sem_destroy(&manager_operations_sem);
+ pthread_mutex_destroy(&manager_operations_mutex);
+}
- nc_client_t *nc_client = nc_client_ssh_connect(instance->docker_ip, instance->docker_port, "netconf", "netconf");
- if(nc_client == 0) {
- log_error("nc_client_ssh_connect");
- lyd_free_withsiblings(local_tree);
- return NTS_ERR_FAILED;
+manager_operation_t *manager_operations_new_oper(manager_operation_type_t type) {
+ manager_operation_t *new_oper = malloc(sizeof(manager_operation_t));
+ if(new_oper == 0) {
+ log_error("malloc failed\n");
+ return 0;
}
- rc += nc_client_edit_batch(nc_client, local_tree, 1000);
- lyd_free_withsiblings(local_tree);
- if(rc != NTS_ERR_OK) {
- log_error("nc_client_edit_batch failed %d\n", rc);
- nc_client_disconnect(nc_client);
- return NTS_ERR_FAILED;
- }
+ new_oper->type = type;
+
+ new_oper->ft_index = -1;
+ new_oper->function_type = 0;
+
+ new_oper->started_instances = -1;
+ new_oper->mounted_instances = -1;
- if(instance->is_configured == false) {
- //run datastore-random-populate rpc
- struct lyd_node *rpc_node = 0;
- struct lyd_node *rpcout = 0;
- rpc_node = lyd_new_path(0, session_context, "/nts-network-function:datastore-random-populate", 0, 0, 0);
- if(rpc_node == 0) {
- log_error("failed to create rpc node");
- nc_client_disconnect(nc_client);
- return NTS_ERR_FAILED;
- }
+ new_oper->docker_instance_name = 0;
+ new_oper->docker_version_tag = 0;
+ new_oper->docker_repository = 0;
- rpcout = nc_client_send_rpc(nc_client, rpc_node, 5000);
- if(rpcout == 0) {
- log_error("datastore-random-populate rpc failed");
- nc_client_disconnect(nc_client);
- lyd_free_withsiblings(rpc_node);
- return NTS_ERR_FAILED;
- }
- else {
- lyd_free_withsiblings(rpcout);
- }
- lyd_free_withsiblings(rpc_node);
-
- //run feature-control rpc
- rpc_node = lyd_new_path(0, session_context, "/nts-network-function:feature-control/features", "ves-file-ready ves-heartbeat ves-pnf-registration manual-notification-generation netconf-call-home web-cut-through", 0, 0);
- if(rpc_node == 0) {
- log_error("failed to create rpc node");
- nc_client_disconnect(nc_client);
- return NTS_ERR_FAILED;
- }
+ new_oper->mount_point_addressing_method = 0;
- rpcout = nc_client_send_rpc(nc_client, rpc_node, 1000);
- if(rpcout == 0) {
- log_error("feature-control rpc failed");
- nc_client_disconnect(nc_client);
- lyd_free_withsiblings(rpc_node);
- return NTS_ERR_FAILED;
- }
- else {
- lyd_free_withsiblings(rpcout);
- }
- lyd_free_withsiblings(rpc_node);
- }
+ new_oper->fault_generation.delay_period = 0;
+ new_oper->fault_generation.delay_period_count = -1;
- instance->is_configured = true;
+ new_oper->netconf.faults_enabled = -1;
+ new_oper->netconf.call_home = -1;
- nc_client_disconnect(nc_client);
+ new_oper->ves.faults_enabled = -1;
+ new_oper->ves.pnf_registration = -1;
+ new_oper->ves.heartbeat_period = -1;
- return NTS_ERR_OK;
+ new_oper->errmsg = 0;
+ new_oper->next = 0;
+
+ return new_oper;
}
-int manager_stop_instance(manager_network_function_type *function_type) {
- assert(function_type);
+int manager_operations_free_oper(manager_operation_t *oper) {
+ assert(oper);
- manager_network_function_instance_t *instance = &function_type->instance[function_type->started_instances - 1];
+ free(oper->function_type);
+ free(oper->docker_instance_name);
+ free(oper->docker_repository);
+ free(oper->docker_version_tag);
+ free(oper->mount_point_addressing_method);
+ free(oper->errmsg);
- if(instance->is_mounted) {
- if(manager_unmount_instance(function_type) != NTS_ERR_OK) {
- log_error("failed to unmount instance");
- }
- }
+ free(oper);
+ return NTS_ERR_OK;
+}
- int rc = docker_device_stop(instance);
- if(rc != NTS_ERR_OK) {
- log_error("docker_device_stop failed");
- return NTS_ERR_FAILED;
- }
+int manager_operations_begin(void) {
+ return pthread_mutex_lock(&manager_operations_mutex);
+}
- //clear unused ports
- manager_port[instance->host_port] = 0;
-
- free(instance->mount_point_addressing_method);
- free(instance->docker_id);
- free(instance->name);
- free(instance->docker_ip);
- free(instance->host_ip);
-
- function_type->started_instances--;
- if(function_type->started_instances) {
- function_type->instance = (manager_network_function_instance_t *)realloc(function_type->instance, sizeof(manager_network_function_instance_t) * function_type->started_instances);
- if(function_type->instance == 0) {
- log_error("realloc failed");
- return NTS_ERR_FAILED;
- }
+int manager_operations_add(manager_operation_t *oper) {
+ assert(oper);
+
+ if(manager_operations == 0) {
+ manager_operations = oper;
}
else {
- free(function_type->instance);
- function_type->instance = 0;
+ manager_operation_t *h = manager_operations;
+ while(h->next) {
+ h = h->next;
+ }
+ h->next = oper;
}
+
return NTS_ERR_OK;
}
-int manager_mount_instance(manager_network_function_type *function_type) {
- assert(function_type);
+void manager_operations_finish_and_execute(void) {
+ pthread_mutex_unlock(&manager_operations_mutex);
+ sem_post(&manager_operations_sem);
+}
- manager_network_function_instance_t *instance = &function_type->instance[function_type->mounted_instances];
+void manager_operations_finish_with_error(void) {
+ while(manager_operations) {
+ manager_operation_t *h = manager_operations->next;
+ manager_operations_free_oper(manager_operations);
+ manager_operations = h;
+ }
+ pthread_mutex_unlock(&manager_operations_mutex);
+ sem_post(&manager_operations_sem);
+}
- if(instance->is_mounted == true) {
- return NTS_ERR_FAILED;
+
+
+int manager_operations_validate(manager_operation_t *oper) {
+ assert(oper);
+
+ //prepopulate unset values
+ if(oper->docker_instance_name == 0) {
+ oper->docker_instance_name = strdup(manager_context[oper->ft_index].docker_instance_name);
}
- controller_details_t *controller;
- controller = controller_details_get(0);
- if(controller == 0) {
- log_error("could not get controller detailes");
- return NTS_ERR_FAILED;
+ if(oper->docker_repository == 0) {
+ oper->docker_repository = strdup(manager_context[oper->ft_index].docker_repository);
}
- for(int i = 0; i < (framework_environment.ssh_connections + framework_environment.tls_connections); i++) {
- char *protocol;
- char *protocol_data;
- if(i < framework_environment.ssh_connections) {
- protocol = "SSH";
- protocol_data = "\
- \"network-topology:netconf-node-topology:username\": \"netconf\",\
- \"network-topology:netconf-node-topology:password\": \"netconf\"";
+ if(oper->docker_version_tag == 0) {
+ oper->docker_version_tag = strdup(manager_context[oper->ft_index].docker_version_tag);
+ }
- }
- else {
- protocol = "TLS";
- protocol_data = "\
- \"netconf-node-topology:key-based\" : {\
- \"netconf-node-topology:username\" : \"netconf\",\
- \"netconf-node-topology:key-id\" : \""KS_KEY_NAME"\"\
- }";
- }
+ if(oper->started_instances == -1) {
+ oper->started_instances = manager_context[oper->ft_index].started_instances;
+ }
- char *json_template = "\
- {\
- \"network-topology:node\": [{\
- \"network-topology:node-id\": \"%s\",\
- \"network-topology:netconf-node-topology:host\": \"%s\",\
- \"network-topology:netconf-node-topology:port\": \"%d\",\
- \"network-topology:netconf-node-topology:tcp-only\": \"false\",\
- \"network-topology:netconf-node-topology:protocol\": {\
- \"network-topology:netconf-node-topology:name\": \"%s\"\
- },\
- %s,\
- \"network-topology:netconf-node-topology:connection-timeout-millis\": \"20000\",\
- \"network-topology:netconf-node-topology:default-request-timeout-millis\": \"60000\",\
- \"network-topology:netconf-node-topology:max-connection-attempts\": \"3\"\
- }]\
- }";
-
- char *json = 0;
- uint16_t port = 0;
- char *ip = 0;
- if(instance->mount_point_addressing_method[0] == 'd') {
- ip = instance->docker_ip;
- port = instance->docker_port + i;
- }
- else {
- ip = instance->host_ip;
- port = instance->host_port + i;
- }
- char *node_id = 0;
- asprintf(&node_id, "%s-%d", instance->name, port);
- asprintf(&json, json_template, node_id, ip, port, protocol, protocol_data);
+ if(oper->mounted_instances == -1) {
+ oper->mounted_instances = manager_context[oper->ft_index].mounted_instances;
+ }
- char *url = 0;
- asprintf(&url, "%s/rests/data/network-topology:network-topology/topology=topology-netconf/node=%s", controller->base_url, node_id);
- int rc = http_request(url, controller->username, controller->password, "PUT", json, 0, 0);
- if(rc != NTS_ERR_OK) {
- log_error("http_request failed");
- free(url);
- free(node_id);
- free(json);
- controller_details_free(controller);
- return NTS_ERR_FAILED;
+ //check docker image if exists
+ bool found = false;
+ for(int i = 0; i < docker_context[oper->ft_index].available_images_count; i++) {
+ if(strcmp(docker_context[oper->ft_index].available_images[i].repo, oper->docker_repository) == 0) {
+ if(strcmp(docker_context[oper->ft_index].available_images[i].tag, oper->docker_version_tag) == 0) {
+ found = true;
+ break;
+ }
}
-
- free(url);
- free(node_id);
- free(json);
}
- controller_details_free(controller);
-
- instance->is_mounted = true;
- function_type->mounted_instances++;
+ if(found == false) {
+ log_error("could not find image: %s/%s:%s\n", oper->docker_repository, docker_context[oper->ft_index].image, oper->docker_version_tag);
+ return NTS_ERR_FAILED;
+ }
return NTS_ERR_OK;
}
-int manager_unmount_instance(manager_network_function_type *function_type) {
- assert(function_type);
- int ret = NTS_ERR_OK;
-
- manager_network_function_instance_t *instance = &function_type->instance[function_type->mounted_instances - 1];
+static int manager_operations_execute(manager_operation_t *oper) {
+ assert(oper);
+
+ int k = oper->ft_index;
+ int rc;
+
+ //operation --> actions
+ if(manager_context[k].started_instances > oper->started_instances) {
+ //stop instances
+ while(manager_context[k].started_instances > oper->started_instances) {
+
+ rc = manager_actions_stop(&manager_context[k]);
+ if(rc != NTS_ERR_OK) {
+ asprintf(&oper->errmsg, "stop FAILED - function-type %s", manager_context[k].function_type);
+ log_error("%s\n", oper->errmsg);
+
+ return NTS_ERR_FAILED;
+ }
+
+ rc = manager_sr_update_context(&manager_context[k]);
+ if(rc != NTS_ERR_OK) {
+ log_error("manager_sr_update_context failed\n");
+ }
+ }
- if(instance->is_mounted == false) {
- log_error("tried to unmount an unmounted instance");
- return NTS_ERR_FAILED;
}
-
- controller_details_t *controller;
- controller = controller_details_get(0);
- if(controller == 0) {
- log_error("could not get controller detailes");
- return NTS_ERR_FAILED;
+ else if(manager_context[k].started_instances < oper->started_instances) {
+ //start instances
+ while(manager_context[k].started_instances < oper->started_instances) {
+
+ rc = manager_actions_start(&manager_context[k]);
+ if(rc != NTS_ERR_OK) {
+ asprintf(&oper->errmsg, "start FAILED - function-type %s", manager_context[k].function_type);
+ log_error("%s\n", oper->errmsg);
+ return NTS_ERR_FAILED;
+ }
+
+ rc = manager_sr_update_context(&manager_context[k]);
+ if(rc != NTS_ERR_OK) {
+ log_error("manager_sr_update_context failed\n");
+ }
+
+ rc = manager_actions_config_instance(&manager_context[k], &manager_context[k].instance[manager_context[k].started_instances - 1]);
+ if(rc != NTS_ERR_OK) {
+ asprintf(&oper->errmsg, "config FAILED - instance %s", manager_context[k].instance[manager_context[k].started_instances - 1].container.name);
+ log_error("%s\n", oper->errmsg);
+ }
+ }
}
- for(int i = 0; i < (framework_environment.ssh_connections + framework_environment.tls_connections); i++) {
- uint16_t port = 0;
- if(function_type->mount_point_addressing_method[0] == 'd') {
- port = instance->docker_port + i;
+ if(manager_context[k].mounted_instances > oper->mounted_instances) {
+ //unmount instances
+ while(manager_context[k].mounted_instances > oper->mounted_instances) {
+ rc = manager_actions_unmount(&manager_context[k]);
+ if(rc != NTS_ERR_OK) {
+ asprintf(&oper->errmsg, "unmount FAILED - instance %s", manager_context[k].instance[manager_context[k].mounted_instances - 1].container.name);
+ log_error("%s\n", oper->errmsg);
+ return NTS_ERR_FAILED;
+ }
+
+ rc = manager_sr_update_context(&manager_context[k]);
+ if(rc != NTS_ERR_OK) {
+ log_error("manager_sr_update_context failed\n");
+ }
}
- else {
- port = instance->host_port + i;
- }
- char *node_id = 0;
- asprintf(&node_id, "%s-%d", instance->name, port);
- char *url = 0;
- asprintf(&url, "%s/rests/data/network-topology:network-topology/topology=topology-netconf/node=%s", controller->base_url, node_id);
- int rc = http_request(url, controller->username, controller->password, "DELETE", "", 0, 0);
- if(rc != NTS_ERR_OK) {
- log_error("http_request failed");
- ret = NTS_ERR_FAILED;
+ }
+ else if(manager_context[k].mounted_instances < oper->mounted_instances) {
+ //mount instances
+ while(manager_context[k].mounted_instances < oper->mounted_instances) {
+ rc = manager_actions_mount(&manager_context[k]);
+ if(rc != NTS_ERR_OK) {
+ asprintf(&oper->errmsg, "mount FAILED - instance %s", manager_context[k].instance[manager_context[k].mounted_instances].container.name);
+ log_error("%s\n", oper->errmsg);
+ return NTS_ERR_FAILED;
+ }
+
+ rc = manager_sr_update_context(&manager_context[k]);
+ if(rc != NTS_ERR_OK) {
+ log_error("manager_sr_update_context failed\n");
+ }
}
-
- free(url);
- free(node_id);
}
- controller_details_free(controller);
-
- function_type->mounted_instances--;
- function_type->instance[function_type->mounted_instances].is_mounted = false;
-
- return ret;
+ return NTS_ERR_OK;
}