48816610a6b79f3b9372988bfd74f222205e3a3a
[sim/o1-interface.git] / ntsimulator / ntsim-ng / core / app / manager.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 <stdio.h>
24 #include <assert.h>
25
26 #include <sysrepo.h>
27 #include <sysrepo/values.h>
28
29 #include "core/framework.h"
30 #include "core/session.h"
31 #include "core/context.h"
32 #include "core/docker.h"
33
34 #define NTS_MANAGER_MODULE                          "nts-manager"
35 #define NTS_SIMULATION_SCHEMA_XPATH                 "/nts-manager:simulation"
36 #define NTS_FUNCTION_LIST_SCHEMA_XPATH              "/nts-manager:simulation/network-functions/network-function"
37 #define NTS_SDN_CONTROLLER_CONFIG_XPATH             "/nts-manager:simulation/sdn-controller"
38 #define NTS_VES_ENDPOINT_CONFIG_XPATH               "/nts-manager:simulation/ves-endpoint"
39
40 #define NTS_NETWORK_FUNCTION_FTYPE_SCHEMA_XPATH     "/nts-network-function:simulation/network-function/function-type"
41
42 static manager_network_function_type *manager_context = 0;
43 static int manager_installed_function_types_count = 0;
44
45 static int manager_populate_sysrepo_network_function_list(void);
46 static int manager_populate_static_status(void);
47
48 static void manager_context_free(manager_network_function_type *context);
49
50 static int manager_process_change(int context_index, manager_network_function_type *new_context);
51 static int manager_change_cb(sr_session_ctx_t *session, const char *module_name, const char *xpath, sr_event_t event, uint32_t request_id, void *private_data);
52 static int manager_instances_get_items_cb(sr_session_ctx_t *session, const char *module_name, const char *xpath, const char *request_xpath, uint32_t request_id, struct lyd_node **parent, void *private_data);
53 static int manager_stats_get_items_cb(sr_session_ctx_t *session, const char *module_name, const char *xpath, const char *request_xpath, uint32_t request_id, struct lyd_node **parent, void *private_data);
54
55 int manager_run(void) {
56     assert_session();
57
58     log_message(1, LOG_COLOR_BOLD_YELLOW"\nrunning as MANAGER daemon...\n"LOG_COLOR_RESET);
59
60     manager_operations_init();
61     docker_device_init();
62
63     //get installed function types
64     struct lys_node_leaf *elem = (struct lys_node_leaf *)ly_ctx_get_node(session_context, 0, NTS_FUNCTION_LIST_SCHEMA_XPATH"/function-type", 0);
65     if(elem == 0) {
66         log_error("ly_ctx_get_node failed for xpath: %s", NTS_FUNCTION_LIST_SCHEMA_XPATH"/function-type");
67         return NTS_ERR_FAILED;
68     }
69
70     struct lys_ident **found = 0;
71     manager_installed_function_types_count = context_get_identity_leafs_of_type(elem->type.info.ident.ref[0], &found);
72     if(!manager_installed_function_types_count) {
73         log_error("error network functions");
74         return NTS_ERR_FAILED;
75     }
76
77     //initial list population
78     manager_context = (manager_network_function_type *)malloc(sizeof(manager_network_function_type) * manager_installed_function_types_count);
79     for(int i = 0; i < manager_installed_function_types_count; i++) {
80         manager_context[i].instance = 0;
81
82         manager_context[i].function_type = found[i];
83         asprintf(&manager_context[i].function_type_string, "%s:%s", found[i]->module->name, found[i]->name);
84         manager_context[i].docker_image_name = manager_context[i].function_type->ref;
85         manager_context[i].started_instances = 0;
86         manager_context[i].mounted_instances = 0;
87         manager_context[i].mount_point_addressing_method = strdup("docker-mapping");
88         manager_context[i].docker_instance_name = strdup(manager_context[i].function_type->name);
89         manager_context[i].docker_version_tag = strdup("latest");
90         manager_context[i].docker_repository = strdup("local");
91     }
92     free(found);
93
94     //do initial sysrepo list population
95     int rc = manager_populate_sysrepo_network_function_list();
96     if(rc != NTS_ERR_OK) {
97         log_error("manager_populate_sysrepo_network_function_list failed");
98         return NTS_ERR_FAILED;
99     }
100
101     rc = manager_populate_static_status();
102     if(rc != NTS_ERR_OK) {
103         log_error("manager_populate_static_status failed");
104         return NTS_ERR_FAILED;
105     }
106     
107     //subscribe to any changes on the list
108     rc = sr_module_change_subscribe(session_running, NTS_MANAGER_MODULE, NTS_SIMULATION_SCHEMA_XPATH, manager_change_cb, NULL, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
109     if(rc != SR_ERR_OK) {
110         log_error("could not subscribe to simulation changes");
111         return NTS_ERR_FAILED;
112     }
113
114     rc = sr_oper_get_items_subscribe(session_running, NTS_MANAGER_MODULE, NTS_FUNCTION_LIST_SCHEMA_XPATH, manager_instances_get_items_cb, NULL, SR_SUBSCR_CTX_REUSE, &session_subscription);
115     if(rc != SR_ERR_OK) {
116         log_error("could not subscribe to oper faults");
117         return 0;
118     }
119
120     rc = sr_oper_get_items_subscribe(session_running, NTS_MANAGER_MODULE, NTS_SIMULATION_SCHEMA_XPATH, manager_stats_get_items_cb, NULL, SR_SUBSCR_CTX_REUSE, &session_subscription);
121     if(rc != SR_ERR_OK) {
122         log_error("could not subscribe to oper faults");
123         return 0;
124     }
125
126     //daemonize
127     while(!framework_sigint) {
128         sleep(1);
129     }
130
131     for(int i = 0; i < manager_installed_function_types_count; i++) {
132         while(manager_context[i].started_instances) {
133             manager_stop_instance(&manager_context[i]);
134         }
135         manager_context_free(&manager_context[i]);
136     }
137
138     free(manager_context);
139
140     return NTS_ERR_OK;
141 }
142
143 static int manager_populate_sysrepo_network_function_list(void) {
144     //check whether everything is already populated, read and update (if previously ran)
145     sr_val_t *values = 0;
146     size_t value_count = 0;
147     int rc = sr_get_items(session_running, NTS_FUNCTION_LIST_SCHEMA_XPATH, 0, 0, &values, &value_count);
148     if(rc != SR_ERR_OK) {
149         log_error("get items failed");
150         return NTS_ERR_FAILED;
151     }
152
153     //either get values, or if data inconclusive, delete everything
154     if(value_count) {
155         log_message(2, "nts-manager instances found (%d). cleaning up for fresh start...\n", value_count);
156
157         for(int i = 0; i < value_count; i++) {           
158             rc = sr_delete_item(session_running, values[i].xpath, 0);
159             if(rc != SR_ERR_OK) {
160                 log_error("sr_delete_item failed");
161                 return NTS_ERR_FAILED;
162             }
163         }
164         rc = sr_apply_changes(session_running, 0, 0);
165         if(rc != SR_ERR_OK) {
166             log_error("sr_apply_changes failed");
167             return NTS_ERR_FAILED;
168         }
169     }
170
171     //populate everything if needed
172     for(int i = 0; i < manager_installed_function_types_count; i++) {
173         char *xpath = 0;
174
175         asprintf(&xpath, "%s[function-type='%s']/function-type", NTS_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type_string);
176         rc = sr_set_item_str(session_running, xpath, (const char *)manager_context[i].function_type_string, 0, 0);
177         if(rc != SR_ERR_OK) {
178             log_error("sr_set_item_str failed");
179             return NTS_ERR_FAILED;
180         }
181         free(xpath);
182
183         asprintf(&xpath, "%s[function-type='%s']/started-instances", NTS_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type_string);
184         rc = sr_set_item_str(session_running, xpath, "0", 0, 0);
185         if(rc != SR_ERR_OK) {
186             log_error("sr_set_item_str failed");
187             return NTS_ERR_FAILED;
188         }
189         free(xpath);
190
191         asprintf(&xpath, "%s[function-type='%s']/mounted-instances", NTS_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type_string);
192         rc = sr_set_item_str(session_running, xpath, "0", 0, 0);
193         if(rc != SR_ERR_OK) {
194             log_error("sr_set_item_str failed");
195             return NTS_ERR_FAILED;
196         }
197         free(xpath);
198
199         asprintf(&xpath, "%s[function-type='%s']/mount-point-addressing-method", NTS_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type_string);
200         rc = sr_set_item_str(session_running, xpath, (const char*)manager_context[i].mount_point_addressing_method, 0, 0);
201         if(rc != SR_ERR_OK) {
202             log_error("sr_set_item_str failed");
203             return NTS_ERR_FAILED;
204         }
205         free(xpath);
206
207         asprintf(&xpath, "%s[function-type='%s']/docker-instance-name", NTS_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type_string);
208         rc = sr_set_item_str(session_running, xpath, (const char*)manager_context[i].docker_instance_name, 0, 0);
209         if(rc != SR_ERR_OK) {
210             log_error("sr_set_item_str failed");
211             return NTS_ERR_FAILED;
212         }
213         free(xpath);
214
215         asprintf(&xpath, "%s[function-type='%s']/docker-version-tag", NTS_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type_string);
216         rc = sr_set_item_str(session_running, xpath, (const char*)manager_context[i].docker_version_tag, 0, 0);
217         if(rc != SR_ERR_OK) {
218             log_error("sr_set_item_str failed");
219             return NTS_ERR_FAILED;
220         }
221         free(xpath);
222
223         asprintf(&xpath, "%s[function-type='%s']/docker-repository", NTS_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type_string);
224         rc = sr_set_item_str(session_running, xpath, (const char*)manager_context[i].docker_repository, 0, 0);
225         if(rc != SR_ERR_OK) {
226             log_error("sr_set_item_str failed");
227             return NTS_ERR_FAILED;
228         }
229         free(xpath);
230     }
231
232     char int_to_str[30];
233
234     //setup sdn-controller defaults
235     if(strlen(framework_environment.sdn_controller_ip)) {
236         rc = sr_set_item_str(session_running, NTS_SDN_CONTROLLER_CONFIG_XPATH"/controller-ip", (const char*)framework_environment.sdn_controller_ip, 0, 0);
237         if(rc != SR_ERR_OK) {
238             log_error("sr_set_item_str failed");
239             return NTS_ERR_FAILED;
240         }
241     }
242
243     sprintf(int_to_str, "%d", framework_environment.sdn_controller_port);
244     rc = sr_set_item_str(session_running, NTS_SDN_CONTROLLER_CONFIG_XPATH"/controller-port", (const char*)int_to_str, 0, 0);
245     if(rc != SR_ERR_OK) {
246         log_error("sr_set_item_str failed");
247         return NTS_ERR_FAILED;
248     }
249
250     sprintf(int_to_str, "%d", framework_environment.sdn_controller_callhome_port);
251     rc = sr_set_item_str(session_running, NTS_SDN_CONTROLLER_CONFIG_XPATH"/controller-netconf-call-home-port", (const char*)int_to_str, 0, 0);
252     if(rc != SR_ERR_OK) {
253         log_error("sr_set_item_str failed");
254         return NTS_ERR_FAILED;
255     }
256
257     if(strlen(framework_environment.sdn_controller_username)) {
258         rc = sr_set_item_str(session_running, NTS_SDN_CONTROLLER_CONFIG_XPATH"/controller-username", (const char*)framework_environment.sdn_controller_username, 0, 0);
259         if(rc != SR_ERR_OK) {
260             log_error("sr_set_item_str failed");
261             return NTS_ERR_FAILED;
262         }
263     }
264
265     if(strlen(framework_environment.sdn_controller_password)) {
266         rc = sr_set_item_str(session_running, NTS_SDN_CONTROLLER_CONFIG_XPATH"/controller-password", (const char*)framework_environment.sdn_controller_password, 0, 0);
267         if(rc != SR_ERR_OK) {
268             log_error("sr_set_item_str failed");
269             return NTS_ERR_FAILED;
270         }
271     }
272
273     //setup ves-endpoint details
274     if(strlen(framework_environment.ves_endpoint_protocol)) {
275         rc = sr_set_item_str(session_running, NTS_VES_ENDPOINT_CONFIG_XPATH"/ves-endpoint-protocol", (const char*)framework_environment.ves_endpoint_protocol, 0, 0);
276         if(rc != SR_ERR_OK) {
277             log_error("sr_set_item_str failed");
278             return NTS_ERR_FAILED;
279         }
280     }
281
282     if(strlen(framework_environment.ves_endpoint_ip)) {
283         rc = sr_set_item_str(session_running, NTS_VES_ENDPOINT_CONFIG_XPATH"/ves-endpoint-ip", (const char*)framework_environment.ves_endpoint_ip, 0, 0);
284         if(rc != SR_ERR_OK) {
285             log_error("sr_set_item_str failed");
286             return NTS_ERR_FAILED;
287         }
288     }
289
290     sprintf(int_to_str, "%d", framework_environment.ves_endpoint_port);
291     rc = sr_set_item_str(session_running, NTS_VES_ENDPOINT_CONFIG_XPATH"/ves-endpoint-port", (const char*)int_to_str, 0, 0);
292     if(rc != SR_ERR_OK) {
293         log_error("sr_set_item_str failed");
294         return NTS_ERR_FAILED;
295     }
296
297     if(strlen(framework_environment.ves_endpoint_auth_method)) {
298         rc = sr_set_item_str(session_running, NTS_VES_ENDPOINT_CONFIG_XPATH"/ves-endpoint-auth-method", (const char*)framework_environment.ves_endpoint_auth_method, 0, 0);
299         if(rc != SR_ERR_OK) {
300             log_error("sr_set_item_str failed");
301             return NTS_ERR_FAILED;
302         }
303     }
304
305     if(strlen(framework_environment.ves_endpoint_username)) {
306         rc = sr_set_item_str(session_running, NTS_VES_ENDPOINT_CONFIG_XPATH"/ves-endpoint-username", (const char*)framework_environment.ves_endpoint_username, 0, 0);
307         if(rc != SR_ERR_OK) {
308             log_error("sr_set_item_str failed");
309             return NTS_ERR_FAILED;
310         }
311     }
312
313     if(strlen(framework_environment.ves_endpoint_password)) {
314         rc = sr_set_item_str(session_running, NTS_VES_ENDPOINT_CONFIG_XPATH"/ves-endpoint-password", (const char*)framework_environment.ves_endpoint_password, 0, 0);
315         if(rc != SR_ERR_OK) {
316             log_error("sr_set_item_str failed");
317             return NTS_ERR_FAILED;
318         }
319     }
320
321     if(strlen(framework_environment.ves_endpoint_certificate)) {
322         rc = sr_set_item_str(session_running, NTS_VES_ENDPOINT_CONFIG_XPATH"/ves-endpoint-certificate", (const char*)framework_environment.ves_endpoint_certificate, 0, 0);
323         if(rc != SR_ERR_OK) {
324             log_error("sr_set_item_str failed");
325             return NTS_ERR_FAILED;
326         }
327     }
328
329     rc = sr_set_item_str(session_running, NTS_NETWORK_FUNCTION_FTYPE_SCHEMA_XPATH, "NTS_FUNCTION_TYPE_MANAGER", 0, 0);
330     if(rc != SR_ERR_OK) {
331         log_error("sr_set_item_str failed");
332         return NTS_ERR_FAILED;
333     }
334
335
336     //apply all changes
337     rc = sr_apply_changes(session_running, 0, 0);
338     if(rc != SR_ERR_OK) {
339         log_error("sr_apply_changes failed: %s", sr_strerror(rc));
340         return NTS_ERR_FAILED;
341     }
342
343     return NTS_ERR_OK;
344 }
345
346 static int manager_populate_static_status(void) {
347     assert_session();
348
349     char int_to_str[30];
350
351     //setup sdn-controller defaults
352     sprintf(int_to_str, "%d", framework_environment.host_base_port);
353     int rc = sr_set_item_str(session_operational, NTS_SIMULATION_SCHEMA_XPATH"/base-port", (const char*)int_to_str, 0, 0);
354     if(rc != SR_ERR_OK) {
355         log_error("sr_set_item_str failed");
356         return NTS_ERR_FAILED;
357     }
358
359     sprintf(int_to_str, "%d", framework_environment.ssh_connections);
360     rc = sr_set_item_str(session_operational, NTS_SIMULATION_SCHEMA_XPATH"/ssh-connections", (const char*)int_to_str, 0, 0);
361     if(rc != SR_ERR_OK) {
362         log_error("sr_set_item_str failed");
363         return NTS_ERR_FAILED;
364     }
365
366     sprintf(int_to_str, "%d", framework_environment.tls_connections);
367     rc = sr_set_item_str(session_operational, NTS_SIMULATION_SCHEMA_XPATH"/tls-connections", (const char*)int_to_str, 0, 0);
368     if(rc != SR_ERR_OK) {
369         log_error("sr_set_item_str failed");
370         return NTS_ERR_FAILED;
371     }
372
373     //apply all changes
374     rc = sr_apply_changes(session_operational, 0, 0);
375     if(rc != SR_ERR_OK) {
376         log_error("sr_apply_changes failed");
377         return NTS_ERR_FAILED;
378     }
379
380     return NTS_ERR_OK;
381 }
382
383 static void manager_context_free(manager_network_function_type *context) {
384     assert(context);
385
386     free(context->function_type_string);
387     free(context->mount_point_addressing_method);
388     free(context->docker_instance_name);
389     free(context->docker_version_tag);
390     free(context->docker_repository);
391 }
392
393 //take note that this happens in the sysrepo thread
394 static int manager_process_change(int context_index, manager_network_function_type *new_context) {
395     assert(context_index < manager_installed_function_types_count);
396     assert(new_context);
397
398     manager_network_function_type *current_context = &manager_context[context_index];
399     int rc = 0;
400
401     current_context->data_changed |= new_context->data_changed;
402
403     //process changes, and update data in current_context to resemble new_context
404     if(new_context->docker_instance_name != 0) {
405         free(current_context->docker_instance_name);
406         current_context->docker_instance_name = strdup(new_context->docker_instance_name);
407     }
408
409     if(new_context->docker_version_tag != 0) {
410         free(current_context->docker_version_tag);
411         current_context->docker_version_tag = strdup(new_context->docker_version_tag);
412     }
413
414     if(new_context->docker_repository != 0) {
415         free(current_context->docker_repository);
416         current_context->docker_repository = strdup(new_context->docker_repository);
417     }
418
419     if(new_context->mount_point_addressing_method != 0) {
420         free(current_context->mount_point_addressing_method);
421         current_context->mount_point_addressing_method = strdup(new_context->mount_point_addressing_method);
422     }
423
424     if(new_context->started_instances != -1) {
425         if(new_context->started_instances < current_context->started_instances) {
426             //remove started instances
427             while(current_context->started_instances > new_context->started_instances) {
428                 log_message(2, "stopping instance of type %s\n", current_context->function_type_string);
429                 rc = manager_stop_instance(current_context);
430                 if(rc != NTS_ERR_OK) {
431                     log_error("manager_stop_instance failed");
432                     return NTS_ERR_FAILED;
433                     break;
434                 }
435             }
436         }
437         else if(new_context->started_instances > current_context->started_instances) {
438             //add started instances
439             while(current_context->started_instances < new_context->started_instances) {
440                 log_message(2, "staring instance of type %s\n", current_context->function_type_string);
441                 rc = manager_start_instance(current_context);
442                 if(rc != NTS_ERR_OK) {
443                     log_error("manager_start_instance failed");
444                     return NTS_ERR_FAILED;
445                     break;
446                 }
447             }
448         }
449     }
450
451     if(new_context->mounted_instances != -1) {
452         if(new_context->mounted_instances < current_context->mounted_instances) {
453             //remove mounted instances
454             while(current_context->mounted_instances > new_context->mounted_instances) {
455                 log_message(2, "unmounting instance of type %s\n", current_context->function_type_string);
456                 rc = manager_unmount_instance(current_context);
457                 if(rc != NTS_ERR_OK) {
458                     log_error("manager_unmount_instance failed");
459                     break;
460                 }
461             }
462         }
463         else if(new_context->mounted_instances > current_context->mounted_instances) {
464             //add mounted instances
465             while(current_context->mounted_instances < new_context->mounted_instances) {
466                 log_message(2, "mouting instance of type %s\n", current_context->function_type_string);
467                 rc = manager_mount_instance(current_context);
468                 if(rc != NTS_ERR_OK) {
469                     log_error("manager_mount_instance failed");
470                     break;
471                 }
472             }
473         }
474     }
475
476     return NTS_ERR_OK;
477 }
478
479 static int manager_change_cb(sr_session_ctx_t *session, const char *module_name, const char *xpath, sr_event_t event, uint32_t request_id, void *private_data) {
480     sr_change_iter_t *it = 0;
481     int rc = SR_ERR_OK;
482     sr_change_oper_t oper;
483     sr_val_t *old_value = 0;
484     sr_val_t *new_value = 0;
485
486     if(event == SR_EV_CHANGE) {
487         manager_network_function_type new_context;
488         new_context.function_type = 0;          //not to be used. use only from current_context
489         new_context.function_type_string = 0;   //not to be used. use only from current_context
490         int index = -1;
491
492         rc = sr_get_changes_iter(session, NTS_FUNCTION_LIST_SCHEMA_XPATH"//.", &it);
493         if(rc != SR_ERR_OK) {
494             log_error("sr_get_changes_iter failed");
495             return SR_ERR_VALIDATION_FAILED;
496         }
497
498         while((rc = sr_get_change_next(session, it, &oper, &old_value, &new_value)) == SR_ERR_OK) {
499             char *ov = sr_val_to_str(old_value);
500             char *nv = sr_val_to_str(new_value);
501
502             //get function type and index
503             char *function_type_string = strdup(strstr(new_value->xpath, "function-type='") + 15);
504             *strchr(function_type_string, '\'') = 0;
505             
506             //if context is new
507             if((new_context.function_type_string == 0) || (strcmp(new_context.function_type_string, function_type_string) != 0)) {
508
509                 if(new_context.function_type_string != 0) {
510                     if(manager_process_change(index, &new_context) != NTS_ERR_OK) {
511                         manager_context_free(&new_context);
512                         return SR_ERR_VALIDATION_FAILED;
513                     }
514
515                     manager_context_free(&new_context);
516                 }
517
518                 //-1 means no change
519                 new_context.function_type_string = function_type_string;
520                 new_context.started_instances = -1;
521                 new_context.mounted_instances = -1;
522                 new_context.mount_point_addressing_method = 0;
523                 new_context.docker_instance_name = 0;
524                 new_context.docker_version_tag = 0;
525                 new_context.docker_repository = 0;
526
527                 new_context.data_changed = false;
528
529                 //find intex in manager_context[]
530                 for(int i = 0; i < manager_installed_function_types_count; i++) {
531                     if(strcmp(function_type_string, manager_context[i].function_type_string) == 0) {
532                         index = i;
533                         break;
534                     }
535                 }
536             }
537
538             char *leaf_path  = strdup(strstr(new_value->xpath, "']/") + 3);
539             if(strcmp(leaf_path, "started-instances") == 0) {
540                 new_context.started_instances = new_value->data.uint16_val;
541             }
542             else if(strcmp(leaf_path, "mounted-instances") == 0) {
543                 new_context.mounted_instances = new_value->data.uint16_val;
544             }
545             else if(strcmp(leaf_path, "mount-point-addressing-method") == 0) {
546                 new_context.mount_point_addressing_method = strdup(nv);
547             }
548             else if(strcmp(leaf_path, "docker-instance-name") == 0) {
549                 new_context.docker_instance_name = strdup(nv);
550             }
551             else if(strcmp(leaf_path, "docker-version-tag") == 0) {
552                 new_context.docker_version_tag = strdup(nv);
553             }
554             else if(strcmp(leaf_path, "docker-repository") == 0) {
555                 new_context.docker_repository = strdup(nv);
556             }
557             else {
558                 new_context.data_changed = true;
559             }
560
561             free(leaf_path);
562             free(ov);
563             free(nv);
564             sr_free_val(old_value);
565             sr_free_val(new_value);
566         }
567
568         sr_free_change_iter(it);
569         
570         if(index != -1) {
571             if(manager_process_change(index, &new_context) != NTS_ERR_OK) {
572                 manager_context_free(&new_context);
573                 return SR_ERR_VALIDATION_FAILED;
574             }
575
576             manager_context_free(&new_context);
577         }
578     }
579     else if(event == SR_EV_DONE) {
580         bool global_change = true;
581
582         rc = sr_get_changes_iter(session, NTS_SIMULATION_SCHEMA_XPATH"//.", &it);
583         if(rc != SR_ERR_OK) {
584             log_error("sr_get_changes_iter failed");
585             return SR_ERR_VALIDATION_FAILED;
586         }
587
588         while((rc = sr_get_change_next(session, it, &oper, &old_value, &new_value)) == SR_ERR_OK) {
589             if(strstr(new_value->xpath, NTS_FUNCTION_LIST_SCHEMA_XPATH) == new_value->xpath) {
590                 global_change = false;
591                 sr_free_val(old_value);
592                 sr_free_val(new_value);
593                 break;
594             }
595
596             sr_free_val(old_value);
597             sr_free_val(new_value);
598         }
599
600         sr_free_change_iter(it);
601
602         // commit all updates
603         for(int i = 0; i < manager_installed_function_types_count; i++) {
604             for(int j = 0; j < manager_context[i].started_instances; j++) {
605                 if(global_change || manager_context[i].data_changed || (manager_context[i].instance[j].is_configured == false)) {
606                     log_message(2, "configuring instance %d of type %s\n", j, manager_context[i].function_type_string);
607                     rc = manager_config_instance(&manager_context[i], &manager_context[i].instance[j]);
608                     if(rc != NTS_ERR_OK) {
609                         log_error("manager_config_instance failed");
610                     }
611                 }
612             }
613
614             manager_context[i].data_changed = false;
615         }
616         global_change = false;
617     }
618
619     return SR_ERR_OK;
620 }
621
622 static int manager_instances_get_items_cb(sr_session_ctx_t *session, const char *module_name, const char *xpath, const char *request_xpath, uint32_t request_id, struct lyd_node **parent, void *private_data) {
623     
624     char value[100];
625
626     *parent = lyd_new_path(NULL, sr_get_context(sr_session_get_connection(session)), NTS_FUNCTION_LIST_SCHEMA_XPATH, 0, 0, 0);
627     if(*parent == 0) {
628         log_error("lyd_new_path failed");
629         return SR_ERR_OPERATION_FAILED;
630     }
631
632     for(int i = 0; i < manager_installed_function_types_count; i++) {
633         char *ftype_path = 0;
634         asprintf(&ftype_path, "%s[function-type='%s']/instances/instance", NTS_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type_string);
635         for(int j = 0; j < manager_context[i].started_instances; j++) {
636             char *instance_path = 0;
637             asprintf(&instance_path, "%s[name='%s']", ftype_path, manager_context[i].instance[j].name);
638
639             char *full_path = 0;
640
641             asprintf(&full_path, "%s/mount-point-addressing-method", instance_path);
642             if(lyd_new_path(*parent, NULL, full_path, manager_context[i].instance[j].mount_point_addressing_method, 0, 0) == 0) {
643                 log_error("lyd_new_path failed");
644                 return SR_ERR_OPERATION_FAILED;
645             }
646             free(full_path);
647
648             asprintf(&full_path, "%s/networking/docker-ip", instance_path);
649             if(lyd_new_path(*parent, NULL, full_path, manager_context[i].instance[j].docker_ip, 0, 0) == 0) {
650                 log_error("lyd_new_path failed");
651                 return SR_ERR_OPERATION_FAILED;
652             }
653             free(full_path);
654
655             asprintf(&full_path, "%s/networking/docker-port", instance_path);
656             sprintf(value, "%d", manager_context[i].instance[j].docker_port);
657             if(lyd_new_path(*parent, NULL, full_path, value, 0, 0) == 0) {
658                 log_error("lyd_new_path failed");
659                 return SR_ERR_OPERATION_FAILED;
660             }
661             free(full_path);
662
663             asprintf(&full_path, "%s/networking/host-ip", instance_path);
664             if(lyd_new_path(*parent, NULL, full_path, manager_context[i].instance[j].host_ip, 0, 0) == 0) {
665                 log_error("lyd_new_path failed");
666                 return SR_ERR_OPERATION_FAILED;
667             }
668             free(full_path);
669
670             asprintf(&full_path, "%s/networking/host-port", instance_path);
671             sprintf(value, "%d", manager_context[i].instance[j].host_port);
672             if(lyd_new_path(*parent, NULL, full_path, value, 0, 0) == 0) {
673                 log_error("lyd_new_path failed");
674                 return SR_ERR_OPERATION_FAILED;
675             }
676             free(full_path);
677
678             free(instance_path);
679         }
680         free(ftype_path);
681     }
682
683     return SR_ERR_OK;
684 }
685
686 static int manager_stats_get_items_cb(sr_session_ctx_t *session, const char *module_name, const char *xpath, const char *request_xpath, uint32_t request_id, struct lyd_node **parent, void *private_data) {
687     char value[128];
688
689     *parent = lyd_new_path(NULL, sr_get_context(sr_session_get_connection(session)), NTS_SIMULATION_SCHEMA_XPATH, 0, 0, 0);
690     if(*parent == 0) {
691         return SR_ERR_OPERATION_FAILED;
692     }
693
694     docker_usage_t usage = docker_usage_get(manager_context, manager_installed_function_types_count);
695
696     sprintf(value, "%.2f", usage.cpu);
697     if(lyd_new_path(*parent, NULL, NTS_SIMULATION_SCHEMA_XPATH"/cpu-usage", value, 0, 0) == 0) {
698         return SR_ERR_OPERATION_FAILED;
699     }
700
701     sprintf(value, "%.0f", usage.mem);
702     if(lyd_new_path(*parent, NULL, NTS_SIMULATION_SCHEMA_XPATH"/mem-usage", value, 0, 0) == 0) {
703         return SR_ERR_OPERATION_FAILED;
704     }
705
706     //setup sdn-controller defaults
707     sprintf(value, "%d", framework_environment.host_base_port);
708     if(lyd_new_path(*parent, NULL, NTS_SIMULATION_SCHEMA_XPATH"/base-port", value, 0, 0) == 0) {
709         return SR_ERR_OPERATION_FAILED;
710     }
711
712     sprintf(value, "%d", framework_environment.ssh_connections);
713     if(lyd_new_path(*parent, NULL, NTS_SIMULATION_SCHEMA_XPATH"/ssh-connections", value, 0, 0) == 0) {
714         return SR_ERR_OPERATION_FAILED;
715     }
716
717     sprintf(value, "%d", framework_environment.tls_connections);
718     if(lyd_new_path(*parent, NULL, NTS_SIMULATION_SCHEMA_XPATH"/tls-connections", value, 0, 0) == 0) {
719         return SR_ERR_OPERATION_FAILED;
720     }
721
722     return SR_ERR_OK;
723 }