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