1 /*************************************************************************
3 * Copyright 2020 highstreet technologies GmbH and others
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 ***************************************************************************/
21 #include "utils/log_utils.h"
22 #include "utils/sys_utils.h"
23 #include "utils/nts_utils.h"
28 #include <sysrepo/values.h>
30 #include "core/framework.h"
31 #include "core/session.h"
32 #include "core/xpath.h"
33 #include "core/context.h"
35 manager_context_t *manager_context = 0;
36 docker_context_t *docker_context = 0;
37 int docker_context_count = 0;
39 static int manager_populate_sysrepo_network_function_list(void);
40 static int manager_populate_available_simulations(void);
42 int manager_context_init(void) {
44 //get installed function types
45 struct lys_node_leaf *elem = (struct lys_node_leaf *)ly_ctx_get_node(session_context, 0, NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH"/function-type", 0);
47 log_error("ly_ctx_get_node failed for xpath: %s\n", NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH"/function-type");
48 return NTS_ERR_FAILED;
51 struct lys_ident **function_types = 0;
52 docker_context_count = context_get_identity_leafs_of_type(elem->type.info.ident.ref[0], &function_types);
53 if(!docker_context_count) {
54 log_error("context_get_identity_leafs_of_type() error\n");
55 return NTS_ERR_FAILED;
58 docker_context_count = docker_context_count;
60 const char **docker_filter = malloc(sizeof(char *) * docker_context_count);
61 if(docker_filter == 0) {
62 log_error("bad malloc\n");
64 return NTS_ERR_FAILED;
67 for(int i = 0; i < docker_context_count; i++) {
68 docker_filter[i] = function_types[i]->ref;
71 int rc = docker_init(docker_filter, docker_context_count, NTS_VERSION_FALLBACK, &docker_context);
72 if(rc != NTS_ERR_OK) {
73 log_error("docker_init() failed\n");
76 return NTS_ERR_FAILED;
79 //check if an image needs to be pulled
80 log_add_verbose(1, "Docker auto-pull is ");
81 if(strlen(framework_environment.settings.docker_repository)) {
82 log_add(1, LOG_COLOR_BOLD_GREEN"enabled"LOG_COLOR_RESET"\n");
84 for(int i = 0; i < docker_context_count; i++) {
86 for(int j = 0; j < docker_context[i].available_images_count; j++) {
87 if(strcmp(framework_environment.nts.version, docker_context[i].available_images[j].tag) == 0) {
93 log_add_verbose(1, "pulling "LOG_COLOR_RED"%s/"LOG_COLOR_CYAN"%s"LOG_COLOR_RESET":"LOG_COLOR_YELLOW"%s"LOG_COLOR_RESET"... ", framework_environment.settings.docker_repository, docker_context[i].image, framework_environment.nts.version);
94 rc = docker_pull(framework_environment.settings.docker_repository, docker_context[i].image, framework_environment.nts.version);
95 if(rc != NTS_ERR_OK) {
96 log_add(1, LOG_COLOR_BOLD_RED"failed"LOG_COLOR_RESET"\n");
99 log_add(1, LOG_COLOR_BOLD_GREEN"OK"LOG_COLOR_RESET"\n");
107 docker_free(docker_context, docker_context_count);
108 rc = docker_init(docker_filter, docker_context_count, NTS_VERSION_FALLBACK, &docker_context);
109 if(rc != NTS_ERR_OK) {
110 log_error("docker_init() failed\n");
112 free(function_types);
113 return NTS_ERR_FAILED;
118 log_add(1, LOG_COLOR_YELLOW"disabled"LOG_COLOR_RESET"\n");
123 //remove non-present network functions
124 int new_context_count = 0;
125 docker_context_t *new_context = malloc(sizeof(docker_context_t) * docker_context_count);
126 struct lys_ident **new_function_types = (struct lys_ident **)malloc(sizeof(struct lys_ident *) * docker_context_count);
127 for(int i = 0; i < docker_context_count; i++) {
128 if(docker_context[i].available_images_count) {
129 new_context[new_context_count].image = docker_context[i].image;
130 new_context[new_context_count].available_images = docker_context[i].available_images;
131 new_context[new_context_count].available_images_count = docker_context[i].available_images_count;
132 new_function_types[new_context_count] = function_types[i];
138 free(docker_context[i].image);
142 free(function_types);
143 function_types = new_function_types;
145 free(docker_context);
146 docker_context = new_context;
147 docker_context_count = new_context_count;
149 //initial list population
150 manager_context = (manager_context_t *)malloc(sizeof(manager_context_t) * docker_context_count);
151 if(manager_context == 0) {
152 log_error("malloc failed\n");
153 free(function_types);
154 return NTS_ERR_FAILED;
157 for(int i = 0; i < docker_context_count; i++) {
158 manager_context[i].ft = function_types[i];
160 asprintf(&manager_context[i].function_type, "%s:%s", manager_context[i].ft->module->name, manager_context[i].ft->name);
161 manager_context[i].instance = 0;
162 manager_context[i].docker = &docker_context[i];
164 manager_context[i].started_instances = 0;
165 manager_context[i].mounted_instances = 0;
166 manager_context[i].mount_point_addressing_method = strdup("docker-mapping");
168 if(docker_context[i].available_images_count) {
169 manager_context[i].docker_instance_name = strdup(strstr(manager_context[i].function_type, ":") + 1);
170 manager_context[i].docker_version_tag = strdup(docker_context[i].available_images[0].tag);
171 manager_context[i].docker_repository = strdup(docker_context[i].available_images[0].repo);
174 manager_context[i].docker_instance_name = strdup("no-image-installed");
175 manager_context[i].docker_version_tag = strdup("no-image-installed");
176 manager_context[i].docker_repository = strdup("no-image-installed");
179 free(function_types);
181 //do initial sysrepo list population
182 rc = manager_populate_sysrepo_network_function_list();
183 if(rc != NTS_ERR_OK) {
184 log_error("manager_populate_sysrepo_network_function_list failed\n");
185 return NTS_ERR_FAILED;
188 rc = manager_populate_available_simulations();
189 if(rc != NTS_ERR_OK) {
190 log_error("manager_populate_available_simulations failed\n");
191 return NTS_ERR_FAILED;
194 rc = nts_utils_populate_info(session_running, framework_environment.nts.function_type);
195 if(rc != NTS_ERR_OK) {
196 log_error("nts_utils_populate_info failed\n");
197 return NTS_ERR_FAILED;
203 void manager_context_free(void) {
204 for(int i = 0; i < docker_context_count; i++) {
205 free(manager_context[i].docker_instance_name);
206 free(manager_context[i].docker_version_tag);
207 free(manager_context[i].docker_repository);
208 free(manager_context[i].function_type);
211 free(manager_context);
214 static int manager_populate_sysrepo_network_function_list(void) {
215 //check whether everything is already populated, read and update (if previously ran)
216 sr_val_t *values = 0;
217 size_t value_count = 0;
218 int rc = sr_get_items(session_running, NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, 0, 0, &values, &value_count);
219 if(rc != SR_ERR_OK) {
220 log_error("get items failed\n");
221 return NTS_ERR_FAILED;
224 //either get values, or if data inconclusive, delete everything
226 log_add_verbose(2, "nts-manager instances found (%d). cleaning up for fresh start...\n", value_count);
228 for(int i = 0; i < value_count; i++) {
229 rc = sr_delete_item(session_running, values[i].xpath, 0);
230 if(rc != SR_ERR_OK) {
231 log_error("sr_delete_item failed\n");
232 return NTS_ERR_FAILED;
235 rc = sr_apply_changes(session_running, 0, 0);
236 if(rc != SR_ERR_OK) {
237 log_error("sr_apply_changes failed\n");
238 return NTS_ERR_FAILED;
241 sr_free_values(values, value_count);
244 //populate everything if needed
245 for(int i = 0; i < docker_context_count; i++) {
248 asprintf(&xpath, "%s[function-type='%s']/function-type", NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
249 rc = sr_set_item_str(session_running, xpath, (const char *)manager_context[i].function_type, 0, 0);
250 if(rc != SR_ERR_OK) {
251 log_error("sr_set_item_str failed\n");
252 return NTS_ERR_FAILED;
256 asprintf(&xpath, "%s[function-type='%s']/started-instances", NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
257 rc = sr_set_item_str(session_running, xpath, "0", 0, 0);
258 if(rc != SR_ERR_OK) {
259 log_error("sr_set_item_str failed\n");
260 return NTS_ERR_FAILED;
264 asprintf(&xpath, "%s[function-type='%s']/mounted-instances", NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
265 rc = sr_set_item_str(session_running, xpath, "0", 0, 0);
266 if(rc != SR_ERR_OK) {
267 log_error("sr_set_item_str failed\n");
268 return NTS_ERR_FAILED;
272 asprintf(&xpath, "%s[function-type='%s']/docker-instance-name", NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
273 rc = sr_set_item_str(session_running, xpath, (const char*)manager_context[i].docker_instance_name, 0, 0);
274 if(rc != SR_ERR_OK) {
275 log_error("sr_set_item_str failed\n");
276 return NTS_ERR_FAILED;
280 asprintf(&xpath, "%s[function-type='%s']/docker-version-tag", NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
281 rc = sr_set_item_str(session_running, xpath, (const char*)manager_context[i].docker_version_tag, 0, 0);
282 if(rc != SR_ERR_OK) {
283 log_error("sr_set_item_str failed\n");
284 return NTS_ERR_FAILED;
288 asprintf(&xpath, "%s[function-type='%s']/docker-repository", NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
289 rc = sr_set_item_str(session_running, xpath, (const char*)manager_context[i].docker_repository, 0, 0);
290 if(rc != SR_ERR_OK) {
291 log_error("sr_set_item_str failed\n");
292 return NTS_ERR_FAILED;
296 asprintf(&xpath, "%s[function-type='%s']/mount-point-addressing-method", NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
297 rc = sr_set_item_str(session_running, xpath, (const char *)manager_context[i].mount_point_addressing_method, 0, 0);
298 if(rc != SR_ERR_OK) {
299 log_error("sr_set_item_str failed\n");
300 return NTS_ERR_FAILED;
304 //presence containers
305 asprintf(&xpath, "%s[function-type='%s']/fault-generation", NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
306 rc = sr_set_item_str(session_running, xpath, 0, 0, 0);
307 if(rc != SR_ERR_OK) {
308 log_error("sr_set_item_str failed\n");
309 return NTS_ERR_FAILED;
313 asprintf(&xpath, "%s[function-type='%s']/netconf", NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
314 rc = sr_set_item_str(session_running, xpath, 0, 0, 0);
315 if(rc != SR_ERR_OK) {
316 log_error("sr_set_item_str failed\n");
317 return NTS_ERR_FAILED;
321 asprintf(&xpath, "%s[function-type='%s']/ves", NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
322 rc = sr_set_item_str(session_running, xpath, 0, 0, 0);
323 if(rc != SR_ERR_OK) {
324 log_error("sr_set_item_str failed\n");
325 return NTS_ERR_FAILED;
331 rc = sr_apply_changes(session_running, 0, 0);
332 if(rc != SR_ERR_OK) {
333 log_error("sr_apply_changes failed: %s\n", sr_strerror(rc));
334 return NTS_ERR_FAILED;
340 static int manager_populate_available_simulations(void) {
343 struct lyd_node *container = lyd_new_path(0, session_context, NTS_MANAGER_AVAILABLE_IMAGES_SCHEMA_XPATH, 0, LYD_ANYDATA_CONSTSTRING, LYD_PATH_OPT_NOPARENTRET);
345 log_error("lyd_new_path failed\n");
346 return NTS_ERR_FAILED;
349 for(int i = 0; i < docker_context_count; i++) {
350 for(int j = 0; j < docker_context[i].available_images_count; j++) {
351 struct lyd_node *list = lyd_new(container, container->schema->module, "network-function-image");
353 log_error("lyd_new failed\n");
354 return NTS_ERR_FAILED;
357 struct lyd_node *rc = lyd_new_leaf(list, list->schema->module, "function-type", (const char *)manager_context[i].function_type);
359 log_error("lyd_new_leaf failed\n");
360 return NTS_ERR_FAILED;
363 rc = lyd_new_leaf(list, list->schema->module, "docker-image-name", docker_context[i].image);
365 log_error("lyd_new_leaf failed\n");
366 return NTS_ERR_FAILED;
369 rc = lyd_new_leaf(list, list->schema->module, "docker-version-tag", docker_context[i].available_images[j].tag);
371 log_error("lyd_new_leaf failed\n");
372 return NTS_ERR_FAILED;
375 rc = lyd_new_leaf(list, list->schema->module, "docker-repository", docker_context[i].available_images[j].repo);
377 log_error("lyd_new_leaf failed\n");
378 return NTS_ERR_FAILED;
384 //find top level container
385 struct lyd_node *root = container;
386 while(root->parent) {
390 int rc = sr_edit_batch(session_operational, root, "replace");
391 if(rc != SR_ERR_OK) {
392 log_error("sr_edit_batch failed\n");
393 return NTS_ERR_FAILED;
397 rc = sr_apply_changes(session_operational, 0, 0);
398 if(rc != SR_ERR_OK) {
399 log_error("sr_apply_changes failed: %s\n", sr_strerror(rc));
400 return NTS_ERR_FAILED;