Bugfix for SIM-63
[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/nc_config.h"
32 #include "utils/nc_client.h"
33 #include "utils/http_client.h"
34 #include "utils/nts_utils.h"
35
36 int manager_actions_start(manager_context_t *ctx) {
37     assert(ctx);
38
39     int started_instances = ctx->started_instances;
40     char instance_name[512];
41     sprintf(instance_name, "%s-%d", ctx->docker_instance_name, started_instances);
42
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;
47
48     if(framework_environment.settings.ssh_connections) {
49         while((netconf_ssh_port) && (manager_port[netconf_ssh_port] != MANAGER_PROTOCOL_UNUSED)) {
50             netconf_ssh_port++;
51         }
52
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;
58             }
59         }
60
61         for(int i = 0; i < framework_environment.settings.ssh_connections; i++) {
62             manager_port[i + netconf_ssh_port] = MANAGER_PROTOCOL_NETCONF_SSH;
63         }
64     }
65
66     if(framework_environment.settings.tls_connections) {
67         while((netconf_tls_port) && (manager_port[netconf_tls_port] != MANAGER_PROTOCOL_UNUSED)) {
68             netconf_tls_port++;
69         }
70
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);
75
76                 for(int i = 0; i < framework_environment.settings.ssh_connections; i++) {
77                     manager_port[i + netconf_ssh_port] = MANAGER_PROTOCOL_UNUSED;
78                 }
79                 return NTS_ERR_FAILED;
80             }
81         }
82
83         for(int i = 0; i < framework_environment.settings.tls_connections; i++) {
84             manager_port[i + netconf_tls_port] = MANAGER_PROTOCOL_NETCONF_TLS;
85         }
86     }
87
88     if(framework_environment.settings.ftp_connections) {
89         while((ftp_port) && (manager_port[ftp_port] != MANAGER_PROTOCOL_UNUSED)) {
90             ftp_port++;
91         }
92
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);
97
98                 for(int i = 0; i < framework_environment.settings.ssh_connections; i++) {
99                     manager_port[i + netconf_ssh_port] = MANAGER_PROTOCOL_UNUSED;
100                 }
101
102                 for(int i = 0; i < framework_environment.settings.tls_connections; i++) {
103                     manager_port[i + netconf_tls_port] = MANAGER_PROTOCOL_UNUSED;
104                 }
105                 return NTS_ERR_FAILED;
106             }
107         }
108
109         for(int i = 0; i < framework_environment.settings.ftp_connections; i++) {
110             manager_port[i + ftp_port] = MANAGER_PROTOCOL_FTP;
111         }
112     }
113
114     if(framework_environment.settings.sftp_connections) {
115         while((sftp_port) && (manager_port[sftp_port] != MANAGER_PROTOCOL_UNUSED)) {
116             sftp_port++;
117         }
118
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);
123
124                 for(int i = 0; i < framework_environment.settings.ssh_connections; i++) {
125                     manager_port[i + netconf_ssh_port] = MANAGER_PROTOCOL_UNUSED;
126                 }
127
128                 for(int i = 0; i < framework_environment.settings.tls_connections; i++) {
129                     manager_port[i + netconf_tls_port] = MANAGER_PROTOCOL_UNUSED;
130                 }
131
132                 for(int i = 0; i < framework_environment.settings.ftp_connections; i++) {
133                     manager_port[i + ftp_port] = MANAGER_PROTOCOL_UNUSED;
134                 }
135                 return NTS_ERR_FAILED;
136             }
137         }
138
139         for(int i = 0; i < framework_environment.settings.sftp_connections; i++) {
140             manager_port[i + sftp_port] = MANAGER_PROTOCOL_SFTP;
141         }
142     }
143
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;
150         }
151
152         for(int i = 0; i < framework_environment.settings.tls_connections; i++) {
153             manager_port[i + netconf_tls_port] = MANAGER_PROTOCOL_UNUSED;
154         }
155
156         for(int i = 0; i < framework_environment.settings.ftp_connections; i++) {
157             manager_port[i + ftp_port] = MANAGER_PROTOCOL_UNUSED;
158         }
159
160         for(int i = 0; i < framework_environment.settings.sftp_connections; i++) {
161             manager_port[i + sftp_port] = MANAGER_PROTOCOL_UNUSED;
162         }
163         return NTS_ERR_FAILED;
164     }
165
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);
171
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;
178         }
179
180         for(int i = 0; i < framework_environment.settings.tls_connections; i++) {
181             manager_port[i + netconf_tls_port] = MANAGER_PROTOCOL_UNUSED;
182         }
183
184         for(int i = 0; i < framework_environment.settings.ftp_connections; i++) {
185             manager_port[i + ftp_port] = MANAGER_PROTOCOL_UNUSED;
186         }
187
188         for(int i = 0; i < framework_environment.settings.sftp_connections; i++) {
189             manager_port[i + sftp_port] = MANAGER_PROTOCOL_UNUSED;
190         }
191         return NTS_ERR_FAILED;
192     }
193
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));
199     }
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);
202     }
203     else {
204         log_add(1, "NETCONF SSH: disabled");
205     }
206
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));
209     }
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);
212     }
213     else {
214         log_add(1, " | NETCONF TLS: disabled");
215     }
216
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));
219     }
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);
222     }
223     else {
224         log_add(1, " | FTP: disabled");
225     }
226
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));
229     }
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);
232     }
233     else {
234         log_add(1, " | SFTP: disabled");
235     }
236
237     log_add(1, "\n");
238
239
240     return NTS_ERR_OK;
241 }
242
243 int manager_actions_config_instance(manager_context_t *ctx, manager_network_function_instance_t *instance) {
244     assert(ctx);
245     assert(instance);
246
247     //first wait for the nc server to be up and running
248     int retries = 0;
249     while(check_port_open(instance->container.docker_ip, CLIENT_CONFIG_TLS_PORT) == false) {
250         usleep(50000);
251         retries++;
252         if(retries >= 200) {
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;
255         }
256     }
257
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;
265     }
266
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;
273     }
274
275     char xpath_s[512];
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;
283     }    
284
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!");
287     if(nc_client == 0) {
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;
292     }
293
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;
301     }
302     
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);
308         if(rpc_node == 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;
313         }
314
315         rpcout = nc_client_send_rpc(nc_client, rpc_node, 10000);
316         if(rpcout == 0) {
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;
322         }
323         else {
324             lyd_free_withsiblings(rpcout);
325         }
326         lyd_free_withsiblings(rpc_node);
327
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);
330         if(rpc_node == 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;
335         }
336
337         rpcout = nc_client_send_rpc(nc_client, rpc_node, 10000);
338         if(rpcout == 0) {
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;
344         }
345         else {
346             lyd_free_withsiblings(rpcout);
347         }
348         lyd_free_withsiblings(rpc_node);
349     }
350
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);
356
357     return NTS_ERR_OK;
358 }
359
360 int manager_actions_stop(manager_context_t *ctx) {
361     assert(ctx);
362
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);
366
367     if(instance->is_mounted) {
368         if(manager_actions_unmount(ctx) != NTS_ERR_OK) {
369             log_error("failed to unmount instance\n");
370         }
371     }
372
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;
378     }
379
380     //free ports
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;
383     }
384
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;
387     }
388
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;
391     }
392
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;
395     }
396
397     free(instance->mount_point_addressing_method);
398
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;
405         }
406     }
407     else {
408         free(ctx->instance);
409         ctx->instance = 0;
410     }
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);
414     
415
416     return NTS_ERR_OK;
417 }
418
419 int manager_actions_mount(manager_context_t *ctx) {
420     assert(ctx);
421
422     manager_network_function_instance_t *instance = &ctx->instance[ctx->mounted_instances];
423
424     if(instance->is_mounted == true) {
425         manager_sr_notif_send_instance_changed("mount SUCCESS - already mounted", ctx->function_type, instance->container.name, instance);
426         return NTS_ERR_OK;
427     }
428
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;
435     }
436
437     for(int i = 0; i < (framework_environment.settings.ssh_connections + framework_environment.settings.tls_connections); i++) {
438         char *protocol;
439         char *protocol_data;
440
441         char *ip = 0;
442         uint16_t port = 0;
443         if(instance->mount_point_addressing_method[0] == 'd') {
444             ip = instance->container.docker_ip;
445         }
446         else {
447             ip = instance->container.host_ip;
448         }
449
450
451         if(i < framework_environment.settings.ssh_connections) {
452             protocol = "SSH";
453             protocol_data = "\
454             \"network-topology:netconf-node-topology:username\": \"netconf\",\
455             \"network-topology:netconf-node-topology:password\": \"netconf!\"";
456
457             if(instance->mount_point_addressing_method[0] == 'd') {
458                 port = instance->container.docker_netconf_ssh_port + i;
459             }
460             else {
461                 port = instance->container.host_netconf_ssh_port + i;
462             }
463         }
464         else {
465             protocol = "TLS";
466             protocol_data = "\
467             \"netconf-node-topology:key-based\" : {\
468                 \"netconf-node-topology:username\" : \"netconf\",\
469                 \"netconf-node-topology:key-id\" : \""KS_KEY_NAME"\"\
470             }";
471
472             if(instance->mount_point_addressing_method[0] == 'd') {
473                 port = instance->container.docker_netconf_tls_port + i - framework_environment.settings.ssh_connections;
474             }
475             else {
476                 port = instance->container.host_netconf_tls_port + i - framework_environment.settings.ssh_connections;
477             }
478         }
479
480         char *json_template = "\
481         {\
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\"\
489                     },\
490                     %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\"\
494             }]\
495         }";
496
497         char node_id[128];
498         char json[4096];
499         if(framework_environment.settings.ssh_connections + framework_environment.settings.tls_connections > 1) {
500             sprintf(node_id, "%s-%d", instance->container.name, port);
501         }
502         else {
503             sprintf(node_id, "%s", instance->container.name);
504         }
505         sprintf(json, json_template, node_id, ip, port, protocol, protocol_data);
506
507         char url[512];
508         sprintf(url, "%s/rests/data/network-topology:network-topology/topology=topology-netconf/node=%s", controller->base_url, node_id);
509         int rc = http_request(url, controller->username, controller->password, "PUT", json, 0, 0);
510         if(rc != NTS_ERR_OK) {
511             log_error("http_request failed\n");
512             controller_details_free(controller);
513             manager_sr_notif_send_instance_changed("mount FAILED - REST request", ctx->function_type, instance->container.name, instance);
514             return NTS_ERR_FAILED;
515         }
516     }
517
518     controller_details_free(controller);
519
520     instance->is_mounted = true;
521     ctx->mounted_instances++;
522     manager_sr_notif_send_instance_changed("mount SUCCESS", ctx->function_type, instance->container.name, instance);
523     log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"%s"LOG_COLOR_RESET" mounted\n", instance->container.name);
524
525     return NTS_ERR_OK;
526 }
527
528 int manager_actions_unmount(manager_context_t *ctx) {
529     assert(ctx);
530
531     int ret = NTS_ERR_OK;
532
533     manager_network_function_instance_t *instance = &ctx->instance[ctx->mounted_instances - 1];
534
535     if(instance->is_mounted == false) {
536         log_error("tried to unmount an unmounted instance\n");
537         manager_sr_notif_send_instance_changed("unmount FAILED - already unmounted", ctx->function_type, instance->container.name, instance);
538         return NTS_ERR_OK;
539     }
540
541     controller_details_t *controller;
542     controller = controller_details_get(0);
543     if(controller == 0) {
544         log_error("could not get controller details\n");
545         manager_sr_notif_send_instance_changed("unmount FAILED - no controller details", ctx->function_type, instance->container.name, instance);
546         return NTS_ERR_FAILED;
547     }
548
549     for(int i = 0; i < (framework_environment.settings.ssh_connections + framework_environment.settings.tls_connections); i++) {
550         uint16_t port = 0;
551         if(i < framework_environment.settings.ssh_connections) {
552             if(instance->mount_point_addressing_method[0] == 'd') {
553                 port = instance->container.docker_netconf_ssh_port + i;
554             }
555             else {
556                 port = instance->container.host_netconf_ssh_port + i;
557             }
558         }
559         else {
560             if(instance->mount_point_addressing_method[0] == 'd') {
561                 port = instance->container.docker_netconf_tls_port + i - framework_environment.settings.ssh_connections;
562             }
563             else {
564                 port = instance->container.host_netconf_tls_port + i - framework_environment.settings.ssh_connections;
565             }
566         }
567         char node_id[128];
568         if(framework_environment.settings.ssh_connections + framework_environment.settings.tls_connections > 1) {
569             sprintf(node_id, "%s-%d", instance->container.name, port);
570         }
571         else {
572             sprintf(node_id, "%s", instance->container.name);
573         }
574
575         char url[512];
576         sprintf(url, "%s/rests/data/network-topology:network-topology/topology=topology-netconf/node=%s", controller->base_url, node_id);
577         int rc = http_request(url, controller->username, controller->password, "DELETE", "", 0, 0);
578         if(rc != NTS_ERR_OK) {
579             log_error("http_request failed\n");
580             manager_sr_notif_send_instance_changed("unmount FAILED - REST request", ctx->function_type, instance->container.name, instance);
581             ret = NTS_ERR_FAILED;
582         }
583     }
584
585     controller_details_free(controller);
586
587     ctx->mounted_instances--;
588     ctx->instance[ctx->mounted_instances].is_mounted = false;
589     manager_sr_notif_send_instance_changed("unmount SUCCESS", ctx->function_type, instance->container.name, instance);
590     log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"%s"LOG_COLOR_RESET" unmounted\n", instance->container.name);
591
592     return ret;
593 }