Add VES stndDefined PM and subscription for O-DU.
[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         sr_free_values(values, value_count);
242     }
243
244     //populate everything if needed
245     for(int i = 0; i < docker_context_count; i++) {
246         char *xpath = 0;
247
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;
253         }
254         free(xpath);
255
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;
261         }
262         free(xpath);
263
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;
269         }
270         free(xpath);
271
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;
277         }
278         free(xpath);
279
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;
285         }
286         free(xpath);
287
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;
293         }
294         free(xpath);
295
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;
301         }
302         free(xpath);
303
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;
310         }
311         free(xpath);
312
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;
318         }
319         free(xpath);
320
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;
326         }
327         free(xpath);
328     }
329
330     //apply all changes
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;
335     }
336
337     return NTS_ERR_OK;
338 }
339
340 static int manager_populate_available_simulations(void) {
341     assert_session();
342
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);
344     if(container == 0) {
345         log_error("lyd_new_path failed\n");
346         return NTS_ERR_FAILED;
347     }
348
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");
352             if(!list) {
353                 log_error("lyd_new failed\n");
354                 return NTS_ERR_FAILED;
355             }
356
357             struct lyd_node *rc = lyd_new_leaf(list, list->schema->module, "function-type", (const char *)manager_context[i].function_type);
358             if(rc == 0) {
359                 log_error("lyd_new_leaf failed\n");
360                 return NTS_ERR_FAILED;
361             }
362
363             rc = lyd_new_leaf(list, list->schema->module, "docker-image-name", docker_context[i].image);
364             if(rc == 0) {
365                 log_error("lyd_new_leaf failed\n");
366                 return NTS_ERR_FAILED;
367             }
368
369             rc = lyd_new_leaf(list, list->schema->module, "docker-version-tag", docker_context[i].available_images[j].tag);
370             if(rc == 0) {
371                 log_error("lyd_new_leaf failed\n");
372                 return NTS_ERR_FAILED;
373             }
374
375             rc = lyd_new_leaf(list, list->schema->module, "docker-repository", docker_context[i].available_images[j].repo);
376             if(rc == 0) {
377                 log_error("lyd_new_leaf failed\n");
378                 return NTS_ERR_FAILED;
379             }
380
381         }
382     }
383
384     //find top level container
385     struct lyd_node *root = container;
386     while(root->parent) {
387         root = root->parent;
388     }
389
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;
394     }
395
396     //apply all changes
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;
401     }
402
403     return NTS_ERR_OK;
404 }