--- /dev/null
+/*************************************************************************
+*
+* Copyright 2020 highstreet technologies GmbH and others
+*
+* 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.
+***************************************************************************/
+
+#define _GNU_SOURCE
+
+#include "manager.h"
+#include "utils/log_utils.h"
+#include "utils/sys_utils.h"
+#include "utils/nts_utils.h"
+#include <stdio.h>
+#include <assert.h>
+
+#include <sysrepo.h>
+#include <sysrepo/values.h>
+
+#include "core/framework.h"
+#include "core/session.h"
+#include "core/context.h"
+
+#define NTS_AVAILABLE_IMAGES_SCHEMA_XPATH "/nts-manager:simulation/available-images"
+
+
+manager_context_t *manager_context = 0;
+docker_context_t *docker_context = 0;
+int docker_context_count = 0;
+
+static int manager_populate_sysrepo_network_function_list(void);
+static int manager_populate_available_simulations(void);
+
+int manager_context_init(void) {
+
+ //get installed function types
+ struct lys_node_leaf *elem = (struct lys_node_leaf *)ly_ctx_get_node(session_context, 0, NTS_FUNCTION_LIST_SCHEMA_XPATH"/function-type", 0);
+ if(elem == 0) {
+ log_error("ly_ctx_get_node failed for xpath: %s\n", NTS_FUNCTION_LIST_SCHEMA_XPATH"/function-type");
+ return NTS_ERR_FAILED;
+ }
+
+ struct lys_ident **function_types = 0;
+ docker_context_count = context_get_identity_leafs_of_type(elem->type.info.ident.ref[0], &function_types);
+ if(!docker_context_count) {
+ log_error("context_get_identity_leafs_of_type() error\n");
+ return NTS_ERR_FAILED;
+ }
+
+ docker_context_count = docker_context_count;
+
+ const char **docker_filter = malloc(sizeof(char *) * docker_context_count);
+ if(docker_filter == 0) {
+ log_error("bad malloc\n");
+ free(function_types);
+ return NTS_ERR_FAILED;
+ }
+
+ for(int i = 0; i < docker_context_count; i++) {
+ docker_filter[i] = function_types[i]->ref;
+ }
+
+ int rc = docker_init(docker_filter, docker_context_count, "1.2.0", &docker_context);
+ free(docker_filter);
+ if(rc != NTS_ERR_OK) {
+ log_error("docker_init() failed\n");
+ free(function_types);
+ return NTS_ERR_FAILED;
+ }
+
+
+ //remove non-present network functions
+ int new_context_count = 0;
+ docker_context_t *new_context = malloc(sizeof(docker_context_t) * docker_context_count);
+ struct lys_ident **new_function_types = (struct lys_ident **)malloc(sizeof(struct lys_ident *) * docker_context_count);
+ for(int i = 0; i < docker_context_count; i++) {
+ if(docker_context[i].available_images_count) {
+ new_context[new_context_count].image = docker_context[i].image;
+ new_context[new_context_count].available_images = docker_context[i].available_images;
+ new_context[new_context_count].available_images_count = docker_context[i].available_images_count;
+ new_function_types[new_context_count] = function_types[i];
+
+ new_context_count++;
+
+ }
+ else {
+ free(docker_context[i].image);
+ }
+ }
+
+ free(function_types);
+ function_types = new_function_types;
+
+ free(docker_context);
+ docker_context = new_context;
+ docker_context_count = new_context_count;
+
+ //initial list population
+ manager_context = (manager_context_t *)malloc(sizeof(manager_context_t) * docker_context_count);
+ if(manager_context == 0) {
+ log_error("malloc failed\n");
+ free(function_types);
+ return NTS_ERR_FAILED;
+ }
+
+ for(int i = 0; i < docker_context_count; i++) {
+ manager_context[i].ft = function_types[i];
+
+ asprintf(&manager_context[i].function_type, "%s:%s", manager_context[i].ft->module->name, manager_context[i].ft->name);
+ manager_context[i].instance = 0;
+ manager_context[i].docker = &docker_context[i];
+
+ manager_context[i].started_instances = 0;
+ manager_context[i].mounted_instances = 0;
+ manager_context[i].mount_point_addressing_method = strdup("docker-mapping");
+
+ if(docker_context[i].available_images_count) {
+ manager_context[i].docker_instance_name = strdup(strstr(manager_context[i].function_type, ":") + 1);
+ manager_context[i].docker_version_tag = strdup(docker_context[i].available_images[0].tag);
+ manager_context[i].docker_repository = strdup(docker_context[i].available_images[0].repo);
+ }
+ else {
+ manager_context[i].docker_instance_name = strdup("no-image-installed");
+ manager_context[i].docker_version_tag = strdup("no-image-installed");
+ manager_context[i].docker_repository = strdup("no-image-installed");
+ }
+ }
+ free(function_types);
+
+ //do initial sysrepo list population
+ rc = manager_populate_sysrepo_network_function_list();
+ if(rc != NTS_ERR_OK) {
+ log_error("manager_populate_sysrepo_network_function_list failed\n");
+ return NTS_ERR_FAILED;
+ }
+
+ rc = manager_populate_available_simulations();
+ if(rc != NTS_ERR_OK) {
+ log_error("manager_populate_available_simulations failed\n");
+ return NTS_ERR_FAILED;
+ }
+
+ rc = nts_utils_populate_info(session_running, framework_environment.nts.function_type);
+ if(rc != NTS_ERR_OK) {
+ log_error("nts_utils_populate_info failed\n");
+ return NTS_ERR_FAILED;
+ }
+
+ return NTS_ERR_OK;
+}
+
+void manager_context_free(void) {
+ for(int i = 0; i < docker_context_count; i++) {
+ free(manager_context[i].docker_instance_name);
+ free(manager_context[i].docker_version_tag);
+ free(manager_context[i].docker_repository);
+ free(manager_context[i].function_type);
+ }
+
+ free(manager_context);
+}
+
+static int manager_populate_sysrepo_network_function_list(void) {
+ //check whether everything is already populated, read and update (if previously ran)
+ sr_val_t *values = 0;
+ size_t value_count = 0;
+ int rc = sr_get_items(session_running, NTS_FUNCTION_LIST_SCHEMA_XPATH, 0, 0, &values, &value_count);
+ if(rc != SR_ERR_OK) {
+ log_error("get items failed\n");
+ return NTS_ERR_FAILED;
+ }
+
+ //either get values, or if data inconclusive, delete everything
+ if(value_count) {
+ log_add_verbose(2, "nts-manager instances found (%d). cleaning up for fresh start...\n", value_count);
+
+ for(int i = 0; i < value_count; i++) {
+ rc = sr_delete_item(session_running, values[i].xpath, 0);
+ if(rc != SR_ERR_OK) {
+ log_error("sr_delete_item failed\n");
+ return NTS_ERR_FAILED;
+ }
+ }
+ rc = sr_apply_changes(session_running, 0, 0);
+ if(rc != SR_ERR_OK) {
+ log_error("sr_apply_changes failed\n");
+ return NTS_ERR_FAILED;
+ }
+ }
+
+ //populate everything if needed
+ for(int i = 0; i < docker_context_count; i++) {
+ char *xpath = 0;
+
+ asprintf(&xpath, "%s[function-type='%s']/function-type", NTS_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
+ rc = sr_set_item_str(session_running, xpath, (const char *)manager_context[i].function_type, 0, 0);
+ if(rc != SR_ERR_OK) {
+ log_error("sr_set_item_str failed\n");
+ return NTS_ERR_FAILED;
+ }
+ free(xpath);
+
+ asprintf(&xpath, "%s[function-type='%s']/started-instances", NTS_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
+ rc = sr_set_item_str(session_running, xpath, "0", 0, 0);
+ if(rc != SR_ERR_OK) {
+ log_error("sr_set_item_str failed\n");
+ return NTS_ERR_FAILED;
+ }
+ free(xpath);
+
+ asprintf(&xpath, "%s[function-type='%s']/mounted-instances", NTS_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
+ rc = sr_set_item_str(session_running, xpath, "0", 0, 0);
+ if(rc != SR_ERR_OK) {
+ log_error("sr_set_item_str failed\n");
+ return NTS_ERR_FAILED;
+ }
+ free(xpath);
+
+ asprintf(&xpath, "%s[function-type='%s']/docker-instance-name", NTS_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
+ rc = sr_set_item_str(session_running, xpath, (const char*)manager_context[i].docker_instance_name, 0, 0);
+ if(rc != SR_ERR_OK) {
+ log_error("sr_set_item_str failed\n");
+ return NTS_ERR_FAILED;
+ }
+ free(xpath);
+
+ asprintf(&xpath, "%s[function-type='%s']/docker-version-tag", NTS_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
+ rc = sr_set_item_str(session_running, xpath, (const char*)manager_context[i].docker_version_tag, 0, 0);
+ if(rc != SR_ERR_OK) {
+ log_error("sr_set_item_str failed\n");
+ return NTS_ERR_FAILED;
+ }
+ free(xpath);
+
+ asprintf(&xpath, "%s[function-type='%s']/docker-repository", NTS_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
+ rc = sr_set_item_str(session_running, xpath, (const char*)manager_context[i].docker_repository, 0, 0);
+ if(rc != SR_ERR_OK) {
+ log_error("sr_set_item_str failed\n");
+ return NTS_ERR_FAILED;
+ }
+ free(xpath);
+
+ asprintf(&xpath, "%s[function-type='%s']/mount-point-addressing-method", NTS_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
+ rc = sr_set_item_str(session_running, xpath, (const char *)manager_context[i].mount_point_addressing_method, 0, 0);
+ if(rc != SR_ERR_OK) {
+ log_error("sr_set_item_str failed\n");
+ return NTS_ERR_FAILED;
+ }
+ free(xpath);
+
+ //presence containers
+ asprintf(&xpath, "%s[function-type='%s']/fault-generation", NTS_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
+ rc = sr_set_item_str(session_running, xpath, 0, 0, 0);
+ if(rc != SR_ERR_OK) {
+ log_error("sr_set_item_str failed\n");
+ return NTS_ERR_FAILED;
+ }
+ free(xpath);
+
+ asprintf(&xpath, "%s[function-type='%s']/netconf", NTS_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
+ rc = sr_set_item_str(session_running, xpath, 0, 0, 0);
+ if(rc != SR_ERR_OK) {
+ log_error("sr_set_item_str failed\n");
+ return NTS_ERR_FAILED;
+ }
+ free(xpath);
+
+ asprintf(&xpath, "%s[function-type='%s']/ves", NTS_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
+ rc = sr_set_item_str(session_running, xpath, 0, 0, 0);
+ if(rc != SR_ERR_OK) {
+ log_error("sr_set_item_str failed\n");
+ return NTS_ERR_FAILED;
+ }
+ free(xpath);
+ }
+
+ //apply all changes
+ rc = sr_apply_changes(session_running, 0, 0);
+ if(rc != SR_ERR_OK) {
+ log_error("sr_apply_changes failed: %s\n", sr_strerror(rc));
+ return NTS_ERR_FAILED;
+ }
+
+ return NTS_ERR_OK;
+}
+
+static int manager_populate_available_simulations(void) {
+ assert_session();
+
+ struct lyd_node *container = lyd_new_path(0, session_context, NTS_AVAILABLE_IMAGES_SCHEMA_XPATH, 0, LYD_ANYDATA_CONSTSTRING, LYD_PATH_OPT_NOPARENTRET);
+ if(container == 0) {
+ log_error("lyd_new_path failed\n");
+ return NTS_ERR_FAILED;
+ }
+
+ for(int i = 0; i < docker_context_count; i++) {
+ for(int j = 0; j < docker_context[i].available_images_count; j++) {
+ struct lyd_node *list = lyd_new(container, container->schema->module, "network-function-image");
+ if(!list) {
+ log_error("lyd_new failed\n");
+ return NTS_ERR_FAILED;
+ }
+
+ struct lyd_node *rc = lyd_new_leaf(list, list->schema->module, "function-type", (const char *)manager_context[i].function_type);
+ if(rc == 0) {
+ log_error("lyd_new_leaf failed\n");
+ return NTS_ERR_FAILED;
+ }
+
+ rc = lyd_new_leaf(list, list->schema->module, "docker-image-name", docker_context[i].image);
+ if(rc == 0) {
+ log_error("lyd_new_leaf failed\n");
+ return NTS_ERR_FAILED;
+ }
+
+ rc = lyd_new_leaf(list, list->schema->module, "docker-version-tag", docker_context[i].available_images[j].tag);
+ if(rc == 0) {
+ log_error("lyd_new_leaf failed\n");
+ return NTS_ERR_FAILED;
+ }
+
+ rc = lyd_new_leaf(list, list->schema->module, "docker-repository", docker_context[i].available_images[j].repo);
+ if(rc == 0) {
+ log_error("lyd_new_leaf failed\n");
+ return NTS_ERR_FAILED;
+ }
+
+ }
+ }
+
+ //find top level container
+ struct lyd_node *root = container;
+ while(root->parent) {
+ root = root->parent;
+ }
+
+ int rc = sr_edit_batch(session_operational, root, "replace");
+ if(rc != SR_ERR_OK) {
+ log_error("sr_edit_batch failed\n");
+ return NTS_ERR_FAILED;
+ }
+
+ //apply all changes
+ rc = sr_apply_changes(session_operational, 0, 0);
+ if(rc != SR_ERR_OK) {
+ log_error("sr_apply_changes failed: %s\n", sr_strerror(rc));
+ return NTS_ERR_FAILED;
+ }
+
+ return NTS_ERR_OK;
+}