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