1 /*************************************************************************
3 * Copyright 2020 highstreet technologies GmbH and others
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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 ***************************************************************************/
21 #include "utils/log_utils.h"
22 #include "utils/sys_utils.h"
27 #include <sysrepo/values.h>
29 #include "core/framework.h"
30 #include "core/session.h"
31 #include "core/xpath.h"
32 #include "core/context.h"
34 #include "app_common.h"
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);
39 int manager_run(void) {
42 log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"starting MANAGER...\n"LOG_COLOR_RESET);
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;
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;
58 rc = manager_operations_init();
59 if(rc != NTS_ERR_OK) {
60 log_error("manager_operations_init failed\n");
61 return NTS_ERR_FAILED;
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);
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);
76 log_error("could not subscribe to simulation changes\n");
77 return NTS_ERR_FAILED;
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);
83 log_error("could not subscribe to oper faults\n");
84 return NTS_ERR_FAILED;
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);
90 log_error("could not subscribe to oper faults\n");
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;
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);
107 log_add(1, "NETCONF SSH: disabled");
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);
113 log_add(1, " | NETCONF TLS: disabled");
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);
119 log_add(1, " | FTP: disabled");
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);
125 log_add(1, " | SFTP: disabled");
128 log_add_verbose(1, LOG_COLOR_BOLD_GREEN"started!\n"LOG_COLOR_RESET);
131 while(!framework_sigint) {
132 manager_operations_loop(); //caution - this function time-waits (1sec) on manager_operation_sem
135 manager_operations_free();
136 manager_context_free();
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;
148 if(manager_sr_get_context_sync()) {
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;
159 manager_operation_t *new_oper = 0;
160 while((rc = sr_get_change_next(session, it, &oper, &old_value, &new_value)) == SR_ERR_OK) {
162 //get function type and index
163 char *nv = sr_val_to_str(new_value);
165 char function_type[512];
166 strncpy(function_type, strstr(new_value->xpath, "function-type='") + 15, 510);
167 *strchr(function_type, '\'') = 0;
170 if((new_oper == 0) || (strcmp(new_oper->function_type, function_type) != 0)) {
173 manager_operations_begin();
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;
183 manager_operations_add(new_oper);
186 new_oper = manager_operations_new_oper(MANAGER_OPERATION_EDIT);
187 new_oper->function_type = strdup(function_type);
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;
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;
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 // checkAL sysrepo v1.4.140 workaround
207 // rc = sr_set_item(session, old_value->xpath, old_value, 0);
208 // if(rc != SR_ERR_OK) {
209 // log_error("sr_set_item failed\n");
210 // return SR_ERR_VALIDATION_FAILED;
213 else if(strcmp(leaf_path, "mounted-instances") == 0) {
214 new_oper->mounted_instances = new_value->data.uint16_val;
215 // checkAL sysrepo v1.4.140 workaround
216 // rc = sr_set_item(session, old_value->xpath, old_value, 0);
217 // if(rc != SR_ERR_OK) {
218 // log_error("sr_set_item failed\n");
219 // return SR_ERR_VALIDATION_FAILED;
222 else if(strcmp(leaf_path, "docker-instance-name") == 0) {
223 new_oper->docker_instance_name = strdup(nv);
224 free(manager_context[new_oper->ft_index].docker_instance_name);
225 manager_context[new_oper->ft_index].docker_instance_name = strdup(nv);
227 else if(strcmp(leaf_path, "docker-version-tag") == 0) {
228 new_oper->docker_version_tag = strdup(nv);
229 free(manager_context[new_oper->ft_index].docker_version_tag);
230 manager_context[new_oper->ft_index].docker_version_tag = strdup(nv);
232 else if(strcmp(leaf_path, "docker-repository") == 0) {
233 new_oper->docker_repository = strdup(nv);
234 free(manager_context[new_oper->ft_index].docker_repository);
235 manager_context[new_oper->ft_index].docker_repository = strdup(nv);
237 else if(strcmp(leaf_path, "mount-point-addressing-method") == 0) {
239 free(manager_context[new_oper->ft_index].mount_point_addressing_method);
240 manager_context[new_oper->ft_index].mount_point_addressing_method = strdup(nv);
243 //mark each instance for reconfiguration
244 for(int i = 0; i < manager_context[new_oper->ft_index].started_instances; i++) {
245 manager_context[new_oper->ft_index].instance[i].is_configured = false;
253 sr_free_val(old_value);
254 sr_free_val(new_value);
257 sr_free_change_iter(it);
259 //validate and add the operation, if any; can be 0 if no modifications to NF list
261 if(manager_operations_validate(new_oper) != NTS_ERR_OK) {
262 manager_operations_free_oper(new_oper);
263 manager_operations_finish_with_error();
264 return SR_ERR_VALIDATION_FAILED;
267 manager_operations_add(new_oper);
270 else if(event == SR_EV_CHANGE) {
272 else if(event == SR_EV_DONE) {
273 bool global_change = false;
275 // go throughout all the changes, not just NF list
276 rc = sr_get_changes_iter(session, NTS_MANAGER_SIMULATION_SCHEMA_XPATH"//.", &it);
277 if(rc != SR_ERR_OK) {
278 log_error("sr_get_changes_iter failed\n");
279 return SR_ERR_VALIDATION_FAILED;
282 while((rc = sr_get_change_next(session, it, &oper, &old_value, &new_value)) == SR_ERR_OK) {
284 if(strstr(new_value->xpath, NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH) != new_value->xpath) {
285 global_change = true;
286 sr_free_val(old_value);
287 sr_free_val(new_value);
292 sr_free_val(old_value);
293 sr_free_val(new_value);
296 sr_free_change_iter(it);
299 //mark each instance for reconfiguration
300 for(int i = 0; i < docker_context_count; i++) {
301 for(int j = 0; j < manager_context[i].started_instances; j++) {
302 manager_context[i].instance[j].is_configured = false;
307 manager_operations_finish_and_execute(); //from this point on, manager_operations_loop will take over
313 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) {
315 *parent = lyd_new_path(NULL, sr_get_context(sr_session_get_connection(session)), NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, 0, 0, 0);
317 log_error("lyd_new_path failed\n");
318 return SR_ERR_OPERATION_FAILED;
321 for(int i = 0; i < docker_context_count; i++) {
322 char ftype_path[512];
323 sprintf(ftype_path, "%s[function-type='%s']/instances/instance", NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH, manager_context[i].function_type);
324 for(int j = 0; j < manager_context[i].started_instances; j++) {
325 char instance_path[1024];
326 sprintf(instance_path, "%s[name='%s']", ftype_path, manager_context[i].instance[j].container.name);
328 char full_path[2048];
330 sprintf(full_path, "%s/mount-point-addressing-method", instance_path);
331 if(lyd_new_path(*parent, NULL, full_path, manager_context[i].instance[j].mount_point_addressing_method, 0, 0) == 0) {
332 log_error("lyd_new_path failed\n");
333 return SR_ERR_OPERATION_FAILED;
336 sprintf(full_path, "%s/is-mounted", instance_path);
337 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);
338 if(is_mounted == 0) {
339 log_error("lyd_new_path failed\n");
340 return SR_ERR_OPERATION_FAILED;
343 if(manager_sr_populate_networking(is_mounted->parent, &manager_context[i].instance[j]) != NTS_ERR_OK) {
344 log_error("manager_sr_populate_networking failed\n");
345 return SR_ERR_OPERATION_FAILED;