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;
242 //populate everything if needed
243 for(int i = 0; i < docker_context_count; i++) {
246 asprintf(&xpath, "%s[function-type='%s']/function-type", NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
247 rc = sr_set_item_str(session_running, xpath, (const char *)manager_context[i].function_type, 0, 0);
248 if(rc != SR_ERR_OK) {
249 log_error("sr_set_item_str failed\n");
250 return NTS_ERR_FAILED;
254 asprintf(&xpath, "%s[function-type='%s']/started-instances", NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
255 rc = sr_set_item_str(session_running, xpath, "0", 0, 0);
256 if(rc != SR_ERR_OK) {
257 log_error("sr_set_item_str failed\n");
258 return NTS_ERR_FAILED;
262 asprintf(&xpath, "%s[function-type='%s']/mounted-instances", NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
263 rc = sr_set_item_str(session_running, xpath, "0", 0, 0);
264 if(rc != SR_ERR_OK) {
265 log_error("sr_set_item_str failed\n");
266 return NTS_ERR_FAILED;
270 asprintf(&xpath, "%s[function-type='%s']/docker-instance-name", NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
271 rc = sr_set_item_str(session_running, xpath, (const char*)manager_context[i].docker_instance_name, 0, 0);
272 if(rc != SR_ERR_OK) {
273 log_error("sr_set_item_str failed\n");
274 return NTS_ERR_FAILED;
278 asprintf(&xpath, "%s[function-type='%s']/docker-version-tag", NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
279 rc = sr_set_item_str(session_running, xpath, (const char*)manager_context[i].docker_version_tag, 0, 0);
280 if(rc != SR_ERR_OK) {
281 log_error("sr_set_item_str failed\n");
282 return NTS_ERR_FAILED;
286 asprintf(&xpath, "%s[function-type='%s']/docker-repository", NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
287 rc = sr_set_item_str(session_running, xpath, (const char*)manager_context[i].docker_repository, 0, 0);
288 if(rc != SR_ERR_OK) {
289 log_error("sr_set_item_str failed\n");
290 return NTS_ERR_FAILED;
294 asprintf(&xpath, "%s[function-type='%s']/mount-point-addressing-method", NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
295 rc = sr_set_item_str(session_running, xpath, (const char *)manager_context[i].mount_point_addressing_method, 0, 0);
296 if(rc != SR_ERR_OK) {
297 log_error("sr_set_item_str failed\n");
298 return NTS_ERR_FAILED;
302 //presence containers
303 asprintf(&xpath, "%s[function-type='%s']/fault-generation", NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
304 rc = sr_set_item_str(session_running, xpath, 0, 0, 0);
305 if(rc != SR_ERR_OK) {
306 log_error("sr_set_item_str failed\n");
307 return NTS_ERR_FAILED;
311 asprintf(&xpath, "%s[function-type='%s']/netconf", NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
312 rc = sr_set_item_str(session_running, xpath, 0, 0, 0);
313 if(rc != SR_ERR_OK) {
314 log_error("sr_set_item_str failed\n");
315 return NTS_ERR_FAILED;
319 asprintf(&xpath, "%s[function-type='%s']/ves", NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
320 rc = sr_set_item_str(session_running, xpath, 0, 0, 0);
321 if(rc != SR_ERR_OK) {
322 log_error("sr_set_item_str failed\n");
323 return NTS_ERR_FAILED;
329 rc = sr_apply_changes(session_running, 0, 0);
330 if(rc != SR_ERR_OK) {
331 log_error("sr_apply_changes failed: %s\n", sr_strerror(rc));
332 return NTS_ERR_FAILED;
338 static int manager_populate_available_simulations(void) {
341 struct lyd_node *container = lyd_new_path(0, session_context, NTS_MANAGER_AVAILABLE_IMAGES_SCHEMA_XPATH, 0, LYD_ANYDATA_CONSTSTRING, LYD_PATH_OPT_NOPARENTRET);
343 log_error("lyd_new_path failed\n");
344 return NTS_ERR_FAILED;
347 for(int i = 0; i < docker_context_count; i++) {
348 for(int j = 0; j < docker_context[i].available_images_count; j++) {
349 struct lyd_node *list = lyd_new(container, container->schema->module, "network-function-image");
351 log_error("lyd_new failed\n");
352 return NTS_ERR_FAILED;
355 struct lyd_node *rc = lyd_new_leaf(list, list->schema->module, "function-type", (const char *)manager_context[i].function_type);
357 log_error("lyd_new_leaf failed\n");
358 return NTS_ERR_FAILED;
361 rc = lyd_new_leaf(list, list->schema->module, "docker-image-name", docker_context[i].image);
363 log_error("lyd_new_leaf failed\n");
364 return NTS_ERR_FAILED;
367 rc = lyd_new_leaf(list, list->schema->module, "docker-version-tag", docker_context[i].available_images[j].tag);
369 log_error("lyd_new_leaf failed\n");
370 return NTS_ERR_FAILED;
373 rc = lyd_new_leaf(list, list->schema->module, "docker-repository", docker_context[i].available_images[j].repo);
375 log_error("lyd_new_leaf failed\n");
376 return NTS_ERR_FAILED;
382 //find top level container
383 struct lyd_node *root = container;
384 while(root->parent) {
388 int rc = sr_edit_batch(session_operational, root, "replace");
389 if(rc != SR_ERR_OK) {
390 log_error("sr_edit_batch failed\n");
391 return NTS_ERR_FAILED;
395 rc = sr_apply_changes(session_operational, 0, 0);
396 if(rc != SR_ERR_OK) {
397 log_error("sr_apply_changes failed: %s\n", sr_strerror(rc));
398 return NTS_ERR_FAILED;