347c11de9f13fc259227cbb7d1e465f249365e17
[sim/o1-interface.git] / ntsimulator / ntsim-ng / core / app / manager_operations.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
27 #include "core/framework.h"
28 #include "core/docker.h"
29 #include "core/session.h"
30 #include "utils/nc_client.h"
31 #include "utils/http_client.h"
32 #include "utils/nts_utils.h"
33
34 static uint16_t manager_start_port = 0;
35 static uint8_t manager_port[65536];
36
37 void manager_operations_init(void) {
38     manager_start_port = framework_environment.host_base_port;
39     for(int i = 0; i < 65536; i++) {
40         manager_port[i] = 0;
41     }
42 }
43
44 int manager_start_instance(manager_network_function_type *function_type) {
45     assert(function_type);
46     assert_session();
47
48     function_type->started_instances++;
49     function_type->instance = (manager_network_function_instance_t *)realloc(function_type->instance, sizeof(manager_network_function_instance_t) * function_type->started_instances);
50     if(function_type->instance == 0) {
51         log_error("realloc failed");
52         function_type->started_instances--;
53         return NTS_ERR_FAILED;
54     }
55
56     manager_network_function_instance_t *instance = &function_type->instance[function_type->started_instances - 1];
57     instance->is_configured = false;
58     instance->is_mounted = false;
59     
60     asprintf(&instance->name, "%s-%d", function_type->docker_instance_name, function_type->started_instances - 1);
61
62     instance->mount_point_addressing_method = strdup(function_type->mount_point_addressing_method);
63     instance->docker_port = STANDARD_NETCONF_PORT;
64     instance->host_ip = strdup(framework_environment.host_ip);
65     instance->host_port = 0;
66
67     //find start host port
68     for(int i = manager_start_port; i < 65536 - (framework_environment.ssh_connections + framework_environment.tls_connections + framework_environment.ftp_connections + framework_environment.sftp_connections); i += (framework_environment.ssh_connections + framework_environment.tls_connections + framework_environment.ftp_connections + framework_environment.sftp_connections)) {
69         if(manager_port[i] == 0) {
70             manager_port[i] = 1;
71             instance->host_port = i;
72             break;
73         }
74     }
75
76     if(instance->host_port == 0) {
77         log_error("no ports available for operation");
78         free(instance->name);
79         free(instance->mount_point_addressing_method);
80         free(instance->host_ip);
81         return NTS_ERR_FAILED;
82     }
83
84     int rc = docker_device_start(function_type, instance);
85     if(rc != NTS_ERR_OK) {
86         log_error("docker_device_start failed");
87         free(instance->name);
88         free(instance->mount_point_addressing_method);
89         free(instance->host_ip);
90         manager_port[instance->host_port] = 0;
91         return NTS_ERR_FAILED;
92     }
93
94     return NTS_ERR_OK;
95 }
96
97 int manager_config_instance(manager_network_function_type *function_type, manager_network_function_instance_t *instance) {
98     assert(function_type);
99     assert(instance);
100
101     //first wait for the nc server to be up and running
102     while(check_port_open(instance->docker_ip, instance->docker_port) == false) {
103         usleep(10000);
104     }
105
106     //populate sdn-controller and ves-endpoint
107     struct lyd_node *local_tree = 0;
108     int rc = lyd_utils_dup(session_running, "/nts-manager:simulation/sdn-controller", "/nts-network-function:simulation/sdn-controller", &local_tree);
109     if(rc != NTS_ERR_OK) {
110         log_error("lyd_utils_dup failed");
111         return NTS_ERR_FAILED;
112     }
113
114     rc = lyd_utils_dup(session_running, "/nts-manager:simulation/ves-endpoint", "/nts-network-function:simulation/ves-endpoint", &local_tree);
115     if(rc != NTS_ERR_OK) {
116         log_error("lyd_utils_dup failed");
117         lyd_free_withsiblings(local_tree);
118         return NTS_ERR_FAILED;
119     }
120
121     char *xpath_s = 0;
122     asprintf(&xpath_s, "/nts-manager:simulation/network-functions/network-function[function-type='%s']", function_type->function_type_string);
123     rc = lyd_utils_dup(session_running, xpath_s, "/nts-network-function:simulation/network-function", &local_tree);
124     free(xpath_s);
125     if(rc != NTS_ERR_OK) {
126         log_error("lyd_utils_dup failed");
127         lyd_free_withsiblings(local_tree);
128         return NTS_ERR_FAILED;
129     }    
130
131     nc_client_t *nc_client = nc_client_ssh_connect(instance->docker_ip, instance->docker_port, "netconf", "netconf");
132     if(nc_client == 0) {
133         log_error("nc_client_ssh_connect");
134         lyd_free_withsiblings(local_tree);
135         return NTS_ERR_FAILED;
136     }
137
138     rc += nc_client_edit_batch(nc_client, local_tree, 1000);
139     lyd_free_withsiblings(local_tree);
140     if(rc != NTS_ERR_OK) {
141         log_error("nc_client_edit_batch failed %d\n", rc);
142         nc_client_disconnect(nc_client);
143         return NTS_ERR_FAILED;
144     }
145     
146     if(instance->is_configured == false) {
147         //run datastore-random-populate rpc
148         struct lyd_node *rpc_node = 0;
149         struct lyd_node *rpcout = 0;
150         rpc_node = lyd_new_path(0, session_context, "/nts-network-function:datastore-random-populate", 0, 0, 0);
151         if(rpc_node == 0) {
152             log_error("failed to create rpc node");
153             nc_client_disconnect(nc_client);
154             return NTS_ERR_FAILED;
155         }
156
157         rpcout = nc_client_send_rpc(nc_client, rpc_node, 5000);
158         if(rpcout == 0) {
159             log_error("datastore-random-populate rpc failed");
160             nc_client_disconnect(nc_client);
161             lyd_free_withsiblings(rpc_node);
162             return NTS_ERR_FAILED;
163         }
164         else {
165             lyd_free_withsiblings(rpcout);
166         }
167         lyd_free_withsiblings(rpc_node);
168
169         //run feature-control rpc
170         rpc_node = lyd_new_path(0, session_context, "/nts-network-function:feature-control/features", "ves-file-ready ves-heartbeat ves-pnf-registration manual-notification-generation netconf-call-home web-cut-through", 0, 0);
171         if(rpc_node == 0) {
172             log_error("failed to create rpc node");
173             nc_client_disconnect(nc_client);
174             return NTS_ERR_FAILED;
175         }
176
177         rpcout = nc_client_send_rpc(nc_client, rpc_node, 1000);
178         if(rpcout == 0) {
179             log_error("feature-control rpc failed");
180             nc_client_disconnect(nc_client);
181             lyd_free_withsiblings(rpc_node);
182             return NTS_ERR_FAILED;
183         }
184         else {
185             lyd_free_withsiblings(rpcout);
186         }
187         lyd_free_withsiblings(rpc_node);
188     }
189
190     instance->is_configured = true;
191
192     nc_client_disconnect(nc_client);
193
194     return NTS_ERR_OK;
195 }
196
197 int manager_stop_instance(manager_network_function_type *function_type) {
198     assert(function_type);
199
200     manager_network_function_instance_t *instance = &function_type->instance[function_type->started_instances - 1];
201
202     if(instance->is_mounted) {
203         if(manager_unmount_instance(function_type) != NTS_ERR_OK) {
204             log_error("failed to unmount instance");
205             return NTS_ERR_FAILED;
206         }
207     }
208
209     int rc = docker_device_stop(instance);
210     if(rc != NTS_ERR_OK) {
211         log_error("docker_device_stop failed");
212         return NTS_ERR_FAILED;
213     }
214
215     //clear unused ports
216     manager_port[instance->host_port] = 0;
217
218     free(instance->mount_point_addressing_method);
219     free(instance->docker_id);
220     free(instance->name);
221     free(instance->docker_ip);
222     free(instance->host_ip);
223
224     function_type->started_instances--;
225     if(function_type->started_instances) {
226         function_type->instance = (manager_network_function_instance_t *)realloc(function_type->instance, sizeof(manager_network_function_instance_t) * function_type->started_instances);
227         if(function_type->instance == 0) {
228             log_error("realloc failed");
229             return NTS_ERR_FAILED;
230         }
231     }
232     else {
233         free(function_type->instance);
234         function_type->instance = 0;
235     }
236     return NTS_ERR_OK;
237 }
238
239 int manager_mount_instance(manager_network_function_type *function_type) {
240     assert(function_type);
241
242     manager_network_function_instance_t *instance = &function_type->instance[function_type->mounted_instances];
243
244     if(instance->is_mounted == true) {
245         return NTS_ERR_FAILED;
246     }
247
248     controller_details_t *controller;
249     controller = controller_details_get(0);
250     if(controller == 0) {
251         log_error("could not get controller detailes");
252         return NTS_ERR_FAILED;
253     }
254
255     for(int i = 0; i < (framework_environment.ssh_connections + framework_environment.tls_connections); i++) {
256         char *protocol;
257         char *protocol_data;
258         if(i < framework_environment.ssh_connections) {
259             protocol = "SSH";
260             protocol_data = "\
261             \"network-topology:netconf-node-topology:username\": \"netconf\",\
262             \"network-topology:netconf-node-topology:password\": \"netconf\"";
263
264         }
265         else {
266             protocol = "TLS";
267             protocol_data = "\
268             \"netconf-node-topology:key-based\" : {\
269                 \"netconf-node-topology:username\" : \"netconf\",\
270                 \"netconf-node-topology:key-id\" : \""KS_KEY_NAME"\"\
271             }";
272         }
273
274         char *json_template = "\
275         {\
276             \"network-topology:node\": [{\
277                     \"network-topology:node-id\": \"%s\",\
278                     \"network-topology:netconf-node-topology:host\": \"%s\",\
279                     \"network-topology:netconf-node-topology:port\": \"%d\",\
280                     \"network-topology:netconf-node-topology:tcp-only\": \"false\",\
281                     \"network-topology:netconf-node-topology:protocol\": {\
282                         \"network-topology:netconf-node-topology:name\": \"%s\"\
283                     },\
284                     %s,\
285                     \"network-topology:netconf-node-topology:connection-timeout-millis\": \"20000\",\
286                     \"network-topology:netconf-node-topology:default-request-timeout-millis\": \"60000\",\
287                     \"network-topology:netconf-node-topology:max-connection-attempts\": \"3\"\
288             }]\
289         }";
290
291         char *json = 0;
292         uint16_t port = 0;
293         char *ip = 0;
294         if(instance->mount_point_addressing_method[0] == 'd') {
295             ip = instance->docker_ip;
296             port = instance->docker_port + i;
297         }
298         else {
299             ip = instance->host_ip;
300             port = instance->host_port + i;
301         }
302         char *node_id = 0;
303         asprintf(&node_id, "%s-%d", instance->name, port);
304         asprintf(&json, json_template, node_id, ip, port, protocol, protocol_data);
305
306         char *url = 0;
307         asprintf(&url, "%s/rests/data/network-topology:network-topology/topology=topology-netconf/node=%s", controller->base_url, node_id);
308         int rc = http_request(url, controller->username, controller->password, "PUT", json, 0, 0);
309         if(rc != NTS_ERR_OK) {
310             log_error("http_request failed");
311             free(url);
312             free(node_id);
313             free(json);
314             controller_details_free(controller);
315             return NTS_ERR_FAILED;
316         }
317
318         free(url);
319         free(node_id);
320         free(json);
321     }
322
323     controller_details_free(controller);
324
325     instance->is_mounted = true;
326     function_type->mounted_instances++;
327
328     return NTS_ERR_OK;
329 }
330
331 int manager_unmount_instance(manager_network_function_type *function_type) {
332     assert(function_type);
333
334     manager_network_function_instance_t *instance = &function_type->instance[function_type->mounted_instances - 1];
335
336     if(instance->is_mounted == false) {
337         log_error("tried to unmount an unmounted instance");
338         return NTS_ERR_FAILED;
339     }
340
341     controller_details_t *controller;
342     controller = controller_details_get(0);
343     if(controller == 0) {
344         log_error("could not get controller detailes");
345         return NTS_ERR_FAILED;
346     }
347
348     for(int i = 0; i < (framework_environment.ssh_connections + framework_environment.tls_connections); i++) {
349         uint16_t port = 0;
350         if(function_type->mount_point_addressing_method[0] == 'd') {
351             port = instance->docker_port + i;
352         }
353         else {
354             port = instance->host_port + i;
355         }
356         char *node_id = 0;
357         asprintf(&node_id, "%s-%d", instance->name, port);
358
359         char *url = 0;
360         asprintf(&url, "%s/rests/data/network-topology:network-topology/topology=topology-netconf/node=%s", controller->base_url, node_id);
361         int rc = http_request(url, controller->username, controller->password, "DELETE", "", 0, 0);
362         if(rc != NTS_ERR_OK) {
363             log_error("http_request failed");
364             free(url);
365             free(node_id);
366             controller_details_free(controller);
367             return NTS_ERR_FAILED;
368         }
369
370         free(url);
371         free(node_id);
372     }
373
374     controller_details_free(controller);
375
376     function_type->mounted_instances--;
377     function_type->instance[function_type->mounted_instances].is_mounted = false;
378
379     return NTS_ERR_OK;
380 }