f7ec705fa2f31f3af00f3840df40af49cd6a9708
[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/xpath.h"
32 #include "core/context.h"
33
34 #include "app_common.h"
35
36 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);
37 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);
38
39 int manager_run(void) {
40     assert_session();
41
42     log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"starting MANAGER...\n"LOG_COLOR_RESET);
43
44     int rc = app_common_init();
45     if(rc != NTS_ERR_OK) {
46         log_error("app_common_init failed\n");
47         return NTS_ERR_FAILED;
48     }
49     
50     //init manager context
51     rc = manager_context_init();
52     if(rc != NTS_ERR_OK) {
53         log_error("manager_context_init failed\n");
54         return NTS_ERR_FAILED;
55     }
56
57     //init operations
58     rc = manager_operations_init();
59     if(rc != NTS_ERR_OK) {
60         log_error("manager_operations_init failed\n");
61         return NTS_ERR_FAILED;
62     }
63
64     //print everything on the manager's screen
65     log_add_verbose(1, LOG_COLOR_BOLD_CYAN"Available images: \n"LOG_COLOR_RESET);
66     for(int i = 0; i < docker_context_count; i++) {
67         log_add_verbose(1, LOG_COLOR_BOLD_CYAN"- %s\n"LOG_COLOR_RESET, docker_context[i].image);
68         for(int j = 0; j < docker_context[i].available_images_count; j++) {
69             log_add_verbose(1, "   - "LOG_COLOR_RED"%s/"LOG_COLOR_CYAN"%s"LOG_COLOR_RESET":"LOG_COLOR_YELLOW"%s\n"LOG_COLOR_RESET, docker_context[i].available_images[j].repo, docker_context[i].image, docker_context[i].available_images[j].tag);
70         }
71     }
72     
73     // subscribe to any changes on the list
74     rc = sr_module_change_subscribe(session_running, NTS_MANAGER_MODULE, NTS_MANAGER_SIMULATION_SCHEMA_XPATH, manager_change_cb, NULL, 0, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_UPDATE, &session_subscription);
75     if(rc != SR_ERR_OK) {
76         log_error("could not subscribe to simulation changes\n");
77         return NTS_ERR_FAILED;
78     }
79
80     //subscribe to stats
81     rc = sr_oper_get_items_subscribe(session_running, NTS_MANAGER_MODULE, NTS_MANAGER_SIMULATION_SCHEMA_XPATH, manager_sr_stats_get_items_cb, NULL, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_OPER_MERGE, &session_subscription);
82     if(rc != SR_ERR_OK) {
83         log_error("could not subscribe to oper faults\n");
84         return NTS_ERR_FAILED;
85     }
86
87     //subscribe to instances oper change
88     rc = sr_oper_get_items_subscribe(session_running, NTS_MANAGER_MODULE, NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, manager_instances_get_items_cb, NULL, SR_SUBSCR_CTX_REUSE, &session_subscription);
89     if(rc != SR_ERR_OK) {
90         log_error("could not subscribe to oper faults\n");
91         return 0;
92     }
93
94     rc = manager_sr_update_static_stats();
95     if(rc != NTS_ERR_OK) {
96         log_error("manager_sr_update_static_stats failed\n");
97         return NTS_ERR_FAILED;
98     }
99
100     log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"nts-ng manager"LOG_COLOR_RESET" v%s build %s\n", framework_environment.nts.version, framework_environment.nts.build_time);
101     log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"Host IP:"LOG_COLOR_RESET" %s\n", framework_environment.host.ip);
102     log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"Host ports"LOG_COLOR_RESET": ");
103     if(framework_environment.settings.ssh_connections) {
104         log_add(1, "NETCONF SSH: %d (%d)", framework_environment.host.ssh_base_port, framework_environment.settings.ssh_connections);
105     }
106     else {
107         log_add(1, "NETCONF SSH: disabled");
108     }
109     if(framework_environment.settings.tls_connections) {
110         log_add(1, " | NETCONF TLS: %d (%d)", framework_environment.host.tls_base_port, framework_environment.settings.tls_connections);
111     }
112     else {
113         log_add(1, " | NETCONF TLS: disabled");
114     }
115     if(framework_environment.settings.ftp_connections) {
116         log_add(1, " | FTP: %d (%d)", framework_environment.host.ftp_base_port, framework_environment.settings.ftp_connections);
117     }
118     else {
119         log_add(1, " | FTP: disabled");
120     }
121     if(framework_environment.settings.sftp_connections) {
122         log_add(1, " | SFTP: %d (%d)", framework_environment.host.sftp_base_port, framework_environment.settings.sftp_connections);
123     }
124     else {
125         log_add(1, " | SFTP: disabled");
126     }
127     log_add(1,"\n");
128     log_add_verbose(1, LOG_COLOR_BOLD_GREEN"started!\n"LOG_COLOR_RESET);
129
130     //daemonize
131     while(!framework_sigint) {
132         manager_operations_loop();  //caution - this function time-waits (1sec) on manager_operation_sem
133     }
134
135     manager_operations_free();
136     manager_context_free();
137
138     return NTS_ERR_OK;
139 }
140
141 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) {
142     sr_change_iter_t *it = 0;
143     sr_change_oper_t oper;
144     sr_val_t *old_value = 0;
145     sr_val_t *new_value = 0;
146     int rc = SR_ERR_OK;
147
148     if(manager_sr_get_context_sync()) {
149         return SR_ERR_OK;
150     }
151
152     if(event == SR_EV_UPDATE) {
153         rc = sr_get_changes_iter(session, NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH"//.", &it);
154         if(rc != SR_ERR_OK) {
155             log_error("sr_get_changes_iter failed\n");
156             return SR_ERR_VALIDATION_FAILED;
157         }
158
159         manager_operation_t *new_oper = 0;
160         while((rc = sr_get_change_next(session, it, &oper, &old_value, &new_value)) == SR_ERR_OK) {
161             if(new_value) {
162                 //get function type and index
163                 char *nv = sr_val_to_str(new_value);
164
165                 char function_type[512];
166                 strncpy(function_type, strstr(new_value->xpath, "function-type='") + 15, 510);
167                 *strchr(function_type, '\'') = 0;
168                 
169                 //if context is new
170                 if((new_oper == 0) || (strcmp(new_oper->function_type, function_type) != 0)) {
171
172                     if(new_oper == 0) {
173                         manager_operations_begin();
174                     }
175                     else {
176                         //validate and add the operation
177                         if(manager_operations_validate(new_oper) != NTS_ERR_OK) {
178                             manager_operations_free_oper(new_oper);
179                             manager_operations_finish_with_error();
180                             return SR_ERR_VALIDATION_FAILED;
181                         }
182                         
183                         manager_operations_add(new_oper);
184                     }
185
186                     new_oper = manager_operations_new_oper(MANAGER_OPERATION_EDIT);
187                     new_oper->function_type = strdup(function_type);
188
189                     //get ft_idnex
190                     for(int i = 0; i < docker_context_count; i++) {
191                         if(strcmp(new_oper->function_type, manager_context[i].function_type) == 0) {
192                             new_oper->ft_index = i;
193                             break;
194                         }
195                     }
196
197                     if(new_oper->ft_index == -1) {
198                         log_error("function-type not found: %s\n", new_oper->function_type);
199                         return SR_ERR_VALIDATION_FAILED;
200                     }
201                 }
202
203                 char *leaf_path  = strdup(strstr(new_value->xpath, "']/") + 3);
204                 if(strcmp(leaf_path, "started-instances") == 0) {
205                     new_oper->started_instances = new_value->data.uint16_val;
206                     rc = sr_set_item(session, old_value->xpath, old_value, 0);
207                     if(rc != SR_ERR_OK) {
208                         log_error("sr_set_item failed\n");
209                         return SR_ERR_VALIDATION_FAILED;
210                     }
211                 }
212                 else if(strcmp(leaf_path, "mounted-instances") == 0) {
213                     new_oper->mounted_instances = new_value->data.uint16_val;
214                     rc = sr_set_item(session, old_value->xpath, old_value, 0);
215                     if(rc != SR_ERR_OK) {
216                         log_error("sr_set_item failed\n");
217                         return SR_ERR_VALIDATION_FAILED;
218                     }
219                 }
220                 else if(strcmp(leaf_path, "docker-instance-name") == 0) {
221                     new_oper->docker_instance_name = strdup(nv);
222                     free(manager_context[new_oper->ft_index].docker_instance_name);
223                     manager_context[new_oper->ft_index].docker_instance_name = strdup(nv);
224                 }
225                 else if(strcmp(leaf_path, "docker-version-tag") == 0) {
226                     new_oper->docker_version_tag = strdup(nv);
227                     free(manager_context[new_oper->ft_index].docker_version_tag);
228                     manager_context[new_oper->ft_index].docker_version_tag = strdup(nv);
229                 }
230                 else if(strcmp(leaf_path, "docker-repository") == 0) {
231                     new_oper->docker_repository = strdup(nv);
232                     free(manager_context[new_oper->ft_index].docker_repository);
233                     manager_context[new_oper->ft_index].docker_repository = strdup(nv);
234                 }
235                 else if(strcmp(leaf_path, "mount-point-addressing-method") == 0) {
236                     //update conetxt
237                     free(manager_context[new_oper->ft_index].mount_point_addressing_method);
238                     manager_context[new_oper->ft_index].mount_point_addressing_method = strdup(nv);
239                 }
240                 else {
241                     //mark each instance for reconfiguration
242                     for(int i = 0; i < manager_context[new_oper->ft_index].started_instances; i++) {
243                         manager_context[new_oper->ft_index].instance[i].is_configured = false;
244                     }
245                 }
246
247                 free(leaf_path);
248                 free(nv);
249             }
250
251             sr_free_val(old_value);
252             sr_free_val(new_value);
253         }
254
255         sr_free_change_iter(it);
256
257         //validate and add the operation, if any; can be 0 if no modifications to NF list
258         if(new_oper) {
259             if(manager_operations_validate(new_oper) != NTS_ERR_OK) {
260                 manager_operations_free_oper(new_oper);
261                 manager_operations_finish_with_error();
262                 return SR_ERR_VALIDATION_FAILED;
263             }
264
265             manager_operations_add(new_oper);
266         }
267     }
268     else if(event == SR_EV_CHANGE) {
269     }
270     else if(event == SR_EV_DONE) {
271         bool global_change = false;
272
273         // go throughout all the changes, not just NF list
274         rc = sr_get_changes_iter(session, NTS_MANAGER_SIMULATION_SCHEMA_XPATH"//.", &it);
275         if(rc != SR_ERR_OK) {
276             log_error("sr_get_changes_iter failed\n");
277             return SR_ERR_VALIDATION_FAILED;
278         }
279
280         while((rc = sr_get_change_next(session, it, &oper, &old_value, &new_value)) == SR_ERR_OK) {
281             if(new_value) {
282                 if(strstr(new_value->xpath, NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH) != new_value->xpath) {
283                     global_change = true;
284                     sr_free_val(old_value);
285                     sr_free_val(new_value);
286                     break;
287                 }
288             }
289
290             sr_free_val(old_value);
291             sr_free_val(new_value);
292         }
293
294         sr_free_change_iter(it);
295
296         if(global_change) {
297             //mark each instance for reconfiguration
298             for(int i = 0; i < docker_context_count; i++) {
299                 for(int j = 0; j < manager_context[i].started_instances; j++) {
300                     manager_context[i].instance[j].is_configured = false;
301                 }
302             }
303         }
304
305         manager_operations_finish_and_execute();   //from this point on, manager_operations_loop will take over
306     }
307
308     return SR_ERR_OK;
309 }
310
311 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) {
312
313     *parent = lyd_new_path(NULL, sr_get_context(sr_session_get_connection(session)), NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, 0, 0, 0);
314     if(*parent == 0) {
315         log_error("lyd_new_path failed\n");
316         return SR_ERR_OPERATION_FAILED;
317     }
318
319     for(int i = 0; i < docker_context_count; i++) {
320         char ftype_path[512];
321         sprintf(ftype_path, "%s[function-type='%s']/instances/instance", NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
322         for(int j = 0; j < manager_context[i].started_instances; j++) {
323             char instance_path[1024];
324             sprintf(instance_path, "%s[name='%s']", ftype_path, manager_context[i].instance[j].container.name);
325
326             char full_path[2048];
327
328             sprintf(full_path, "%s/mount-point-addressing-method", instance_path);
329             if(lyd_new_path(*parent, NULL, full_path, manager_context[i].instance[j].mount_point_addressing_method, 0, 0) == 0) {
330                 log_error("lyd_new_path failed\n");
331                 return SR_ERR_OPERATION_FAILED;
332             }
333
334             sprintf(full_path, "%s/is-mounted", instance_path);
335             struct lyd_node *is_mounted = lyd_new_path(*parent, NULL, full_path, manager_context[i].instance[j].is_mounted ? "true" : "false", 0, LYD_PATH_OPT_NOPARENTRET);
336             if(is_mounted == 0) {
337                 log_error("lyd_new_path failed\n");
338                 return SR_ERR_OPERATION_FAILED;
339             }
340
341             if(manager_sr_populate_networking(is_mounted->parent, &manager_context[i].instance[j]) != NTS_ERR_OK) {
342                 log_error("manager_sr_populate_networking failed\n");
343                 return SR_ERR_OPERATION_FAILED;
344             }
345         }
346     }
347
348     return SR_ERR_OK;
349 }