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"
28 #include "core/framework.h"
29 #include "core/docker.h"
30 #include "core/session.h"
31 #include "core/nc_config.h"
32 #include "utils/nc_client.h"
33 #include "utils/http_client.h"
34 #include "utils/nts_utils.h"
36 int manager_actions_start(manager_context_t *ctx) {
39 int started_instances = ctx->started_instances;
40 char instance_name[512];
41 sprintf(instance_name, "%s-%d", ctx->docker_instance_name, started_instances);
43 uint16_t netconf_ssh_port = framework_environment.host.ssh_base_port;
44 uint16_t netconf_tls_port = framework_environment.host.tls_base_port;
45 uint16_t ftp_port = framework_environment.host.ftp_base_port;
46 uint16_t sftp_port = framework_environment.host.sftp_base_port;
48 if(framework_environment.settings.ssh_connections) {
49 while((netconf_ssh_port) && (manager_port[netconf_ssh_port] != MANAGER_PROTOCOL_UNUSED)) {
53 for(int i = 0; i < framework_environment.settings.ssh_connections; i++) {
54 if(manager_port[i + netconf_ssh_port] != MANAGER_PROTOCOL_UNUSED) {
55 log_error("no ports available for operation for ssh\n");
56 manager_sr_notif_send_instance_changed("start FAILED - no ports available for ssh", ctx->function_type, instance_name, 0);
57 return NTS_ERR_FAILED;
61 for(int i = 0; i < framework_environment.settings.ssh_connections; i++) {
62 manager_port[i + netconf_ssh_port] = MANAGER_PROTOCOL_NETCONF_SSH;
66 if(framework_environment.settings.tls_connections) {
67 while((netconf_tls_port) && (manager_port[netconf_tls_port] != MANAGER_PROTOCOL_UNUSED)) {
71 for(int i = 0; i < framework_environment.settings.tls_connections; i++) {
72 if(manager_port[i + netconf_tls_port] != MANAGER_PROTOCOL_UNUSED) {
73 log_error("no ports available for operation for tls\n");
74 manager_sr_notif_send_instance_changed("start FAILED - no ports available for tls", ctx->function_type, instance_name, 0);
76 for(int i = 0; i < framework_environment.settings.ssh_connections; i++) {
77 manager_port[i + netconf_ssh_port] = MANAGER_PROTOCOL_UNUSED;
79 return NTS_ERR_FAILED;
83 for(int i = 0; i < framework_environment.settings.tls_connections; i++) {
84 manager_port[i + netconf_tls_port] = MANAGER_PROTOCOL_NETCONF_TLS;
88 if(framework_environment.settings.ftp_connections) {
89 while((ftp_port) && (manager_port[ftp_port] != MANAGER_PROTOCOL_UNUSED)) {
93 for(int i = 0; i < framework_environment.settings.ftp_connections; i++) {
94 if(manager_port[i + ftp_port] != MANAGER_PROTOCOL_UNUSED) {
95 log_error("no ports available for operation for ftp\n");
96 manager_sr_notif_send_instance_changed("start FAILED - no ports available for ftp", ctx->function_type, instance_name, 0);
98 for(int i = 0; i < framework_environment.settings.ssh_connections; i++) {
99 manager_port[i + netconf_ssh_port] = MANAGER_PROTOCOL_UNUSED;
102 for(int i = 0; i < framework_environment.settings.tls_connections; i++) {
103 manager_port[i + netconf_tls_port] = MANAGER_PROTOCOL_UNUSED;
105 return NTS_ERR_FAILED;
109 for(int i = 0; i < framework_environment.settings.ftp_connections; i++) {
110 manager_port[i + ftp_port] = MANAGER_PROTOCOL_FTP;
114 if(framework_environment.settings.sftp_connections) {
115 while((sftp_port) && (manager_port[sftp_port] != MANAGER_PROTOCOL_UNUSED)) {
119 for(int i = 0; i < framework_environment.settings.sftp_connections; i++) {
120 if(manager_port[i + sftp_port] != MANAGER_PROTOCOL_UNUSED) {
121 log_error("no ports available for operation for sftp\n");
122 manager_sr_notif_send_instance_changed("start FAILED - no ports available for sftp", ctx->function_type, instance_name, 0);
124 for(int i = 0; i < framework_environment.settings.ssh_connections; i++) {
125 manager_port[i + netconf_ssh_port] = MANAGER_PROTOCOL_UNUSED;
128 for(int i = 0; i < framework_environment.settings.tls_connections; i++) {
129 manager_port[i + netconf_tls_port] = MANAGER_PROTOCOL_UNUSED;
132 for(int i = 0; i < framework_environment.settings.ftp_connections; i++) {
133 manager_port[i + ftp_port] = MANAGER_PROTOCOL_UNUSED;
135 return NTS_ERR_FAILED;
139 for(int i = 0; i < framework_environment.settings.sftp_connections; i++) {
140 manager_port[i + sftp_port] = MANAGER_PROTOCOL_SFTP;
144 ctx->instance = (manager_network_function_instance_t *)realloc(ctx->instance, sizeof(manager_network_function_instance_t) * (started_instances + 1));
145 if(ctx->instance == 0) {
146 log_error("realloc failed\n");
147 manager_sr_notif_send_instance_changed("start FAILED - realloc error", ctx->function_type, instance_name, 0);
148 for(int i = 0; i < framework_environment.settings.ssh_connections; i++) {
149 manager_port[i + netconf_ssh_port] = MANAGER_PROTOCOL_UNUSED;
152 for(int i = 0; i < framework_environment.settings.tls_connections; i++) {
153 manager_port[i + netconf_tls_port] = MANAGER_PROTOCOL_UNUSED;
156 for(int i = 0; i < framework_environment.settings.ftp_connections; i++) {
157 manager_port[i + ftp_port] = MANAGER_PROTOCOL_UNUSED;
160 for(int i = 0; i < framework_environment.settings.sftp_connections; i++) {
161 manager_port[i + sftp_port] = MANAGER_PROTOCOL_UNUSED;
163 return NTS_ERR_FAILED;
166 manager_network_function_instance_t *instance = &ctx->instance[started_instances];
167 instance->is_init = false;
168 instance->is_configured = false;
169 instance->is_mounted = false;
170 instance->mount_point_addressing_method = strdup(ctx->mount_point_addressing_method);
172 int rc = docker_start(instance_name, ctx->docker_version_tag, ctx->docker->image, ctx->docker_repository, netconf_ssh_port, netconf_tls_port, ftp_port, sftp_port, &instance->container);
173 if(rc != NTS_ERR_OK) {
174 log_error("docker_start failed\n");
175 manager_sr_notif_send_instance_changed("start FAILED - Docker start error", ctx->function_type, instance_name, 0);
176 for(int i = 0; i < framework_environment.settings.ssh_connections; i++) {
177 manager_port[i + netconf_ssh_port] = MANAGER_PROTOCOL_UNUSED;
180 for(int i = 0; i < framework_environment.settings.tls_connections; i++) {
181 manager_port[i + netconf_tls_port] = MANAGER_PROTOCOL_UNUSED;
184 for(int i = 0; i < framework_environment.settings.ftp_connections; i++) {
185 manager_port[i + ftp_port] = MANAGER_PROTOCOL_UNUSED;
188 for(int i = 0; i < framework_environment.settings.sftp_connections; i++) {
189 manager_port[i + sftp_port] = MANAGER_PROTOCOL_UNUSED;
191 return NTS_ERR_FAILED;
194 ctx->started_instances++;
195 manager_sr_notif_send_instance_changed("start SUCCESS", ctx->function_type, instance_name, instance);
196 log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"%s"LOG_COLOR_RESET" started (%s); ports host(docker): ", instance_name, instance->mount_point_addressing_method);
197 if(framework_environment.settings.ssh_connections > 1) {
198 log_add(1, "NETCONF SSH: %d-%d(%d-%d)", instance->container.host_netconf_ssh_port, (instance->container.host_netconf_ssh_port + framework_environment.settings.ssh_connections - 1), instance->container.docker_netconf_ssh_port, (instance->container.docker_netconf_ssh_port + framework_environment.settings.ssh_connections - 1));
200 else if(framework_environment.settings.ssh_connections == 1) {
201 log_add(1, "NETCONF SSH: %d(%d)", instance->container.host_netconf_ssh_port, instance->container.docker_netconf_ssh_port);
204 log_add(1, "NETCONF SSH: disabled");
207 if(framework_environment.settings.tls_connections > 1) {
208 log_add(1, " | NETCONF TLS: %d-%d(%d-%d)", instance->container.host_netconf_tls_port, (instance->container.host_netconf_tls_port + framework_environment.settings.tls_connections - 1), instance->container.docker_netconf_tls_port, (instance->container.docker_netconf_tls_port + framework_environment.settings.tls_connections - 1));
210 else if(framework_environment.settings.tls_connections == 1) {
211 log_add(1, " | NETCONF TLS: %d(%d)", instance->container.host_netconf_tls_port, instance->container.docker_netconf_tls_port);
214 log_add(1, " | NETCONF TLS: disabled");
217 if(framework_environment.settings.ftp_connections > 1) {
218 log_add(1, " | FTP: %d-%d(%d-%d)", instance->container.host_ftp_port, (instance->container.host_ftp_port + framework_environment.settings.ftp_connections - 1), instance->container.docker_ftp_port, (instance->container.docker_ftp_port + framework_environment.settings.ftp_connections - 1));
220 else if(framework_environment.settings.ftp_connections == 1) {
221 log_add(1, " | FTP: %d(%d)", instance->container.host_ftp_port, instance->container.docker_ftp_port);
224 log_add(1, " | FTP: disabled");
227 if(framework_environment.settings.sftp_connections > 1) {
228 log_add(1, " | SFTP: %d-%d(%d-%d)", instance->container.host_sftp_port, (instance->container.host_sftp_port + framework_environment.settings.sftp_connections - 1), instance->container.docker_sftp_port, (instance->container.docker_sftp_port + framework_environment.settings.sftp_connections - 1));
230 else if(framework_environment.settings.sftp_connections == 1) {
231 log_add(1, " | SFTP: %d(%d)", instance->container.host_sftp_port, instance->container.docker_sftp_port);
234 log_add(1, " | SFTP: disabled");
243 int manager_actions_config_instance(manager_context_t *ctx, manager_network_function_instance_t *instance) {
247 //first wait for the nc server to be up and running
249 while(check_port_open(instance->container.docker_ip, CLIENT_CONFIG_TLS_PORT) == false) {
253 log_error("manager_actions_config_instance() could not connect to %s, as port is not open\n", instance->container.name);
254 return NTS_ERR_FAILED;
258 //populate sdn-controller and ves-endpoint
259 struct lyd_node *local_tree = 0;
260 int rc = lyd_utils_dup(session_running, "/nts-manager:simulation/sdn-controller", "/nts-network-function:simulation/sdn-controller", &local_tree);
261 if(rc != NTS_ERR_OK) {
262 log_error("lyd_utils_dup failed\n");
263 manager_sr_notif_send_instance_changed("config FAILED - libyang", ctx->function_type, instance->container.name, instance);
264 return NTS_ERR_FAILED;
267 rc = lyd_utils_dup(session_running, "/nts-manager:simulation/ves-endpoint", "/nts-network-function:simulation/ves-endpoint", &local_tree);
268 if(rc != NTS_ERR_OK) {
269 log_error("lyd_utils_dup failed\n");
270 manager_sr_notif_send_instance_changed("config FAILED - libyang", ctx->function_type, instance->container.name, instance);
271 lyd_free_withsiblings(local_tree);
272 return NTS_ERR_FAILED;
276 sprintf(xpath_s, "/nts-manager:simulation/network-functions/network-function[function-type='%s']", ctx->function_type);
277 rc = lyd_utils_dup(session_running, xpath_s, "/nts-network-function:simulation/network-function", &local_tree);
278 if(rc != NTS_ERR_OK) {
279 log_error("lyd_utils_dup failed\n");
280 manager_sr_notif_send_instance_changed("config FAILED - libyang", ctx->function_type, instance->container.name, instance);
281 lyd_free_withsiblings(local_tree);
282 return NTS_ERR_FAILED;
285 nc_client_t *nc_client = nc_client_tls_connect(instance->container.docker_ip, CLIENT_CONFIG_TLS_PORT);
286 // nc_client_t *nc_client = nc_client_ssh_connect(instance->container.docker_ip, instance->container.docker_port, "netconf", "netconf!");
288 log_error("nc_client_tls_connect\n");
289 manager_sr_notif_send_instance_changed("config FAILED - netconf client connect", ctx->function_type, instance->container.name, instance);
290 lyd_free_withsiblings(local_tree);
291 return NTS_ERR_FAILED;
294 rc += nc_client_edit_batch(nc_client, local_tree, 5000);
295 lyd_free_withsiblings(local_tree);
296 if(rc != NTS_ERR_OK) {
297 log_error("nc_client_edit_batch failed %d\n", rc);
298 manager_sr_notif_send_instance_changed("config FAILED - netconf edit batch", ctx->function_type, instance->container.name, instance);
299 nc_client_disconnect(nc_client);
300 return NTS_ERR_FAILED;
303 if(instance->is_init == false) {
304 //run datastore-populate rpc
305 struct lyd_node *rpc_node = 0;
306 struct lyd_node *rpcout = 0;
307 rpc_node = lyd_new_path(0, session_context, "/nts-network-function:datastore-populate", 0, 0, 0);
309 log_error("failed to create rpc node\n");
310 manager_sr_notif_send_instance_changed("config FAILED - populate RPC", ctx->function_type, instance->container.name, instance);
311 nc_client_disconnect(nc_client);
312 return NTS_ERR_FAILED;
315 rpcout = nc_client_send_rpc(nc_client, rpc_node, 10000);
317 log_error("datastore-populate rpc failed\n");
318 manager_sr_notif_send_instance_changed("config FAILED - datastore populate RPC", ctx->function_type, instance->container.name, instance);
319 nc_client_disconnect(nc_client);
320 lyd_free_withsiblings(rpc_node);
321 return NTS_ERR_FAILED;
324 lyd_free_withsiblings(rpcout);
326 lyd_free_withsiblings(rpc_node);
328 //run feature-control rpc
329 rpc_node = lyd_new_path(0, session_context, "/nts-network-function:feature-control/start-features", "ves-file-ready ves-heartbeat ves-pnf-registration manual-notification-generation netconf-call-home web-cut-through", 0, 0);
331 log_error("failed to create rpc node\n");
332 manager_sr_notif_send_instance_changed("config FAILED - feature-control RPC", ctx->function_type, instance->container.name, instance);
333 nc_client_disconnect(nc_client);
334 return NTS_ERR_FAILED;
337 rpcout = nc_client_send_rpc(nc_client, rpc_node, 10000);
339 log_error("feature-control rpc failed\n");
340 manager_sr_notif_send_instance_changed("config FAILED - feature-control RPC", ctx->function_type, instance->container.name, instance);
341 nc_client_disconnect(nc_client);
342 lyd_free_withsiblings(rpc_node);
343 return NTS_ERR_FAILED;
346 lyd_free_withsiblings(rpcout);
348 lyd_free_withsiblings(rpc_node);
351 instance->is_init = true;
352 instance->is_configured = true;
353 nc_client_disconnect(nc_client);
354 manager_sr_notif_send_instance_changed("config SUCCESS", ctx->function_type, instance->container.name, instance);
355 log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"%s"LOG_COLOR_RESET" configured via netconf\n", instance->container.name);
360 int manager_actions_stop(manager_context_t *ctx) {
363 manager_network_function_instance_t *instance = &ctx->instance[ctx->started_instances - 1];
364 char instance_name[512];
365 strcpy(instance_name, instance->container.name);
367 if(instance->is_mounted) {
368 if(manager_actions_unmount(ctx) != NTS_ERR_OK) {
369 log_error("failed to unmount instance\n");
373 int rc = docker_stop(&instance->container);
374 if(rc != NTS_ERR_OK) {
375 log_error("docker_device_stop failed\n");
376 manager_sr_notif_send_instance_changed("stop FAILED - Docker error", ctx->function_type, instance_name, 0);
377 return NTS_ERR_FAILED;
381 for(int i = 0; i < framework_environment.settings.ssh_connections; i++) {
382 manager_port[i + ctx->instance[ctx->started_instances - 1].container.host_netconf_ssh_port] = MANAGER_PROTOCOL_UNUSED;
385 for(int i = 0; i < framework_environment.settings.tls_connections; i++) {
386 manager_port[i + ctx->instance[ctx->started_instances - 1].container.host_netconf_tls_port] = MANAGER_PROTOCOL_UNUSED;
389 for(int i = 0; i < framework_environment.settings.ftp_connections; i++) {
390 manager_port[i + ctx->instance[ctx->started_instances - 1].container.host_ftp_port] = MANAGER_PROTOCOL_UNUSED;
393 for(int i = 0; i < framework_environment.settings.sftp_connections; i++) {
394 manager_port[i + ctx->instance[ctx->started_instances - 1].container.host_sftp_port] = MANAGER_PROTOCOL_UNUSED;
397 free(instance->mount_point_addressing_method);
399 if(ctx->started_instances > 1) {
400 ctx->instance = (manager_network_function_instance_t *)realloc(ctx->instance, sizeof(manager_network_function_instance_t) * ctx->started_instances);
401 if(ctx->instance == 0) {
402 log_error("realloc failed\n");
403 manager_sr_notif_send_instance_changed("stop FAILED - realloc", ctx->function_type, instance_name, 0);
404 return NTS_ERR_FAILED;
411 ctx->started_instances--;
412 manager_sr_notif_send_instance_changed("stop SUCCESS", ctx->function_type, instance_name, 0);
413 log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"%s"LOG_COLOR_RESET" stopped\n", instance_name);
419 int manager_actions_mount(manager_context_t *ctx) {
422 manager_network_function_instance_t *instance = &ctx->instance[ctx->mounted_instances];
424 if(instance->is_mounted == true) {
425 manager_sr_notif_send_instance_changed("mount SUCCESS - already mounted", ctx->function_type, instance->container.name, instance);
429 controller_details_t *controller;
430 controller = controller_details_get(0);
431 if(controller == 0) {
432 log_error("could not get controller details\n");
433 manager_sr_notif_send_instance_changed("mount FAILED - no controller details", ctx->function_type, instance->container.name, instance);
434 return NTS_ERR_FAILED;
437 for(int i = 0; i < (framework_environment.settings.ssh_connections + framework_environment.settings.tls_connections); i++) {
443 if(instance->mount_point_addressing_method[0] == 'd') {
444 ip = instance->container.docker_ip;
447 ip = instance->container.host_ip;
451 if(i < framework_environment.settings.ssh_connections) {
454 \"network-topology:netconf-node-topology:username\": \"netconf\",\
455 \"network-topology:netconf-node-topology:password\": \"netconf\"";
457 if(instance->mount_point_addressing_method[0] == 'd') {
458 port = instance->container.docker_netconf_ssh_port + i;
461 port = instance->container.host_netconf_ssh_port + i;
467 \"netconf-node-topology:key-based\" : {\
468 \"netconf-node-topology:username\" : \"netconf\",\
469 \"netconf-node-topology:key-id\" : \""KS_KEY_NAME"\"\
472 if(instance->mount_point_addressing_method[0] == 'd') {
473 port = instance->container.docker_netconf_tls_port + i - framework_environment.settings.ssh_connections;
476 port = instance->container.host_netconf_tls_port + i - framework_environment.settings.ssh_connections;
480 char *json_template = "\
482 \"network-topology:node\": [{\
483 \"network-topology:node-id\": \"%s\",\
484 \"network-topology:netconf-node-topology:host\": \"%s\",\
485 \"network-topology:netconf-node-topology:port\": \"%d\",\
486 \"network-topology:netconf-node-topology:tcp-only\": \"false\",\
487 \"network-topology:netconf-node-topology:protocol\": {\
488 \"network-topology:netconf-node-topology:name\": \"%s\"\
491 \"network-topology:netconf-node-topology:connection-timeout-millis\": \"20000\",\
492 \"network-topology:netconf-node-topology:default-request-timeout-millis\": \"60000\",\
493 \"network-topology:netconf-node-topology:max-connection-attempts\": \"3\"\
499 sprintf(node_id, "%s-%d", instance->container.name, port);
500 sprintf(json, json_template, node_id, ip, port, protocol, protocol_data);
503 sprintf(url, "%s/rests/data/network-topology:network-topology/topology=topology-netconf/node=%s", controller->base_url, node_id);
504 int rc = http_request(url, controller->username, controller->password, "PUT", json, 0, 0);
505 if(rc != NTS_ERR_OK) {
506 log_error("http_request failed\n");
507 controller_details_free(controller);
508 manager_sr_notif_send_instance_changed("mount FAILED - REST request", ctx->function_type, instance->container.name, instance);
509 return NTS_ERR_FAILED;
513 controller_details_free(controller);
515 instance->is_mounted = true;
516 ctx->mounted_instances++;
517 manager_sr_notif_send_instance_changed("mount SUCCESS", ctx->function_type, instance->container.name, instance);
518 log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"%s"LOG_COLOR_RESET" mounted\n", instance->container.name);
523 int manager_actions_unmount(manager_context_t *ctx) {
526 int ret = NTS_ERR_OK;
528 manager_network_function_instance_t *instance = &ctx->instance[ctx->mounted_instances - 1];
530 if(instance->is_mounted == false) {
531 log_error("tried to unmount an unmounted instance\n");
532 manager_sr_notif_send_instance_changed("unmount FAILED - already unmounted", ctx->function_type, instance->container.name, instance);
536 controller_details_t *controller;
537 controller = controller_details_get(0);
538 if(controller == 0) {
539 log_error("could not get controller details\n");
540 manager_sr_notif_send_instance_changed("unmount FAILED - no controller details", ctx->function_type, instance->container.name, instance);
541 return NTS_ERR_FAILED;
544 for(int i = 0; i < (framework_environment.settings.ssh_connections + framework_environment.settings.tls_connections); i++) {
546 if(i < framework_environment.settings.ssh_connections) {
547 if(instance->mount_point_addressing_method[0] == 'd') {
548 port = instance->container.docker_netconf_ssh_port + i;
551 port = instance->container.host_netconf_ssh_port + i;
555 if(instance->mount_point_addressing_method[0] == 'd') {
556 port = instance->container.docker_netconf_tls_port + i - framework_environment.settings.ssh_connections;
559 port = instance->container.host_netconf_tls_port + i - framework_environment.settings.ssh_connections;
563 sprintf(node_id, "%s-%d", instance->container.name, port);
566 sprintf(url, "%s/rests/data/network-topology:network-topology/topology=topology-netconf/node=%s", controller->base_url, node_id);
567 int rc = http_request(url, controller->username, controller->password, "DELETE", "", 0, 0);
568 if(rc != NTS_ERR_OK) {
569 log_error("http_request failed\n");
570 manager_sr_notif_send_instance_changed("unmount FAILED - REST request", ctx->function_type, instance->container.name, instance);
571 ret = NTS_ERR_FAILED;
575 controller_details_free(controller);
577 ctx->mounted_instances--;
578 ctx->instance[ctx->mounted_instances].is_mounted = false;
579 manager_sr_notif_send_instance_changed("unmount SUCCESS", ctx->function_type, instance->container.name, instance);
580 log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"%s"LOG_COLOR_RESET" unmounted\n", instance->container.name);