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"
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"
34 static uint16_t manager_start_port = 0;
35 static uint8_t manager_port[65536];
37 void manager_operations_init(void) {
38 manager_start_port = framework_environment.host_base_port;
39 for(int i = 0; i < 65536; i++) {
44 int manager_start_instance(manager_network_function_type *function_type) {
45 assert(function_type);
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;
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;
60 asprintf(&instance->name, "%s-%d", function_type->docker_instance_name, function_type->started_instances - 1);
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;
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) {
71 instance->host_port = i;
76 if(instance->host_port == 0) {
77 log_error("no ports available for operation");
79 free(instance->mount_point_addressing_method);
80 free(instance->host_ip);
81 function_type->started_instances--;
82 return NTS_ERR_FAILED;
85 int rc = docker_device_start(function_type, instance);
86 if(rc != NTS_ERR_OK) {
87 log_error("docker_device_start failed");
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;
99 int manager_config_instance(manager_network_function_type *function_type, manager_network_function_instance_t *instance) {
100 assert(function_type);
103 //first wait for the nc server to be up and running
104 while(check_port_open(instance->docker_ip, instance->docker_port) == false) {
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;
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;
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);
127 if(rc != NTS_ERR_OK) {
128 log_error("lyd_utils_dup failed");
129 lyd_free_withsiblings(local_tree);
130 return NTS_ERR_FAILED;
133 nc_client_t *nc_client = nc_client_ssh_connect(instance->docker_ip, instance->docker_port, "netconf", "netconf");
135 log_error("nc_client_ssh_connect");
136 lyd_free_withsiblings(local_tree);
137 return NTS_ERR_FAILED;
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;
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);
154 log_error("failed to create rpc node");
155 nc_client_disconnect(nc_client);
156 return NTS_ERR_FAILED;
159 rpcout = nc_client_send_rpc(nc_client, rpc_node, 5000);
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;
167 lyd_free_withsiblings(rpcout);
169 lyd_free_withsiblings(rpc_node);
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);
174 log_error("failed to create rpc node");
175 nc_client_disconnect(nc_client);
176 return NTS_ERR_FAILED;
179 rpcout = nc_client_send_rpc(nc_client, rpc_node, 1000);
181 log_error("feature-control rpc failed");
182 nc_client_disconnect(nc_client);
183 lyd_free_withsiblings(rpc_node);
184 return NTS_ERR_FAILED;
187 lyd_free_withsiblings(rpcout);
189 lyd_free_withsiblings(rpc_node);
192 instance->is_configured = true;
194 nc_client_disconnect(nc_client);
199 int manager_stop_instance(manager_network_function_type *function_type) {
200 assert(function_type);
202 manager_network_function_instance_t *instance = &function_type->instance[function_type->started_instances - 1];
204 if(instance->is_mounted) {
205 if(manager_unmount_instance(function_type) != NTS_ERR_OK) {
206 log_error("failed to unmount instance");
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;
217 manager_port[instance->host_port] = 0;
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);
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;
234 free(function_type->instance);
235 function_type->instance = 0;
240 int manager_mount_instance(manager_network_function_type *function_type) {
241 assert(function_type);
243 manager_network_function_instance_t *instance = &function_type->instance[function_type->mounted_instances];
245 if(instance->is_mounted == true) {
246 return NTS_ERR_FAILED;
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;
256 for(int i = 0; i < (framework_environment.ssh_connections + framework_environment.tls_connections); i++) {
259 if(i < framework_environment.ssh_connections) {
262 \"network-topology:netconf-node-topology:username\": \"netconf\",\
263 \"network-topology:netconf-node-topology:password\": \"netconf\"";
269 \"netconf-node-topology:key-based\" : {\
270 \"netconf-node-topology:username\" : \"netconf\",\
271 \"netconf-node-topology:key-id\" : \""KS_KEY_NAME"\"\
275 char *json_template = "\
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\"\
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\"\
295 if(instance->mount_point_addressing_method[0] == 'd') {
296 ip = instance->docker_ip;
297 port = instance->docker_port + i;
300 ip = instance->host_ip;
301 port = instance->host_port + i;
304 asprintf(&node_id, "%s-%d", instance->name, port);
305 asprintf(&json, json_template, node_id, ip, port, protocol, protocol_data);
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");
315 controller_details_free(controller);
316 return NTS_ERR_FAILED;
324 controller_details_free(controller);
326 instance->is_mounted = true;
327 function_type->mounted_instances++;
332 int manager_unmount_instance(manager_network_function_type *function_type) {
333 assert(function_type);
334 int ret = NTS_ERR_OK;
336 manager_network_function_instance_t *instance = &function_type->instance[function_type->mounted_instances - 1];
338 if(instance->is_mounted == false) {
339 log_error("tried to unmount an unmounted instance");
340 return NTS_ERR_FAILED;
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;
350 for(int i = 0; i < (framework_environment.ssh_connections + framework_environment.tls_connections); i++) {
352 if(function_type->mount_point_addressing_method[0] == 'd') {
353 port = instance->docker_port + i;
356 port = instance->host_port + i;
359 asprintf(&node_id, "%s-%d", instance->name, port);
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;
373 controller_details_free(controller);
375 function_type->mounted_instances--;
376 function_type->instance[function_type->mounted_instances].is_mounted = false;