3ee398a4e832b3d1ca87bb97d676e22e91819c1b
[sim/o1-interface.git] / ntsimulator / ntsim-ng / core / app / manager_context.c
1 /*************************************************************************
2 *
3 * Copyright 2020 highstreet technologies GmbH and others
4 *
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
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
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 ***************************************************************************/
17
18 #define _GNU_SOURCE
19
20 #include "manager.h"
21 #include "utils/log_utils.h"
22 #include "utils/sys_utils.h"
23 #include "utils/nts_utils.h"
24 #include <stdio.h>
25 #include <assert.h>
26
27 #include <sysrepo.h>
28 #include <sysrepo/values.h>
29
30 #include "core/framework.h"
31 #include "core/session.h"
32 #include "core/xpath.h"
33 #include "core/context.h"
34
35 manager_context_t *manager_context = 0;
36 docker_context_t *docker_context = 0;
37 int docker_context_count = 0;
38
39 static int manager_populate_sysrepo_network_function_list(void);
40 static int manager_populate_available_simulations(void);
41
42 int manager_context_init(void) {
43
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);
46     if(elem == 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;
49     }
50
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;
56     }
57
58     docker_context_count = docker_context_count;
59
60     const char **docker_filter = malloc(sizeof(char *) * docker_context_count);
61     if(docker_filter == 0) {
62         log_error("bad malloc\n");
63         free(function_types);
64         return NTS_ERR_FAILED;
65     }
66
67     for(int i = 0; i < docker_context_count; i++) {
68         docker_filter[i] = function_types[i]->ref;
69     }
70
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");
74         free(docker_filter);
75         free(function_types);
76         return NTS_ERR_FAILED;
77     }
78
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");
83         int pull_count = 0;
84         for(int i = 0; i < docker_context_count; i++) {
85             bool pull = true;
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) {
88                     pull = false;
89                 }
90             }
91             
92             if(pull) {
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");
97                 }
98                 else {
99                     log_add(1, LOG_COLOR_BOLD_GREEN"OK"LOG_COLOR_RESET"\n");
100                     pull_count++;
101                 }
102             }
103         }
104
105         if(pull_count) {
106             //reinit docker
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");
111                 free(docker_filter);
112                 free(function_types);
113                 return NTS_ERR_FAILED;
114             }
115         }
116     }
117     else {
118         log_add(1, LOG_COLOR_YELLOW"disabled"LOG_COLOR_RESET"\n");
119     }
120     free(docker_filter);
121
122
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];
133             
134             new_context_count++;
135
136         }
137         else {
138             free(docker_context[i].image);
139         }
140     }
141
142     free(function_types);
143     function_types = new_function_types;
144
145     free(docker_context);
146     docker_context = new_context;
147     docker_context_count = new_context_count;
148
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;
155     }
156
157     for(int i = 0; i < docker_context_count; i++) {
158         manager_context[i].ft = function_types[i];
159
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];
163
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");
167         
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);
172         }
173         else {
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");
177         }
178     }
179     free(function_types);
180
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;
186     }
187
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;
192     }
193
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;
198     }
199
200     return NTS_ERR_OK;
201 }
202
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);
209     }
210
211     free(manager_context);
212 }
213
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;
222     }
223
224     //either get values, or if data inconclusive, delete everything
225     if(value_count) {
226         log_add_verbose(2, "nts-manager instances found (%d). cleaning up for fresh start...\n", value_count);
227
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;
233             }
234         }
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;
239         }
240     }
241
242     //populate everything if needed
243     for(int i = 0; i < docker_context_count; i++) {
244         char *xpath = 0;
245
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;
251         }
252         free(xpath);
253
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;
259         }
260         free(xpath);
261
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;
267         }
268         free(xpath);
269
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;
275         }
276         free(xpath);
277
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;
283         }
284         free(xpath);
285
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;
291         }
292         free(xpath);
293
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;
299         }
300         free(xpath);
301
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;
308         }
309         free(xpath);
310
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;
316         }
317         free(xpath);
318
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;
324         }
325         free(xpath);
326     }
327
328     //apply all changes
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;
333     }
334
335     return NTS_ERR_OK;
336 }
337
338 static int manager_populate_available_simulations(void) {
339     assert_session();
340
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);
342     if(container == 0) {
343         log_error("lyd_new_path failed\n");
344         return NTS_ERR_FAILED;
345     }
346
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");
350             if(!list) {
351                 log_error("lyd_new failed\n");
352                 return NTS_ERR_FAILED;
353             }
354
355             struct lyd_node *rc = lyd_new_leaf(list, list->schema->module, "function-type", (const char *)manager_context[i].function_type);
356             if(rc == 0) {
357                 log_error("lyd_new_leaf failed\n");
358                 return NTS_ERR_FAILED;
359             }
360
361             rc = lyd_new_leaf(list, list->schema->module, "docker-image-name", docker_context[i].image);
362             if(rc == 0) {
363                 log_error("lyd_new_leaf failed\n");
364                 return NTS_ERR_FAILED;
365             }
366
367             rc = lyd_new_leaf(list, list->schema->module, "docker-version-tag", docker_context[i].available_images[j].tag);
368             if(rc == 0) {
369                 log_error("lyd_new_leaf failed\n");
370                 return NTS_ERR_FAILED;
371             }
372
373             rc = lyd_new_leaf(list, list->schema->module, "docker-repository", docker_context[i].available_images[j].repo);
374             if(rc == 0) {
375                 log_error("lyd_new_leaf failed\n");
376                 return NTS_ERR_FAILED;
377             }
378
379         }
380     }
381
382     //find top level container
383     struct lyd_node *root = container;
384     while(root->parent) {
385         root = root->parent;
386     }
387
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;
392     }
393
394     //apply all changes
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;
399     }
400
401     return NTS_ERR_OK;
402 }