1 /*************************************************************************
3 * Copyright 2019 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 ***************************************************************************/
28 #include "sysrepo/values.h"
31 #include "simulator-operations.h"
33 volatile int exit_application = 0;
35 volatile unsigned int simulated_devices_config = 0;
36 volatile unsigned int mounted_devices_config = 0;
39 static device_stack_t *device_list = NULL;
41 controller_t controller_details;
43 #define XPATH_MAX_LEN 500
44 #define CONTROLLER_LIST_MAX_LEN 1
47 print_current_config(sr_session_ctx_t *session, const char *module_name)
49 sr_val_t *values = NULL;
52 char xpath[XPATH_MAX_LEN] = {0};
53 snprintf(xpath, XPATH_MAX_LEN, "/%s:*//.", module_name);
55 sr_val_t *odl_ip = NULL;
56 sr_val_t *odl_port = NULL;
57 sr_val_t *odl_username = NULL;
58 sr_val_t *odl_password = NULL;
60 rc = sr_get_items(session, xpath, &values, &count);
61 if (SR_ERR_OK != rc) {
62 printf("Error by sr_get_items: %s\n", sr_strerror(rc));
65 for (size_t i = 0; i < count; i++){
67 sr_print_val(&values[i]);
69 if (sr_xpath_node_name_eq(values[i].xpath, "controller-ip"))
71 rc = sr_dup_val(&values[i], &odl_ip);
73 else if (sr_xpath_node_name_eq(values[i].xpath, "controller-port"))
75 rc = sr_dup_val(&values[i], &odl_port);
77 else if (sr_xpath_node_name_eq(values[i].xpath, "controller-username"))
79 rc = sr_dup_val(&values[i], &odl_username);
81 else if (sr_xpath_node_name_eq(values[i].xpath, "controller-password"))
83 rc = sr_dup_val(&values[i], &odl_password);
87 char *ipv6 = strchr(odl_ip->data.string_val, ':');
88 char odl_ip_string[URL_AND_CREDENTIALS_MAX_LEN];
91 sprintf(odl_ip_string, "[%s]", odl_ip->data.string_val);
95 sprintf(odl_ip_string, "%s", odl_ip->data.string_val);
99 //URL used for mounting/unmounting a device; the device name needs to be appended
100 char url[URL_AND_CREDENTIALS_MAX_LEN];
101 sprintf(url, "http://%s:%d/restconf/config/network-topology:network-topology/topology/"
102 "topology-netconf/node/",
103 odl_ip_string, odl_port->data.uint32_val);
105 char credentials[URL_AND_CREDENTIALS_MAX_LEN];
106 sprintf(credentials, "%s:%s", odl_username->data.string_val, odl_password->data.string_val);
108 //URLs used for adding key pair to ODL, for TLS connections
109 char url_for_keystore_add[URL_AND_CREDENTIALS_MAX_LEN];
110 sprintf(url_for_keystore_add, "http://%s:%d/restconf/operations/netconf-keystore:add-keystore-entry",
111 odl_ip_string, odl_port->data.uint32_val);
113 char url_for_private_key_add[URL_AND_CREDENTIALS_MAX_LEN];
114 sprintf(url_for_private_key_add, "http://%s:%d/restconf/operations/netconf-keystore:add-private-key",
115 odl_ip_string, odl_port->data.uint32_val);
117 char url_for_trusted_ca_add[URL_AND_CREDENTIALS_MAX_LEN];
118 sprintf(url_for_trusted_ca_add, "http://%s:%d/restconf/operations/netconf-keystore:add-trusted-certificate",
119 odl_ip_string, odl_port->data.uint32_val);
121 strcpy(controller_details.url, url);
122 strcpy(controller_details.credentials, credentials);
123 strcpy(controller_details.url_for_keystore_add, url_for_keystore_add);
124 strcpy(controller_details.url_for_private_key_add, url_for_private_key_add);
125 strcpy(controller_details.url_for_trusted_ca_add, url_for_trusted_ca_add);
128 sr_free_val(odl_port);
129 sr_free_val(odl_username);
130 sr_free_val(odl_password);
132 sr_free_values(values, count);
135 static void clean_current_docker_configuration(void);
137 static int simulated_devices_changed(int new_value)
141 if (strcmp(getenv("K8S_DEPLOYMENT"), "true") == 0)
143 if (new_value != simulated_devices_config)
145 simulated_devices_config = new_value;
146 rc = send_k8s_scale(new_value);
149 printf("Could not send new_scale=%d to k8s cluster.\n", new_value);
155 if (simulated_devices_config > new_value)
157 //we are configuring less elements that currently
158 for (int i = 0; i < simulated_devices_config - new_value; ++i)
160 rc = stop_device(device_list);
163 else if (simulated_devices_config < new_value)
165 //we are configuring more elements that currently
166 for (int i = 0; i < new_value - simulated_devices_config; ++i)
168 rc = start_device(device_list);
171 printf("ERROR: Could not start simulated device. Ignoring, trying with the next simulated device, if any...\n");
176 simulated_devices_config = new_value;
181 int mounted_devices_changed(sr_session_ctx_t *session, int new_value)
185 if (mounted_devices_config > new_value)
187 //we need have less mounted elements
188 for (int i = 0; i < mounted_devices_config - new_value; ++i)
190 printf("Sending unmount device...\n");
191 rc = unmount_device(device_list, controller_details);
194 else if (mounted_devices_config < new_value)
196 //we are configuring more elements that currently
197 for (int i = 0; i < new_value - mounted_devices_config; ++i)
199 printf("Sending mount device...\n");
200 rc = mount_device(device_list, controller_details);
204 mounted_devices_config = new_value;
210 simulator_config_change_cb(sr_session_ctx_t *session, const char *module_name, sr_notif_event_t event, void *private_ctx)
214 printf("\n\n ========== CONFIG HAS CHANGED, CURRENT RUNNING CONFIG %s: ==========\n\n", module_name);
215 print_current_config(session, module_name);
217 sr_val_t *val = NULL;
219 /* get the value from sysrepo, we do not care if the value did not change in our case */
220 rc = sr_get_item(session, "/network-topology-simulator:simulator-config/simulated-devices", &val);
221 if (rc != SR_ERR_OK) {
225 rc = simulated_devices_changed(val->data.uint32_val);
226 if (rc != SR_ERR_OK) {
233 /* get the value from sysrepo, we do not care if the value did not change in our case */
234 rc = sr_get_item(session, "/network-topology-simulator:simulator-config/mounted-devices", &val);
235 if (rc != SR_ERR_OK) {
239 if (mounted_devices_config != val->data.uint32_val)
241 if (val->data.uint32_val > simulated_devices_config)
243 printf("Cannot set mount value greater than number of simulated devices.\n");
249 rc = mounted_devices_changed(session, val->data.uint32_val);
250 if (rc != SR_ERR_OK) {
260 /* get the value from sysrepo, we do not care if the value did not change in our case */
261 rc = sr_get_items(session, "/network-topology-simulator:simulator-config/notification-config/fault-notification-delay-period", &val, &count);
262 if (rc != SR_ERR_OK) {
266 rc = notification_delay_period_changed(val, count);
267 if (rc != SR_ERR_OK) {
270 sr_free_values(val, count);
273 /* get the value from sysrepo, we do not care if the value did not change in our case */
274 rc = sr_get_item(session, "/network-topology-simulator:simulator-config/notification-config/ves-heartbeat-period", &val);
275 if (rc != SR_ERR_OK) {
279 rc = ves_heartbeat_period_changed(val->data.uint32_val);
280 if (rc != SR_ERR_OK) {
287 /* get the value from sysrepo, we do not care if the value did not change in our case */
288 rc = sr_get_item(session, "/network-topology-simulator:simulator-config/ves-endpoint-details/ves-endpoint-ip", &val);
289 if (rc != SR_ERR_OK) {
293 rc = ves_ip_changed(val->data.string_val);
294 if (rc != SR_ERR_OK) {
301 /* get the value from sysrepo, we do not care if the value did not change in our case */
302 rc = sr_get_item(session, "/network-topology-simulator:simulator-config/ves-endpoint-details/ves-endpoint-port", &val);
303 if (rc != SR_ERR_OK) {
307 rc = ves_port_changed(val->data.uint16_val);
308 if (rc != SR_ERR_OK) {
315 /* get the value from sysrepo, we do not care if the value did not change in our case */
316 rc = sr_get_item(session, "/network-topology-simulator:simulator-config/ves-endpoint-details/ves-registration", &val);
317 if (rc != SR_ERR_OK) {
321 rc = ves_registration_changed(val->data.bool_val);
322 if (rc != SR_ERR_OK) {
329 /* get the value from sysrepo, we do not care if the value did not change in our case */
330 rc = sr_get_item(session, "/network-topology-simulator:simulator-config/notification-config/is-netconf-available", &val);
331 if (rc != SR_ERR_OK) {
335 rc = is_netconf_available_changed(val->data.bool_val);
336 if (rc != SR_ERR_OK) {
343 /* get the value from sysrepo, we do not care if the value did not change in our case */
344 rc = sr_get_item(session, "/network-topology-simulator:simulator-config/notification-config/is-ves-available", &val);
345 if (rc != SR_ERR_OK) {
349 rc = is_ves_available_changed(val->data.bool_val);
350 if (rc != SR_ERR_OK) {
357 /* get the value from sysrepo, we do not care if the value did not change in our case */
358 rc = sr_get_item(session, "/network-topology-simulator:simulator-config/netconf-call-home", &val);
359 if (rc != SR_ERR_OK) {
363 rc = netconf_call_home_changed(val->data.bool_val);
364 if (rc != SR_ERR_OK) {
371 /* get the value from sysrepo, we do not care if the value did not change in our case */
372 rc = sr_get_item(session, "/network-topology-simulator:simulator-config/controller-details/controller-ip", &val);
373 if (rc != SR_ERR_OK) {
377 rc = controller_ip_changed(val->data.string_val);
378 if (rc != SR_ERR_OK) {
385 /* get the value from sysrepo, we do not care if the value did not change in our case */
386 rc = sr_get_item(session, "/network-topology-simulator:simulator-config/controller-details/controller-port", &val);
387 if (rc != SR_ERR_OK) {
391 rc = controller_port_changed(val->data.uint16_val);
392 if (rc != SR_ERR_OK) {
399 /* get the value from sysrepo, we do not care if the value did not change in our case */
400 rc = sr_get_item(session, "/network-topology-simulator:simulator-config/controller-details/netconf-call-home-port", &val);
401 if (rc != SR_ERR_OK) {
405 rc = controller_netconf_call_home_port_changed(val->data.uint16_val);
406 if (rc != SR_ERR_OK) {
413 /* get the value from sysrepo, we do not care if the value did not change in our case */
414 rc = sr_get_item(session, "/network-topology-simulator:simulator-config/controller-details/controller-username", &val);
415 if (rc != SR_ERR_OK) {
419 rc = controller_username_changed(val->data.string_val);
420 if (rc != SR_ERR_OK) {
427 /* get the value from sysrepo, we do not care if the value did not change in our case */
428 rc = sr_get_item(session, "/network-topology-simulator:simulator-config/controller-details/controller-password", &val);
429 if (rc != SR_ERR_OK) {
433 rc = controller_password_changed(val->data.string_val);
434 if (rc != SR_ERR_OK) {
444 printf("NTSimulator config change callback failed: %s.", sr_strerror(rc));
454 simulator_status_cb(const char *xpath, sr_val_t **values, size_t *values_cnt,
455 uint64_t request_id, const char *original_xpath, void *private_ctx)
459 // printf("\n\n ========== Called simulator_status_cb for xpath: %s ==========\n\n", xpath);
461 counterAlarms ves_counter, netconf_counter;
462 rc = compute_notifications_count(&ves_counter, &netconf_counter);
465 printf("Could not compute the total number of notification count.\n");
468 if (sr_xpath_node_name_eq(xpath, "simulated-devices-list"))
471 size_t current_num_of_values= 0;
473 if (simulated_devices_config == 0) //nothing to return if no devices are running
481 rc = get_docker_containers_operational_state_curl(device_list);
484 printf("Could not get the operational state for the devices simulated.\n");
485 return SR_ERR_OPERATION_FAILED;
488 device_t *current_device = device_list->head;
490 while (current_device != NULL)
492 counterAlarms vesCount, netconfCount;
493 rc = getDeviceCounters(current_device->device_id, &vesCount, &netconfCount);
496 printf("Could not get Notification Counters for device with uuid=\"%s\"", current_device->device_id);
499 char device_name[200];
500 sprintf(device_name, "%s-%d", getenv("CONTAINER_NAME"), current_device->device_number);
502 CREATE_NEW_VALUE(rc, v, current_num_of_values);
504 sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/%s", xpath, device_name, "device-ip");
505 v[current_num_of_values - 1].type = SR_STRING_T;
506 v[current_num_of_values - 1].data.string_val = getenv("NTS_IP");
508 for (int i = 0; i < NETCONF_CONNECTIONS_PER_DEVICE; ++i)
510 CREATE_NEW_VALUE(rc, v, current_num_of_values);
512 sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/%s", xpath, device_name, "device-port");
513 v[current_num_of_values - 1].type = SR_UINT32_T;
514 v[current_num_of_values - 1].data.uint32_val = current_device->netconf_port + i;
517 CREATE_NEW_VALUE(rc, v, current_num_of_values);
519 sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/%s", xpath, device_name, "is-mounted");
520 v[current_num_of_values - 1].type = SR_BOOL_T;
521 v[current_num_of_values - 1].data.bool_val = current_device->is_mounted;
523 char *operational_state = get_docker_container_operational_state(device_list, current_device->device_id);
525 CREATE_NEW_VALUE(rc, v, current_num_of_values);
527 sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/%s", xpath, device_name, "operational-state");
528 sr_val_build_str_data(&v[current_num_of_values - 1], SR_ENUM_T, "%s", operational_state);
530 CREATE_NEW_VALUE(rc, v, current_num_of_values);
532 sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/ves-notifications/%s", xpath, device_name, "normal");
533 v[current_num_of_values - 1].type = SR_UINT32_T;
534 v[current_num_of_values - 1].data.uint32_val = vesCount.normal;
536 CREATE_NEW_VALUE(rc, v, current_num_of_values);
538 sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/ves-notifications/%s", xpath, device_name, "warning");
539 v[current_num_of_values - 1].type = SR_UINT32_T;
540 v[current_num_of_values - 1].data.uint32_val = vesCount.warning;
542 CREATE_NEW_VALUE(rc, v, current_num_of_values);
544 sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/ves-notifications/%s", xpath, device_name, "minor");
545 v[current_num_of_values - 1].type = SR_UINT32_T;
546 v[current_num_of_values - 1].data.uint32_val = vesCount.minor;
548 CREATE_NEW_VALUE(rc, v, current_num_of_values);
550 sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/ves-notifications/%s", xpath, device_name, "major");
551 v[current_num_of_values - 1].type = SR_UINT32_T;
552 v[current_num_of_values - 1].data.uint32_val = vesCount.major;
554 CREATE_NEW_VALUE(rc, v, current_num_of_values);
556 sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/ves-notifications/%s", xpath, device_name, "critical");
557 v[current_num_of_values - 1].type = SR_UINT32_T;
558 v[current_num_of_values - 1].data.uint32_val = vesCount.critical;
560 CREATE_NEW_VALUE(rc, v, current_num_of_values);
562 sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/netconf-notifications/%s", xpath, device_name, "normal");
563 v[current_num_of_values - 1].type = SR_UINT32_T;
564 v[current_num_of_values - 1].data.uint32_val = netconfCount.normal;
566 CREATE_NEW_VALUE(rc, v, current_num_of_values);
568 sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/netconf-notifications/%s", xpath, device_name, "warning");
569 v[current_num_of_values - 1].type = SR_UINT32_T;
570 v[current_num_of_values - 1].data.uint32_val = netconfCount.warning;
572 CREATE_NEW_VALUE(rc, v, current_num_of_values);
574 sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/netconf-notifications/%s", xpath, device_name, "minor");
575 v[current_num_of_values - 1].type = SR_UINT32_T;
576 v[current_num_of_values - 1].data.uint32_val = netconfCount.minor;
578 CREATE_NEW_VALUE(rc, v, current_num_of_values);
580 sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/netconf-notifications/%s", xpath, device_name, "major");
581 v[current_num_of_values - 1].type = SR_UINT32_T;
582 v[current_num_of_values - 1].data.uint32_val = netconfCount.major;
584 CREATE_NEW_VALUE(rc, v, current_num_of_values);
586 sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/netconf-notifications/%s", xpath, device_name, "critical");
587 v[current_num_of_values - 1].type = SR_UINT32_T;
588 v[current_num_of_values - 1].data.uint32_val = netconfCount.critical;
590 current_device = current_device->next;
593 //return the values that we have just created
595 *values_cnt = current_num_of_values;
597 else if (sr_xpath_node_name_eq(xpath, "simulation-usage-details"))
599 float cpu_usage = 0.0, mem_usage = 0.0;
601 char *resource_usage_from_script = get_docker_container_resource_stats();
603 if (resource_usage_from_script != NULL)
605 printf("Received line: %s\n", resource_usage_from_script);
606 sscanf(resource_usage_from_script, "CPU=%f%%;RAM=%fMiB", &cpu_usage, &mem_usage);
607 printf("Read cpu=\"%f\" and mem=\"%f\"\n", cpu_usage, mem_usage);
608 free(resource_usage_from_script);
612 /* convenient functions such as this can be found in sysrepo/values.h */
613 size_t current_num_of_values= 0;
615 CREATE_NEW_VALUE(rc, v, current_num_of_values);
617 sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "running-simulated-devices");
618 v[current_num_of_values - 1].type = SR_UINT32_T;
619 v[current_num_of_values - 1].data.uint32_val = get_current_number_of_devices(device_list);
621 CREATE_NEW_VALUE(rc, v, current_num_of_values);
623 sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "running-mounted-devices");
624 v[current_num_of_values - 1].type = SR_UINT32_T;
625 v[current_num_of_values - 1].data.uint32_val = get_current_number_of_mounted_devices(device_list);
627 CREATE_NEW_VALUE(rc, v, current_num_of_values);
629 sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "base-netconf-port");
630 v[current_num_of_values - 1].type = SR_UINT32_T;
631 v[current_num_of_values - 1].data.uint32_val = get_netconf_port_base();
633 CREATE_NEW_VALUE(rc, v, current_num_of_values);
635 sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "cpu-usage");
636 v[current_num_of_values - 1].type = SR_DECIMAL64_T;
637 v[current_num_of_values - 1].data.decimal64_val = cpu_usage;
639 CREATE_NEW_VALUE(rc, v, current_num_of_values);
641 sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "mem-usage");
642 v[current_num_of_values - 1].type = SR_UINT32_T;
643 v[current_num_of_values - 1].data.uint32_val = (int)mem_usage;
645 CREATE_NEW_VALUE(rc, v, current_num_of_values);
647 sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "ssh-connections");
648 v[current_num_of_values - 1].type = SR_UINT32_T;
649 v[current_num_of_values - 1].data.uint32_val = getSshConnectionsFromConfigJson();
651 CREATE_NEW_VALUE(rc, v, current_num_of_values);
653 sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "tls-connections");
654 v[current_num_of_values - 1].type = SR_UINT32_T;
655 v[current_num_of_values - 1].data.uint32_val = getTlsConnectionsFromConfigJson();
657 //return the values that we have just created
659 *values_cnt = current_num_of_values;
661 else if (sr_xpath_node_name_eq(xpath, "total-ves-notifications"))
664 /* convenient functions such as this can be found in sysrepo/values.h */
665 size_t current_num_of_values= 0;
667 CREATE_NEW_VALUE(rc, v, current_num_of_values);
669 sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "normal");
670 v[current_num_of_values - 1].type = SR_UINT32_T;
671 v[current_num_of_values - 1].data.uint32_val = ves_counter.normal;
673 CREATE_NEW_VALUE(rc, v, current_num_of_values);
675 sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "warning");
676 v[current_num_of_values - 1].type = SR_UINT32_T;
677 v[current_num_of_values - 1].data.uint32_val = ves_counter.warning;
679 CREATE_NEW_VALUE(rc, v, current_num_of_values);
681 sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "minor");
682 v[current_num_of_values - 1].type = SR_UINT32_T;
683 v[current_num_of_values - 1].data.uint32_val = ves_counter.minor;
685 CREATE_NEW_VALUE(rc, v, current_num_of_values);
687 sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "major");
688 v[current_num_of_values - 1].type = SR_UINT32_T;
689 v[current_num_of_values - 1].data.uint32_val = ves_counter.major;
691 CREATE_NEW_VALUE(rc, v, current_num_of_values);
693 sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "critical");
694 v[current_num_of_values - 1].type = SR_UINT32_T;
695 v[current_num_of_values - 1].data.uint32_val = ves_counter.critical;
697 //return the values that we have just created
699 *values_cnt = current_num_of_values;
701 else if (sr_xpath_node_name_eq(xpath, "total-netconf-notifications"))
704 /* convenient functions such as this can be found in sysrepo/values.h */
705 size_t current_num_of_values= 0;
707 CREATE_NEW_VALUE(rc, v, current_num_of_values);
709 sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "normal");
710 v[current_num_of_values - 1].type = SR_UINT32_T;
711 v[current_num_of_values - 1].data.uint32_val = netconf_counter.normal;
713 CREATE_NEW_VALUE(rc, v, current_num_of_values);
715 sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "warning");
716 v[current_num_of_values - 1].type = SR_UINT32_T;
717 v[current_num_of_values - 1].data.uint32_val = netconf_counter.warning;
719 CREATE_NEW_VALUE(rc, v, current_num_of_values);
721 sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "minor");
722 v[current_num_of_values - 1].type = SR_UINT32_T;
723 v[current_num_of_values - 1].data.uint32_val = netconf_counter.minor;
725 CREATE_NEW_VALUE(rc, v, current_num_of_values);
727 sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "major");
728 v[current_num_of_values - 1].type = SR_UINT32_T;
729 v[current_num_of_values - 1].data.uint32_val = netconf_counter.major;
731 CREATE_NEW_VALUE(rc, v, current_num_of_values);
733 sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "critical");
734 v[current_num_of_values - 1].type = SR_UINT32_T;
735 v[current_num_of_values - 1].data.uint32_val = netconf_counter.critical;
737 //return the values that we have just created
739 *values_cnt = current_num_of_values;
745 static int odl_add_key_pair_cb(const char *xpath, const sr_val_t *input, const size_t input_cnt,
746 sr_val_t **output, size_t *output_cnt, void *private_ctx)
749 controller_t controller_list[CONTROLLER_LIST_MAX_LEN];
750 int controller_list_size = 0;
752 controller_list[0] = controller_details;
753 controller_list_size++;
755 for (int i = 0; i < controller_list_size; ++i)
757 printf("%d iteration: Got back url=%s and credentials=%s\n", i, controller_list[i].url, controller_list[i].credentials);
760 rc = add_key_pair_to_odl(controller_list, controller_list_size);
763 printf("Failed to add key pair to ODL.\n");
764 return SR_ERR_OPERATION_FAILED;
770 static int invoke_notification_cb(const char *xpath, const sr_val_t *input, const size_t input_cnt,
771 sr_val_t **output, size_t *output_cnt, void *private_ctx)
775 char *device_name = NULL, *module_name = NULL, *notification_object = NULL;
777 /* print input values */
778 printf("\n\n ========== RECEIVED RPC REQUEST ==========\n\n");
779 printf(">>> RPC Input:\n\n");
781 device_name = strdup(input[0].data.string_val);
782 module_name = strdup(input[1].data.string_val);
783 notification_object = strdup(input[2].data.string_val);
785 rc = sr_new_values(1, output);
786 if (SR_ERR_OK != rc) {
790 /* set 'output/step-count' leaf */
791 rc = sr_val_set_xpath(&(*output)[0], "/network-topology-simulator:invoke-notification/status");
792 if (SR_ERR_OK != rc) {
796 rc = invoke_device_notification(device_name, module_name, notification_object);
800 sr_val_build_str_data(&(*output)[0], SR_ENUM_T, "%s", "ERROR");
804 sr_val_build_str_data(&(*output)[0], SR_ENUM_T, "%s", "SUCCESS");
813 sigint_handler(int signum)
815 exit_application = 1;
819 main(int argc, char **argv)
821 sr_conn_ctx_t *connection = NULL;
822 sr_session_ctx_t *session = NULL;
823 sr_subscription_ctx_t *subscription = NULL;
826 setbuf(stdout, NULL);
828 rc = _init_curl_k8s();
831 fprintf(stderr, "Could not initialize cURL for K8S connection: %s\n", sr_strerror(rc));
834 device_list = new_device_stack();
838 fprintf(stderr, "Could not initialize cURL: %s\n", sr_strerror(rc));
841 rc = writeSkeletonConfigFile();
844 fprintf(stderr, "Could not initialize configuration JSON file: %s\n", sr_strerror(rc));
847 /* connect to sysrepo */
848 rc = sr_connect("network-topology-simulator", SR_CONN_DEFAULT, &connection);
849 if (SR_ERR_OK != rc) {
850 fprintf(stderr, "Error by sr_connect: %s\n", sr_strerror(rc));
855 rc = sr_session_start(connection, SR_DS_STARTUP, SR_SESS_DEFAULT, &session);
856 if (SR_ERR_OK != rc) {
857 fprintf(stderr, "Error by sr_session_start: %s\n", sr_strerror(rc));
861 // setting the values that come in an ENV variable as defaults - ves-heartbeat-period
862 int vesHeartbeatPeriod = getIntFromString(getenv("VesHeartbeatPeriod"), 0);
864 sr_val_t value = { 0 };
865 value.type = SR_UINT32_T;
866 value.data.uint32_val = vesHeartbeatPeriod;
867 rc = sr_set_item(session, "/network-topology-simulator:simulator-config/notification-config/ves-heartbeat-period",
868 &value, SR_EDIT_DEFAULT);
869 if (SR_ERR_OK != rc) {
870 printf("Error by sr_set_item: %s\n", sr_strerror(rc));
874 rc = ves_heartbeat_period_changed(vesHeartbeatPeriod);
875 if (SR_ERR_OK != rc) {
876 printf("Error by ves_heartbeat_period_changed: %s\n", sr_strerror(rc));
880 // setting the values that come in an ENV variable as defaults - is-netconf-available
882 int isNetconfAvailable = 1;
884 char *isNetconfAvailablString = getenv("IsNetconfAvailable");
885 if (isNetconfAvailablString != NULL)
887 if (strcmp(isNetconfAvailablString, "false") == 0)
889 isNetconfAvailable = 0;
893 value = (const sr_val_t) { 0 };
894 value.type = SR_BOOL_T;
895 value.data.bool_val = isNetconfAvailable;
896 rc = sr_set_item(session, "/network-topology-simulator:simulator-config/notification-config/is-netconf-available",
897 &value, SR_EDIT_DEFAULT);
898 if (SR_ERR_OK != rc) {
899 printf("Error by sr_set_item: %s\n", sr_strerror(rc));
903 rc = is_netconf_available_changed(isNetconfAvailable);
904 if (SR_ERR_OK != rc) {
905 printf("Error by is_netconf_available_changed: %s\n", sr_strerror(rc));
909 // setting the values that come in an ENV variable as defaults - is-ves-available
911 int isVesAvailable = 1;
913 char *isVesAvailablString = getenv("IsVesAvailable");
914 if (isVesAvailablString != NULL)
916 if (strcmp(isVesAvailablString, "false") == 0)
922 value = (const sr_val_t) { 0 };
923 value.type = SR_BOOL_T;
924 value.data.bool_val = isVesAvailable;
925 rc = sr_set_item(session, "/network-topology-simulator:simulator-config/notification-config/is-ves-available",
926 &value, SR_EDIT_DEFAULT);
927 if (SR_ERR_OK != rc) {
928 printf("Error by sr_set_item: %s\n", sr_strerror(rc));
932 rc = is_ves_available_changed(isVesAvailable);
933 if (SR_ERR_OK != rc) {
934 printf("Error by is_ves_available_changed: %s\n", sr_strerror(rc));
938 // setting the values that come in an ENV variable as defaults - ves-endpoint-port
940 int vesEndpointPort = getIntFromString(getenv("VesEndpointPort"), 8080);
942 value = (const sr_val_t) { 0 };
943 value.type = SR_UINT16_T;
944 value.data.uint16_val = vesEndpointPort;
945 rc = sr_set_item(session, "/network-topology-simulator:simulator-config/ves-endpoint-details/ves-endpoint-port",
946 &value, SR_EDIT_DEFAULT);
947 if (SR_ERR_OK != rc) {
948 printf("Error by sr_set_item: %s\n", sr_strerror(rc));
952 rc = ves_port_changed(vesEndpointPort);
953 if (SR_ERR_OK != rc) {
954 printf("Error by ves_port_changed: %s\n", sr_strerror(rc));
958 // setting the values that come in an ENV variable as defaults - ves-endpoint-ip
960 value = (const sr_val_t) { 0 };
961 value.type = SR_STRING_T;
962 value.data.string_val = getenv("VesEndpointIp");
963 rc = sr_set_item(session, "/network-topology-simulator:simulator-config/ves-endpoint-details/ves-endpoint-ip",
964 &value, SR_EDIT_DEFAULT);
965 if (SR_ERR_OK != rc) {
966 printf("Error by sr_set_item: %s\n", sr_strerror(rc));
970 rc = ves_ip_changed(getenv("VesEndpointIp"));
971 if (SR_ERR_OK != rc) {
972 printf("Error by ves_ip_changed: %s\n", sr_strerror(rc));
976 // setting the values that come in an ENV variable as defaults - ssh-connections
978 int sshConnections = getIntFromString(getenv("SshConnections"), 1);
980 rc = ssh_connections_changed(sshConnections);
981 if (SR_ERR_OK != rc) {
982 printf("Error by ssh_connections_changed: %s\n", sr_strerror(rc));
986 // setting the values that come in an ENV variable as defaults - tls-connections
988 int tlsConnections = getIntFromString(getenv("TlsConnections"), 0);
990 rc = tls_connections_changed(tlsConnections);
991 if (SR_ERR_OK != rc) {
992 printf("Error by tls_connections_changed: %s\n", sr_strerror(rc));
996 if (strcmp(getenv("K8S_DEPLOYMENT"), "true") == 0)
998 rc = send_k8s_extend_port();
1001 printf("Could not send the number of ports to k8s cluster\n");
1005 // setting the values that come in an ENV variable as defaults - controller-ip
1007 value = (const sr_val_t) { 0 };
1008 value.type = SR_STRING_T;
1009 value.data.string_val = getenv("ControllerIp");
1010 rc = sr_set_item(session, "/network-topology-simulator:simulator-config/controller-details/controller-ip",
1011 &value, SR_EDIT_DEFAULT);
1012 if (SR_ERR_OK != rc) {
1013 printf("Error by sr_set_item: %s\n", sr_strerror(rc));
1017 rc = controller_ip_changed(getenv("ControllerIp"));
1018 if (SR_ERR_OK != rc) {
1019 printf("Error by controller_ip_changed: %s\n", sr_strerror(rc));
1023 // setting the values that come in an ENV variable as defaults - controller-port
1025 int controllerPort = getIntFromString(getenv("ControllerPort"), 8181);
1027 value = (const sr_val_t) { 0 };
1028 value.type = SR_UINT16_T;
1029 value.data.uint16_val = controllerPort;
1030 rc = sr_set_item(session, "/network-topology-simulator:simulator-config/controller-details/controller-port",
1031 &value, SR_EDIT_DEFAULT);
1032 if (SR_ERR_OK != rc) {
1033 printf("Error by sr_set_item: %s\n", sr_strerror(rc));
1037 rc = controller_port_changed(controllerPort);
1038 if (SR_ERR_OK != rc) {
1039 printf("Error by controller_port_changed: %s\n", sr_strerror(rc));
1043 // setting the values that come in an ENV variable as defaults - netconf-call-home-port
1045 int netconfCallHomePort = getIntFromString(getenv("NetconfCallHomePort"), 6666);
1047 value = (const sr_val_t) { 0 };
1048 value.type = SR_UINT16_T;
1049 value.data.uint16_val = netconfCallHomePort;
1050 rc = sr_set_item(session, "/network-topology-simulator:simulator-config/controller-details/netconf-call-home-port",
1051 &value, SR_EDIT_DEFAULT);
1052 if (SR_ERR_OK != rc) {
1053 printf("Error by sr_set_item: %s\n", sr_strerror(rc));
1057 rc = controller_netconf_call_home_port_changed(netconfCallHomePort);
1058 if (SR_ERR_OK != rc) {
1059 printf("Error by controller_netconf_call_home_port_changed: %s\n", sr_strerror(rc));
1063 // setting the values that come in an ENV variable as defaults - controller-username
1065 value = (const sr_val_t) { 0 };
1066 value.type = SR_STRING_T;
1067 value.data.string_val = getenv("ControllerUsername");
1068 rc = sr_set_item(session, "/network-topology-simulator:simulator-config/controller-details/controller-username",
1069 &value, SR_EDIT_DEFAULT);
1070 if (SR_ERR_OK != rc) {
1071 printf("Error by sr_set_item: %s\n", sr_strerror(rc));
1075 rc = controller_username_changed(getenv("ControllerUsername"));
1076 if (SR_ERR_OK != rc) {
1077 printf("Error by controller_username_changed: %s\n", sr_strerror(rc));
1081 // setting the values that come in an ENV variable as defaults - controller-password
1083 value = (const sr_val_t) { 0 };
1084 value.type = SR_STRING_T;
1085 value.data.string_val = getenv("ControllerPassword");
1086 rc = sr_set_item(session, "/network-topology-simulator:simulator-config/controller-details/controller-password",
1087 &value, SR_EDIT_DEFAULT);
1088 if (SR_ERR_OK != rc) {
1089 printf("Error by sr_set_item: %s\n", sr_strerror(rc));
1093 rc = controller_password_changed(getenv("ControllerPassword"));
1094 if (SR_ERR_OK != rc) {
1095 printf("Error by controller_password_changed: %s\n", sr_strerror(rc));
1099 // setting the values that come in an ENV variable as defaults - netconf-call-home
1101 int netconfCallHome = 1;
1103 char *netconfCallHomeString = getenv("NetconfCallHome");
1104 if (netconfCallHomeString != NULL)
1106 if (strcmp(netconfCallHomeString, "false") == 0)
1108 netconfCallHome = 0;
1112 value = (const sr_val_t) { 0 };
1113 value.type = SR_BOOL_T;
1114 value.data.bool_val = netconfCallHome;
1115 rc = sr_set_item(session, "/network-topology-simulator:simulator-config/netconf-call-home",
1116 &value, SR_EDIT_DEFAULT);
1117 if (SR_ERR_OK != rc) {
1118 printf("Error by sr_set_item: %s\n", sr_strerror(rc));
1122 rc = netconf_call_home_changed(netconfCallHome);
1123 if (SR_ERR_OK != rc) {
1124 printf("Error by netconf_call_home_changed: %s\n", sr_strerror(rc));
1128 //commit the changes that we have done until now
1129 rc = sr_commit(session);
1130 if (SR_ERR_OK != rc) {
1131 printf("Error by sr_commit: %s\n", sr_strerror(rc));
1135 /* read startup config */
1136 printf("\n\n ========== READING STARTUP CONFIG network-topology-simulator: ==========\n\n");
1137 print_current_config(session, "network-topology-simulator");
1139 /* subscribe for changes in running config */
1140 rc = sr_module_change_subscribe(session, "network-topology-simulator", simulator_config_change_cb, NULL,
1141 0, SR_SUBSCR_DEFAULT | SR_SUBSCR_APPLY_ONLY, &subscription);
1142 if (SR_ERR_OK != rc) {
1143 fprintf(stderr, "Error by sr_module_change_subscribe: %s\n", sr_strerror(rc));
1147 /* subscribe as state data provider for the ntsimulator state data */
1148 rc = sr_dp_get_items_subscribe(session, "/network-topology-simulator:simulator-status", simulator_status_cb, NULL,
1149 SR_SUBSCR_CTX_REUSE, &subscription);
1150 if (rc != SR_ERR_OK) {
1154 rc = notification_delay_period_changed(NULL, 0);
1155 if (rc != SR_ERR_OK) {
1156 printf("Could not write the delay period to file!\n");
1160 rc = _init_curl_odl();
1161 if (rc != SR_ERR_OK)
1163 fprintf(stderr, "Could not initialize cURL for ODL connection: %s\n", sr_strerror(rc));
1166 rc = sr_rpc_subscribe(session, "/network-topology-simulator:add-key-pair-to-odl", odl_add_key_pair_cb, (void *)session,
1167 SR_SUBSCR_CTX_REUSE, &subscription);
1169 printf("\n\n ========== STARTUP CONFIG network-topology-simulator APPLIED AS RUNNING ==========\n\n");
1171 rc = writeSkeletonStatusFile();
1172 if (rc != SR_ERR_OK)
1174 fprintf(stderr, "Could not initialize status JSON file: %s\n", sr_strerror(rc));
1177 rc = sr_rpc_subscribe(session, "/network-topology-simulator:invoke-notification", invoke_notification_cb,
1178 (void *)session, SR_SUBSCR_DEFAULT, &subscription);
1179 if (SR_ERR_OK != rc) {
1180 fprintf(stderr, "Error by sr_rpc_subscribe: %s\n", sr_strerror(rc));
1184 rc = pull_docker_image_of_simulated_device();
1186 /* loop until ctrl-c is pressed / SIGINT is received */
1187 signal(SIGINT, sigint_handler);
1188 signal(SIGTERM, sigint_handler);
1189 signal(SIGPIPE, SIG_IGN);
1191 while (!exit_application) {
1193 sleep(1); /* or do some more useful work... */
1196 printf("Application exit requested, exiting.\n");
1199 if (NULL != subscription) {
1200 sr_unsubscribe(session, subscription);
1202 if (NULL != session) {
1203 sr_session_stop(session);
1205 if (NULL != connection) {
1206 sr_disconnect(connection);
1209 clean_current_docker_configuration();
1210 rc = cleanup_curl();
1211 rc = cleanup_curl_odl();
1212 rc = cleanup_curl_k8s();
1217 static void clean_current_docker_configuration(void)
1219 if (strcmp(getenv("K8S_DEPLOYMENT"), "true"))
1224 printf("Cleaning docker containers...\n");
1226 if (device_list == NULL)
1231 for (int i = 0; i < simulated_devices_config; ++i)
1233 stop_device(device_list);
1236 printf("Cleaning completed!\n");