Add NF addressing method as ENV.
[sim/o1-interface.git] / ntsimulator / ntsim-ng / core / app / manager_actions.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 <stdlib.h>
25 #include <assert.h>
26 #include <pthread.h>
27
28 #include "core/framework.h"
29 #include "core/docker.h"
30 #include "core/session.h"
31 #include "core/xpath.h"
32 #include "core/nc_config.h"
33 #include "utils/nc_client.h"
34 #include "utils/http_client.h"
35 #include "utils/nts_utils.h"
36
37 int manager_actions_start(manager_context_t *ctx) {
38     assert(ctx);
39
40     int started_instances = ctx->started_instances;
41     char instance_name[512];
42     sprintf(instance_name, "%s-%d", ctx->docker_instance_name, started_instances);
43
44     uint16_t netconf_ssh_port = framework_environment.host.ssh_base_port;
45     uint16_t netconf_tls_port = framework_environment.host.tls_base_port;
46     uint16_t ftp_port = framework_environment.host.ftp_base_port;
47     uint16_t sftp_port = framework_environment.host.sftp_base_port;
48
49     if(framework_environment.settings.ssh_connections) {
50         while((netconf_ssh_port) && (manager_port[netconf_ssh_port] != MANAGER_PROTOCOL_UNUSED)) {
51             netconf_ssh_port++;
52         }
53
54         for(int i = 0; i < framework_environment.settings.ssh_connections; i++) {
55             if(manager_port[i + netconf_ssh_port] != MANAGER_PROTOCOL_UNUSED) {
56                 log_error("no ports available for operation for ssh\n");
57                 manager_sr_notif_send_instance_changed("start FAILED - no ports available for ssh", ctx->function_type, instance_name, 0);
58                 return NTS_ERR_FAILED;
59             }
60         }
61
62         for(int i = 0; i < framework_environment.settings.ssh_connections; i++) {
63             manager_port[i + netconf_ssh_port] = MANAGER_PROTOCOL_NETCONF_SSH;
64         }
65     }
66
67     if(framework_environment.settings.tls_connections) {
68         while((netconf_tls_port) && (manager_port[netconf_tls_port] != MANAGER_PROTOCOL_UNUSED)) {
69             netconf_tls_port++;
70         }
71
72         for(int i = 0; i < framework_environment.settings.tls_connections; i++) {
73             if(manager_port[i + netconf_tls_port] != MANAGER_PROTOCOL_UNUSED) {
74                 log_error("no ports available for operation for tls\n");
75                 manager_sr_notif_send_instance_changed("start FAILED - no ports available for tls", ctx->function_type, instance_name, 0);
76
77                 for(int i = 0; i < framework_environment.settings.ssh_connections; i++) {
78                     manager_port[i + netconf_ssh_port] = MANAGER_PROTOCOL_UNUSED;
79                 }
80                 return NTS_ERR_FAILED;
81             }
82         }
83
84         for(int i = 0; i < framework_environment.settings.tls_connections; i++) {
85             manager_port[i + netconf_tls_port] = MANAGER_PROTOCOL_NETCONF_TLS;
86         }
87     }
88
89     if(framework_environment.settings.ftp_connections) {
90         while((ftp_port) && (manager_port[ftp_port] != MANAGER_PROTOCOL_UNUSED)) {
91             ftp_port++;
92         }
93
94         for(int i = 0; i < framework_environment.settings.ftp_connections; i++) {
95             if(manager_port[i + ftp_port] != MANAGER_PROTOCOL_UNUSED) {
96                 log_error("no ports available for operation for ftp\n");
97                 manager_sr_notif_send_instance_changed("start FAILED - no ports available for ftp", ctx->function_type, instance_name, 0);
98
99                 for(int i = 0; i < framework_environment.settings.ssh_connections; i++) {
100                     manager_port[i + netconf_ssh_port] = MANAGER_PROTOCOL_UNUSED;
101                 }
102
103                 for(int i = 0; i < framework_environment.settings.tls_connections; i++) {
104                     manager_port[i + netconf_tls_port] = MANAGER_PROTOCOL_UNUSED;
105                 }
106                 return NTS_ERR_FAILED;
107             }
108         }
109
110         for(int i = 0; i < framework_environment.settings.ftp_connections; i++) {
111             manager_port[i + ftp_port] = MANAGER_PROTOCOL_FTP;
112         }
113     }
114
115     if(framework_environment.settings.sftp_connections) {
116         while((sftp_port) && (manager_port[sftp_port] != MANAGER_PROTOCOL_UNUSED)) {
117             sftp_port++;
118         }
119
120         for(int i = 0; i < framework_environment.settings.sftp_connections; i++) {
121             if(manager_port[i + sftp_port] != MANAGER_PROTOCOL_UNUSED) {
122                 log_error("no ports available for operation for sftp\n");
123                 manager_sr_notif_send_instance_changed("start FAILED - no ports available for sftp", ctx->function_type, instance_name, 0);
124
125                 for(int i = 0; i < framework_environment.settings.ssh_connections; i++) {
126                     manager_port[i + netconf_ssh_port] = MANAGER_PROTOCOL_UNUSED;
127                 }
128
129                 for(int i = 0; i < framework_environment.settings.tls_connections; i++) {
130                     manager_port[i + netconf_tls_port] = MANAGER_PROTOCOL_UNUSED;
131                 }
132
133                 for(int i = 0; i < framework_environment.settings.ftp_connections; i++) {
134                     manager_port[i + ftp_port] = MANAGER_PROTOCOL_UNUSED;
135                 }
136                 return NTS_ERR_FAILED;
137             }
138         }
139
140         for(int i = 0; i < framework_environment.settings.sftp_connections; i++) {
141             manager_port[i + sftp_port] = MANAGER_PROTOCOL_SFTP;
142         }
143     }
144
145     ctx->instance = (manager_network_function_instance_t *)realloc(ctx->instance, sizeof(manager_network_function_instance_t) * (started_instances + 1));
146     if(ctx->instance == 0) {
147         log_error("realloc failed\n");
148         manager_sr_notif_send_instance_changed("start FAILED - realloc error", ctx->function_type, instance_name, 0);
149         for(int i = 0; i < framework_environment.settings.ssh_connections; i++) {
150             manager_port[i + netconf_ssh_port] = MANAGER_PROTOCOL_UNUSED;
151         }
152
153         for(int i = 0; i < framework_environment.settings.tls_connections; i++) {
154             manager_port[i + netconf_tls_port] = MANAGER_PROTOCOL_UNUSED;
155         }
156
157         for(int i = 0; i < framework_environment.settings.ftp_connections; i++) {
158             manager_port[i + ftp_port] = MANAGER_PROTOCOL_UNUSED;
159         }
160
161         for(int i = 0; i < framework_environment.settings.sftp_connections; i++) {
162             manager_port[i + sftp_port] = MANAGER_PROTOCOL_UNUSED;
163         }
164         return NTS_ERR_FAILED;
165     }
166
167     manager_network_function_instance_t *instance = &ctx->instance[started_instances];
168     instance->is_init = false;
169     instance->is_configured = false;
170     instance->is_mounted = false;
171     instance->mount_point_addressing_method = strdup(ctx->mount_point_addressing_method);
172
173     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);
174     if(rc != NTS_ERR_OK) {
175         log_error("docker_start failed\n");
176         manager_sr_notif_send_instance_changed("start FAILED - Docker start error", ctx->function_type, instance_name, 0);
177         for(int i = 0; i < framework_environment.settings.ssh_connections; i++) {
178             manager_port[i + netconf_ssh_port] = MANAGER_PROTOCOL_UNUSED;
179         }
180
181         for(int i = 0; i < framework_environment.settings.tls_connections; i++) {
182             manager_port[i + netconf_tls_port] = MANAGER_PROTOCOL_UNUSED;
183         }
184
185         for(int i = 0; i < framework_environment.settings.ftp_connections; i++) {
186             manager_port[i + ftp_port] = MANAGER_PROTOCOL_UNUSED;
187         }
188
189         for(int i = 0; i < framework_environment.settings.sftp_connections; i++) {
190             manager_port[i + sftp_port] = MANAGER_PROTOCOL_UNUSED;
191         }
192         return NTS_ERR_FAILED;
193     }
194
195     ctx->started_instances++;
196     manager_sr_notif_send_instance_changed("start SUCCESS", ctx->function_type, instance_name, instance);
197     log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"%s"LOG_COLOR_RESET" started (%s); ports host(docker): ", instance_name, instance->mount_point_addressing_method);
198     if(framework_environment.settings.ssh_connections > 1) {
199         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     }
201     else if(framework_environment.settings.ssh_connections == 1) {
202         log_add(1, "NETCONF SSH: %d(%d)", instance->container.host_netconf_ssh_port, instance->container.docker_netconf_ssh_port);
203     }
204     else {
205         log_add(1, "NETCONF SSH: disabled");
206     }
207
208     if(framework_environment.settings.tls_connections > 1) {
209         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     }
211     else if(framework_environment.settings.tls_connections == 1) {
212         log_add(1, " | NETCONF TLS: %d(%d)", instance->container.host_netconf_tls_port, instance->container.docker_netconf_tls_port);
213     }
214     else {
215         log_add(1, " | NETCONF TLS: disabled");
216     }
217
218     if(framework_environment.settings.ftp_connections > 1) {
219         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     }
221     else if(framework_environment.settings.ftp_connections == 1) {
222         log_add(1, " | FTP: %d(%d)", instance->container.host_ftp_port, instance->container.docker_ftp_port);
223     }
224     else {
225         log_add(1, " | FTP: disabled");
226     }
227
228     if(framework_environment.settings.sftp_connections > 1) {
229         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     }
231     else if(framework_environment.settings.sftp_connections == 1) {
232         log_add(1, " | SFTP: %d(%d)", instance->container.host_sftp_port, instance->container.docker_sftp_port);
233     }
234     else {
235         log_add(1, " | SFTP: disabled");
236     }
237
238     log_add(1, "\n");
239
240
241     return NTS_ERR_OK;
242 }
243
244 int manager_actions_config_instance(manager_context_t *ctx, manager_network_function_instance_t *instance) {
245     assert(ctx);
246     assert(instance);
247
248     //first wait for the nc server to be up and running
249     int retries = 0;
250     while(check_port_open(instance->container.docker_ip, CLIENT_CONFIG_TLS_PORT) == false) {
251         usleep(50000);
252         retries++;
253         if(retries >= 200) {
254             log_error("manager_actions_config_instance() could not connect to %s, as port is not open\n", instance->container.name);
255             return NTS_ERR_FAILED;
256         }
257     }
258
259     //populate sdn-controller and ves-endpoint
260     struct lyd_node *local_tree = 0;
261     int rc = lyd_utils_dup(session_running, NTS_MANAGER_SDN_CONTROLLER_CONFIG_XPATH, NTS_NF_SDN_CONTROLLER_CONFIG_XPATH, &local_tree);
262     if(rc != NTS_ERR_OK) {
263         log_error("lyd_utils_dup failed\n");
264         manager_sr_notif_send_instance_changed("config FAILED - libyang", ctx->function_type, instance->container.name, instance);
265         return NTS_ERR_FAILED;
266     }
267
268     rc = lyd_utils_dup(session_running, NTS_MANAGER_VES_ENDPOINT_CONFIG_XPATH, NTS_NF_VES_ENDPOINT_CONFIG_XPATH, &local_tree);
269     if(rc != NTS_ERR_OK) {
270         log_error("lyd_utils_dup failed\n");
271         manager_sr_notif_send_instance_changed("config FAILED - libyang", ctx->function_type, instance->container.name, instance);
272         lyd_free_withsiblings(local_tree);
273         return NTS_ERR_FAILED;
274     }
275
276     char xpath_s[512];
277     sprintf(xpath_s, NTS_MANAGER_FUNCTION_LIST_SCHEMA_XPATH"[function-type='%s']", ctx->function_type);
278     rc = lyd_utils_dup(session_running, xpath_s, NTS_NF_NETWORK_FUNCTION_SCHEMA_XPATH, &local_tree);
279     if(rc != NTS_ERR_OK) {
280         log_error("lyd_utils_dup failed\n");
281         manager_sr_notif_send_instance_changed("config FAILED - libyang", ctx->function_type, instance->container.name, instance);
282         lyd_free_withsiblings(local_tree);
283         return NTS_ERR_FAILED;
284     }    
285
286     nc_client_t *nc_client = nc_client_tls_connect(instance->container.docker_ip, CLIENT_CONFIG_TLS_PORT);
287     // nc_client_t *nc_client = nc_client_ssh_connect(instance->container.docker_ip, instance->container.docker_port, "netconf", "netconf!");
288     if(nc_client == 0) {
289         log_error("nc_client_tls_connect\n");
290         manager_sr_notif_send_instance_changed("config FAILED - netconf client connect", ctx->function_type, instance->container.name, instance);
291         lyd_free_withsiblings(local_tree);
292         return NTS_ERR_FAILED;
293     }
294
295     rc += nc_client_edit_batch(nc_client, local_tree, 5000);
296     lyd_free_withsiblings(local_tree);
297     if(rc != NTS_ERR_OK) {
298         log_error("nc_client_edit_batch failed %d\n", rc);
299         manager_sr_notif_send_instance_changed("config FAILED - netconf edit batch", ctx->function_type, instance->container.name, instance);
300         nc_client_disconnect(nc_client);
301         return NTS_ERR_FAILED;
302     }
303     
304     if(instance->is_init == false) {
305         //run datastore-populate rpc
306         struct lyd_node *rpc_node = 0;
307         struct lyd_node *rpcout = 0;
308         rpc_node = lyd_new_path(0, session_context, NTS_NF_RPC_POPULATE_SCHEMA_XPATH, 0, 0, 0);
309         if(rpc_node == 0) {
310             log_error("failed to create rpc node\n");
311             manager_sr_notif_send_instance_changed("config FAILED - populate RPC", ctx->function_type, instance->container.name, instance);
312             nc_client_disconnect(nc_client);
313             return NTS_ERR_FAILED;
314         }
315
316         rpcout = nc_client_send_rpc(nc_client, rpc_node, 10000);
317         if(rpcout == 0) {
318             log_error("datastore-populate rpc failed\n");
319             manager_sr_notif_send_instance_changed("config FAILED - datastore populate RPC", ctx->function_type, instance->container.name, instance);
320             nc_client_disconnect(nc_client);
321             lyd_free_withsiblings(rpc_node);
322             return NTS_ERR_FAILED;
323         }
324         else {
325             lyd_free_withsiblings(rpcout);
326         }
327         lyd_free_withsiblings(rpc_node);
328
329         //run feature-control rpc
330         rpc_node = lyd_new_path(0, session_context, NTS_NF_RPC_FEATURE_CONTROL_SCHEMA_XPATH"/start-features", "ves-file-ready ves-heartbeat ves-pnf-registration manual-notification-generation netconf-call-home web-cut-through", 0, 0);
331         if(rpc_node == 0) {
332             log_error("failed to create rpc node\n");
333             manager_sr_notif_send_instance_changed("config FAILED - feature-control RPC", ctx->function_type, instance->container.name, instance);
334             nc_client_disconnect(nc_client);
335             return NTS_ERR_FAILED;
336         }
337
338         rpcout = nc_client_send_rpc(nc_client, rpc_node, 10000);
339         if(rpcout == 0) {
340             log_error("feature-control rpc failed\n");
341             manager_sr_notif_send_instance_changed("config FAILED - feature-control RPC", ctx->function_type, instance->container.name, instance);
342             nc_client_disconnect(nc_client);
343             lyd_free_withsiblings(rpc_node);
344             return NTS_ERR_FAILED;
345         }
346         else {
347             lyd_free_withsiblings(rpcout);
348         }
349         lyd_free_withsiblings(rpc_node);
350     }
351
352     instance->is_init = true;
353     instance->is_configured = true;
354     nc_client_disconnect(nc_client);
355     manager_sr_notif_send_instance_changed("config SUCCESS", ctx->function_type, instance->container.name, instance);
356     log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"%s"LOG_COLOR_RESET" configured via netconf\n", instance->container.name);
357
358     return NTS_ERR_OK;
359 }
360
361 int manager_actions_stop(manager_context_t *ctx) {
362     assert(ctx);
363
364     manager_network_function_instance_t *instance = &ctx->instance[ctx->started_instances - 1];
365     char instance_name[512];
366     strcpy(instance_name, instance->container.name);
367
368     if(instance->is_mounted) {
369         if(manager_actions_unmount(ctx) != NTS_ERR_OK) {
370             log_error("failed to unmount instance\n");
371         }
372     }
373
374     int rc = docker_stop(&instance->container);
375     if(rc != NTS_ERR_OK) {
376         log_error("docker_device_stop failed\n");
377         manager_sr_notif_send_instance_changed("stop FAILED - Docker error", ctx->function_type, instance_name, 0);
378         return NTS_ERR_FAILED;
379     }
380
381     //free ports
382     for(int i = 0; i < framework_environment.settings.ssh_connections; i++) {
383         manager_port[i + ctx->instance[ctx->started_instances - 1].container.host_netconf_ssh_port] = MANAGER_PROTOCOL_UNUSED;
384     }
385
386     for(int i = 0; i < framework_environment.settings.tls_connections; i++) {
387         manager_port[i + ctx->instance[ctx->started_instances - 1].container.host_netconf_tls_port] = MANAGER_PROTOCOL_UNUSED;
388     }
389
390     for(int i = 0; i < framework_environment.settings.ftp_connections; i++) {
391         manager_port[i + ctx->instance[ctx->started_instances - 1].container.host_ftp_port] = MANAGER_PROTOCOL_UNUSED;
392     }
393
394     for(int i = 0; i < framework_environment.settings.sftp_connections; i++) {
395         manager_port[i + ctx->instance[ctx->started_instances - 1].container.host_sftp_port] = MANAGER_PROTOCOL_UNUSED;
396     }
397
398     free(instance->mount_point_addressing_method);
399
400     if(ctx->started_instances > 1) {
401         ctx->instance = (manager_network_function_instance_t *)realloc(ctx->instance, sizeof(manager_network_function_instance_t) * ctx->started_instances);
402         if(ctx->instance == 0) {
403             log_error("realloc failed\n");
404             manager_sr_notif_send_instance_changed("stop FAILED - realloc", ctx->function_type, instance_name, 0);
405             return NTS_ERR_FAILED;
406         }
407     }
408     else {
409         free(ctx->instance);
410         ctx->instance = 0;
411     }
412     ctx->started_instances--;
413     manager_sr_notif_send_instance_changed("stop SUCCESS", ctx->function_type, instance_name, 0);
414     log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"%s"LOG_COLOR_RESET" stopped\n", instance_name);
415     
416
417     return NTS_ERR_OK;
418 }
419
420 int manager_actions_mount(manager_context_t *ctx) {
421     assert(ctx);
422
423     manager_network_function_instance_t *instance = &ctx->instance[ctx->mounted_instances];
424
425     if(instance->is_mounted == true) {
426         manager_sr_notif_send_instance_changed("mount SUCCESS - already mounted", ctx->function_type, instance->container.name, instance);
427         return NTS_ERR_OK;
428     }
429
430     controller_details_t *controller;
431     controller = controller_details_get(0);
432     if(controller == 0) {
433         log_error("could not get controller details\n");
434         manager_sr_notif_send_instance_changed("mount FAILED - no controller details", ctx->function_type, instance->container.name, instance);
435         return NTS_ERR_FAILED;
436     }
437
438     for(int i = 0; i < (framework_environment.settings.ssh_connections + framework_environment.settings.tls_connections); i++) {
439         char *protocol;
440         char *protocol_data;
441
442         char *ip = 0;
443         uint16_t port = 0;
444         if(instance->mount_point_addressing_method[0] == 'd') {
445             ip = instance->container.docker_ip;
446         }
447         else {
448             ip = instance->container.host_ip;
449         }
450
451
452         if(i < framework_environment.settings.ssh_connections) {
453             protocol = "SSH";
454             protocol_data = "\
455             \"network-topology:netconf-node-topology:username\": \"netconf\",\
456             \"network-topology:netconf-node-topology:password\": \"netconf!\"";
457
458             if(instance->mount_point_addressing_method[0] == 'd') {
459                 port = instance->container.docker_netconf_ssh_port + i;
460             }
461             else {
462                 port = instance->container.host_netconf_ssh_port + i;
463             }
464         }
465         else {
466             protocol = "TLS";
467             protocol_data = "\
468             \"netconf-node-topology:key-based\" : {\
469                 \"netconf-node-topology:username\" : \"netconf\",\
470                 \"netconf-node-topology:key-id\" : \""KS_KEY_NAME"\"\
471             }";
472
473             if(instance->mount_point_addressing_method[0] == 'd') {
474                 port = instance->container.docker_netconf_tls_port + i - framework_environment.settings.ssh_connections;
475             }
476             else {
477                 port = instance->container.host_netconf_tls_port + i - framework_environment.settings.ssh_connections;
478             }
479         }
480
481         char *json_template = "\
482         {\
483             \"network-topology:node\": [{\
484                     \"network-topology:node-id\": \"%s\",\
485                     \"network-topology:netconf-node-topology:host\": \"%s\",\
486                     \"network-topology:netconf-node-topology:port\": \"%d\",\
487                     \"network-topology:netconf-node-topology:tcp-only\": \"false\",\
488                     \"network-topology:netconf-node-topology:protocol\": {\
489                         \"network-topology:netconf-node-topology:name\": \"%s\"\
490                     },\
491                     %s,\
492                     \"network-topology:netconf-node-topology:connection-timeout-millis\": \"20000\",\
493                     \"network-topology:netconf-node-topology:default-request-timeout-millis\": \"60000\",\
494                     \"network-topology:netconf-node-topology:max-connection-attempts\": \"3\"\
495             }]\
496         }";
497
498         char node_id[128];
499         char json[4096];
500         if(framework_environment.settings.ssh_connections + framework_environment.settings.tls_connections > 1) {
501             sprintf(node_id, "%s-%d", instance->container.name, port);
502         }
503         else {
504             sprintf(node_id, "%s", instance->container.name);
505         }
506         sprintf(json, json_template, node_id, ip, port, protocol, protocol_data);
507
508         char url[512];
509         sprintf(url, "%s/rests/data/network-topology:network-topology/topology=topology-netconf/node=%s", controller->base_url, node_id);
510         int rc = http_request(url, controller->username, controller->password, "PUT", json, 0, 0);
511         if(rc != NTS_ERR_OK) {
512             log_error("http_request failed\n");
513             controller_details_free(controller);
514             manager_sr_notif_send_instance_changed("mount FAILED - REST request", ctx->function_type, instance->container.name, instance);
515             return NTS_ERR_FAILED;
516         }
517     }
518
519     controller_details_free(controller);
520
521     instance->is_mounted = true;
522     ctx->mounted_instances++;
523     manager_sr_notif_send_instance_changed("mount SUCCESS", ctx->function_type, instance->container.name, instance);
524     log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"%s"LOG_COLOR_RESET" mounted\n", instance->container.name);
525
526     return NTS_ERR_OK;
527 }
528
529 int manager_actions_unmount(manager_context_t *ctx) {
530     assert(ctx);
531
532     int ret = NTS_ERR_OK;
533
534     manager_network_function_instance_t *instance = &ctx->instance[ctx->mounted_instances - 1];
535
536     if(instance->is_mounted == false) {
537         log_error("tried to unmount an unmounted instance\n");
538         manager_sr_notif_send_instance_changed("unmount FAILED - already unmounted", ctx->function_type, instance->container.name, instance);
539         return NTS_ERR_OK;
540     }
541
542     controller_details_t *controller;
543     controller = controller_details_get(0);
544     if(controller == 0) {
545         log_error("could not get controller details\n");
546         manager_sr_notif_send_instance_changed("unmount FAILED - no controller details", ctx->function_type, instance->container.name, instance);
547         return NTS_ERR_FAILED;
548     }
549
550     for(int i = 0; i < (framework_environment.settings.ssh_connections + framework_environment.settings.tls_connections); i++) {
551         uint16_t port = 0;
552         if(i < framework_environment.settings.ssh_connections) {
553             if(instance->mount_point_addressing_method[0] == 'd') {
554                 port = instance->container.docker_netconf_ssh_port + i;
555             }
556             else {
557                 port = instance->container.host_netconf_ssh_port + i;
558             }
559         }
560         else {
561             if(instance->mount_point_addressing_method[0] == 'd') {
562                 port = instance->container.docker_netconf_tls_port + i - framework_environment.settings.ssh_connections;
563             }
564             else {
565                 port = instance->container.host_netconf_tls_port + i - framework_environment.settings.ssh_connections;
566             }
567         }
568         char node_id[128];
569         if(framework_environment.settings.ssh_connections + framework_environment.settings.tls_connections > 1) {
570             sprintf(node_id, "%s-%d", instance->container.name, port);
571         }
572         else {
573             sprintf(node_id, "%s", instance->container.name);
574         }
575
576         char url[512];
577         sprintf(url, "%s/rests/data/network-topology:network-topology/topology=topology-netconf/node=%s", controller->base_url, node_id);
578         int rc = http_request(url, controller->username, controller->password, "DELETE", "", 0, 0);
579         if(rc != NTS_ERR_OK) {
580             log_error("http_request failed\n");
581             manager_sr_notif_send_instance_changed("unmount FAILED - REST request", ctx->function_type, instance->container.name, instance);
582             ret = NTS_ERR_FAILED;
583         }
584     }
585
586     controller_details_free(controller);
587
588     ctx->mounted_instances--;
589     ctx->instance[ctx->mounted_instances].is_mounted = false;
590     manager_sr_notif_send_instance_changed("unmount SUCCESS", ctx->function_type, instance->container.name, instance);
591     log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"%s"LOG_COLOR_RESET" unmounted\n", instance->container.name);
592
593     return ret;
594 }