165e7bb9d1e5a49bc5248ed526d210e86b0530af
[sim/o1-interface.git] / ntsimulator / src / ntsimulator-manager / ntsimulator-manager.c
1 /*************************************************************************
2 *
3 * Copyright 2019 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
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <signal.h>
23 #include <inttypes.h>
24 #include <limits.h>
25 #include <string.h>
26
27 #include "sysrepo.h"
28 #include "sysrepo/values.h"
29
30 #include "utils.h"
31 #include "simulator-operations.h"
32
33 volatile int exit_application = 0;
34
35 volatile unsigned int simulated_devices_config = 0;
36 volatile unsigned int mounted_devices_config = 0;
37
38
39 static device_stack_t *device_list = NULL;
40
41 controller_t controller_details;
42
43 #define XPATH_MAX_LEN 500
44 #define CONTROLLER_LIST_MAX_LEN 1
45
46 static void
47 print_current_config(sr_session_ctx_t *session, const char *module_name)
48 {
49     sr_val_t *values = NULL;
50     size_t count = 0;
51     int rc = SR_ERR_OK;
52     char xpath[XPATH_MAX_LEN] = {0};
53     snprintf(xpath, XPATH_MAX_LEN, "/%s:*//.", module_name);
54
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;
59
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));
63         return;
64     }
65     for (size_t i = 0; i < count; i++){
66
67         sr_print_val(&values[i]);
68
69         if (sr_xpath_node_name_eq(values[i].xpath, "controller-ip"))
70         {
71                 rc = sr_dup_val(&values[i], &odl_ip);
72         }
73         else if (sr_xpath_node_name_eq(values[i].xpath, "controller-port"))
74         {
75                 rc = sr_dup_val(&values[i], &odl_port);
76         }
77         else if (sr_xpath_node_name_eq(values[i].xpath, "controller-username"))
78         {
79                 rc = sr_dup_val(&values[i], &odl_username);
80         }
81         else if (sr_xpath_node_name_eq(values[i].xpath, "controller-password"))
82         {
83                 rc = sr_dup_val(&values[i], &odl_password);
84         }
85     }
86
87     char *ipv6 = strchr(odl_ip->data.string_val, ':');
88     char odl_ip_string[URL_AND_CREDENTIALS_MAX_LEN];
89     if (ipv6 != NULL)
90     {
91         sprintf(odl_ip_string, "[%s]", odl_ip->data.string_val);
92     }
93     else
94     {
95         sprintf(odl_ip_string, "%s", odl_ip->data.string_val);
96     }
97
98
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);
104
105    char credentials[URL_AND_CREDENTIALS_MAX_LEN];
106    sprintf(credentials, "%s:%s", odl_username->data.string_val, odl_password->data.string_val);
107
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);
112
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);
116
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);
120
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);
126
127    sr_free_val(odl_ip);
128    sr_free_val(odl_port);
129    sr_free_val(odl_username);
130    sr_free_val(odl_password);
131
132    sr_free_values(values, count);
133 }
134
135 static void clean_current_docker_configuration(void);
136
137 static int simulated_devices_changed(int new_value)
138 {
139         int rc = SR_ERR_OK;
140
141     if (strcmp(getenv("K8S_DEPLOYMENT"), "true") == 0)
142     {
143         if (new_value != simulated_devices_config)
144         {
145             simulated_devices_config = new_value;
146             rc = send_k8s_scale(new_value);
147             if (rc != SR_ERR_OK)
148             {
149                 printf("Could not send new_scale=%d to k8s cluster.\n", new_value);
150             }
151         }
152         return SR_ERR_OK;
153     }
154
155     if (simulated_devices_config > new_value)
156     {
157         //we are configuring less elements that currently
158         for (int i = 0; i < simulated_devices_config - new_value; ++i)
159         {
160                 rc = stop_device(device_list);
161         }
162     }
163     else if (simulated_devices_config < new_value)
164     {
165         //we are configuring more elements that currently
166         for (int i = 0; i < new_value - simulated_devices_config; ++i)
167         {
168                 rc = start_device(device_list);
169             if (rc != SR_ERR_OK)
170             {
171                 printf("ERROR: Could not start simulated device. Ignoring, trying with the next simulated device, if any...\n");
172             }
173         }
174     }
175
176     simulated_devices_config = new_value;
177
178     return rc;
179 }
180
181 int mounted_devices_changed(sr_session_ctx_t *session, int new_value)
182 {
183         int rc = SR_ERR_OK;
184
185         if (mounted_devices_config > new_value)
186         {
187           //we need have less mounted elements
188           for (int i = 0; i < mounted_devices_config - new_value; ++i)
189           {
190                   printf("Sending unmount device...\n");
191                   rc = unmount_device(device_list, controller_details);
192           }
193         }
194         else if (mounted_devices_config < new_value)
195         {
196           //we are configuring more elements that currently
197           for (int i = 0; i < new_value - mounted_devices_config; ++i)
198           {
199                   printf("Sending mount device...\n");
200                   rc = mount_device(device_list, controller_details);
201           }
202         }
203
204         mounted_devices_config = new_value;
205
206     return rc;
207 }
208
209 static int
210 simulator_config_change_cb(sr_session_ctx_t *session, const char *module_name, sr_notif_event_t event, void *private_ctx)
211 {
212         int rc;
213
214     printf("\n\n ========== CONFIG HAS CHANGED, CURRENT RUNNING CONFIG %s: ==========\n\n", module_name);
215     print_current_config(session, module_name);
216
217     sr_val_t *val = NULL;
218
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) {
222         goto sr_error;
223     }
224
225     rc = simulated_devices_changed(val->data.uint32_val);
226     if (rc != SR_ERR_OK) {
227         goto sr_error;
228     }
229
230     sr_free_val(val);
231         val = NULL;
232
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) {
236         goto sr_error;
237     }
238
239     if (mounted_devices_config != val->data.uint32_val)
240     {
241         if (val->data.uint32_val > simulated_devices_config)
242         {
243                 printf("Cannot set mount value greater than number of simulated devices.\n");
244                 sr_free_val(val);
245                         val = NULL;
246                 return SR_ERR_OK;
247         }
248
249                 rc = mounted_devices_changed(session, val->data.uint32_val);
250                 if (rc != SR_ERR_OK) {
251                         goto sr_error;
252                 }
253     }
254
255     sr_free_val(val);
256         val = NULL;
257
258     size_t count = 0;
259
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) {
263         goto sr_error;
264     }
265
266     rc = notification_delay_period_changed(val, count);
267     if (rc != SR_ERR_OK) {
268         goto sr_error;
269     }
270     sr_free_values(val, count);
271         val = NULL;
272
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) {
276                 goto sr_error;
277         }
278
279         rc = ves_heartbeat_period_changed(val->data.uint32_val);
280         if (rc != SR_ERR_OK) {
281                 goto sr_error;
282         }
283
284         sr_free_val(val);
285         val = NULL;
286
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) {
290                 goto sr_error;
291         }
292
293         rc = ves_ip_changed(val->data.string_val);
294         if (rc != SR_ERR_OK) {
295                 goto sr_error;
296         }
297
298         sr_free_val(val);
299         val = NULL;
300
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) {
304                 goto sr_error;
305         }
306
307         rc = ves_port_changed(val->data.uint16_val);
308         if (rc != SR_ERR_OK) {
309                 goto sr_error;
310         }
311
312         sr_free_val(val);
313         val = NULL;
314
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) {
318                 goto sr_error;
319         }
320
321         rc = ves_registration_changed(val->data.bool_val);
322         if (rc != SR_ERR_OK) {
323                 goto sr_error;
324         }
325
326         sr_free_val(val);
327         val = NULL;
328
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) {
332                 goto sr_error;
333         }
334
335         rc = is_netconf_available_changed(val->data.bool_val);
336         if (rc != SR_ERR_OK) {
337                 goto sr_error;
338         }
339
340         sr_free_val(val);
341         val = NULL;
342
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) {
346                 goto sr_error;
347         }
348
349         rc = is_ves_available_changed(val->data.bool_val);
350         if (rc != SR_ERR_OK) {
351                 goto sr_error;
352         }
353
354         sr_free_val(val);
355         val = NULL;
356
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/ssh-connections", &val);
359     if (rc != SR_ERR_OK) {
360         printf("NTS Manager /network-topology-simulator:simulator-config/ssh-connections object not available, ignoring..");
361     }
362     else
363     {
364         rc = ssh_connections_changed(val->data.uint32_val);
365         if (rc != SR_ERR_OK) {
366             goto sr_error;
367         }
368
369         if (strcmp(getenv("K8S_DEPLOYMENT"), "true") == 0)
370         {
371             rc = send_k8s_extend_port();
372             if (rc != SR_ERR_OK)
373             {
374                 printf("Could not send the extended port to k8s cluster.\n");
375             }
376         }
377     }
378
379     sr_free_val(val);
380         val = NULL;
381
382     /* get the value from sysrepo, we do not care if the value did not change in our case */
383     rc = sr_get_item(session, "/network-topology-simulator:simulator-config/tls-connections", &val);
384     if (rc != SR_ERR_OK) {
385         printf("NTS Manager /network-topology-simulator:simulator-config/tls-connections object not available, ignoring..");
386     }
387     else
388     {
389         rc = tls_connections_changed(val->data.uint32_val);
390         if (rc != SR_ERR_OK) {
391             goto sr_error;
392         }
393
394         if (strcmp(getenv("K8S_DEPLOYMENT"), "true") == 0)
395         {
396             rc = send_k8s_extend_port();
397             if (rc != SR_ERR_OK)
398             {
399                 printf("Could not send the extended port to k8s cluster.\n");
400             }
401         }
402     }
403
404     sr_free_val(val);
405         val = NULL;
406
407     return SR_ERR_OK;
408
409 sr_error:
410         printf("NTSimulator config change callback failed: %s.", sr_strerror(rc));
411         if (val != NULL)
412         {
413                 sr_free_val(val);
414                 val = NULL;
415         }
416         return rc;
417 }
418
419 static int
420 simulator_status_cb(const char *xpath, sr_val_t **values, size_t *values_cnt,
421         uint64_t request_id, const char *original_xpath, void *private_ctx)
422 {
423         int rc;
424
425         // printf("\n\n ========== Called simulator_status_cb for xpath: %s ==========\n\n", xpath);
426
427     counterAlarms ves_counter, netconf_counter;
428     rc = compute_notifications_count(&ves_counter, &netconf_counter);
429     if (rc != SR_ERR_OK)
430     {
431         printf("Could not compute the total number of notification count.\n");
432     }
433
434         if (sr_xpath_node_name_eq(xpath, "simulated-devices-list")) 
435     {
436                 sr_val_t *v;
437                 size_t current_num_of_values= 0;
438
439                 if (simulated_devices_config == 0) //nothing to return if no devices are running
440                 {
441                         *values = NULL;
442                         *values_cnt = 0;
443
444                         return SR_ERR_OK;
445                 }
446
447                 rc = get_docker_containers_operational_state_curl(device_list);
448                 if (rc != SR_ERR_OK)
449                 {
450                         printf("Could not get the operational state for the devices simulated.\n");
451                         return SR_ERR_OPERATION_FAILED;
452                 }
453
454                 device_t *current_device = device_list->head;
455
456                 while (current_device != NULL)
457                 {
458             counterAlarms vesCount, netconfCount;
459             rc = getDeviceCounters(current_device->device_id, &vesCount, &netconfCount);
460             if (rc != SR_ERR_OK)
461             {
462                 printf("Could not get Notification Counters for device with uuid=\"%s\"", current_device->device_id);
463             }            
464
465                         CREATE_NEW_VALUE(rc, v, current_num_of_values);
466
467                         sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/%s", xpath, current_device->device_id, "device-ip");
468                         v[current_num_of_values - 1].type = SR_STRING_T;
469                         v[current_num_of_values - 1].data.string_val = getenv("NTS_IP");
470
471                         for (int i = 0; i < NETCONF_CONNECTIONS_PER_DEVICE; ++i)
472                         {
473                                 CREATE_NEW_VALUE(rc, v, current_num_of_values);
474
475                                 sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/%s", xpath, current_device->device_id, "device-port");
476                                 v[current_num_of_values - 1].type = SR_UINT32_T;
477                                 v[current_num_of_values - 1].data.uint32_val = current_device->netconf_port + i;
478                         }
479
480                         CREATE_NEW_VALUE(rc, v, current_num_of_values);
481
482                         sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/%s", xpath, current_device->device_id, "is-mounted");
483                         v[current_num_of_values - 1].type = SR_BOOL_T;
484                         v[current_num_of_values - 1].data.bool_val = current_device->is_mounted;
485
486                         char *operational_state = get_docker_container_operational_state(device_list, current_device->device_id);
487
488                         CREATE_NEW_VALUE(rc, v, current_num_of_values);
489
490                         sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/%s", xpath, current_device->device_id, "operational-state");
491                         sr_val_build_str_data(&v[current_num_of_values - 1], SR_ENUM_T, "%s", operational_state);
492
493             CREATE_NEW_VALUE(rc, v, current_num_of_values);
494
495             sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/ves-notifications/%s", xpath, current_device->device_id, "normal");
496             v[current_num_of_values - 1].type = SR_UINT32_T;
497             v[current_num_of_values - 1].data.uint32_val = vesCount.normal;
498
499             CREATE_NEW_VALUE(rc, v, current_num_of_values);
500
501             sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/ves-notifications/%s", xpath, current_device->device_id, "warning");
502             v[current_num_of_values - 1].type = SR_UINT32_T;
503             v[current_num_of_values - 1].data.uint32_val = vesCount.warning;
504
505             CREATE_NEW_VALUE(rc, v, current_num_of_values);
506
507             sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/ves-notifications/%s", xpath, current_device->device_id, "minor");
508             v[current_num_of_values - 1].type = SR_UINT32_T;
509             v[current_num_of_values - 1].data.uint32_val = vesCount.minor;
510
511             CREATE_NEW_VALUE(rc, v, current_num_of_values);
512
513             sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/ves-notifications/%s", xpath, current_device->device_id, "major");
514             v[current_num_of_values - 1].type = SR_UINT32_T;
515             v[current_num_of_values - 1].data.uint32_val = vesCount.major;
516
517             CREATE_NEW_VALUE(rc, v, current_num_of_values);
518
519             sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/ves-notifications/%s", xpath, current_device->device_id, "critical");
520             v[current_num_of_values - 1].type = SR_UINT32_T;
521             v[current_num_of_values - 1].data.uint32_val = vesCount.critical;
522
523             CREATE_NEW_VALUE(rc, v, current_num_of_values);
524
525             sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/netconf-notifications/%s", xpath, current_device->device_id, "normal");
526             v[current_num_of_values - 1].type = SR_UINT32_T;
527             v[current_num_of_values - 1].data.uint32_val = netconfCount.normal;
528
529             CREATE_NEW_VALUE(rc, v, current_num_of_values);
530
531             sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/netconf-notifications/%s", xpath, current_device->device_id, "warning");
532             v[current_num_of_values - 1].type = SR_UINT32_T;
533             v[current_num_of_values - 1].data.uint32_val = netconfCount.warning;
534
535             CREATE_NEW_VALUE(rc, v, current_num_of_values);
536
537             sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/netconf-notifications/%s", xpath, current_device->device_id, "minor");
538             v[current_num_of_values - 1].type = SR_UINT32_T;
539             v[current_num_of_values - 1].data.uint32_val = netconfCount.minor;
540
541             CREATE_NEW_VALUE(rc, v, current_num_of_values);
542
543             sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/netconf-notifications/%s", xpath, current_device->device_id, "major");
544             v[current_num_of_values - 1].type = SR_UINT32_T;
545             v[current_num_of_values - 1].data.uint32_val = netconfCount.major;
546
547             CREATE_NEW_VALUE(rc, v, current_num_of_values);
548
549             sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/netconf-notifications/%s", xpath, current_device->device_id, "critical");
550             v[current_num_of_values - 1].type = SR_UINT32_T;
551             v[current_num_of_values - 1].data.uint32_val = netconfCount.critical;
552
553                         current_device = current_device->next;
554                 }
555
556                 //return the values that we have just created
557                 *values = v;
558                 *values_cnt = current_num_of_values;
559          }
560          else if (sr_xpath_node_name_eq(xpath, "simulation-usage-details"))
561          {
562                 float cpu_usage = 0.0, mem_usage = 0.0;
563
564                 char *resource_usage_from_script = get_docker_container_resource_stats();
565
566                 if (resource_usage_from_script != NULL)
567                 {
568                         printf("Received line: %s\n", resource_usage_from_script);
569                         sscanf(resource_usage_from_script, "CPU=%f%%;RAM=%fMiB", &cpu_usage, &mem_usage);
570                         printf("Read cpu=\"%f\" and mem=\"%f\"\n", cpu_usage, mem_usage);
571                         free(resource_usage_from_script);
572                 }
573
574                 sr_val_t *v;
575                 /* convenient functions such as this can be found in sysrepo/values.h */
576                 size_t current_num_of_values= 0;
577
578                 CREATE_NEW_VALUE(rc, v, current_num_of_values);
579
580                 sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "running-simulated-devices");
581                 v[current_num_of_values - 1].type = SR_UINT32_T;
582                 v[current_num_of_values - 1].data.uint32_val = get_current_number_of_devices(device_list);
583
584                 CREATE_NEW_VALUE(rc, v, current_num_of_values);
585
586                 sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "running-mounted-devices");
587                 v[current_num_of_values - 1].type = SR_UINT32_T;
588                 v[current_num_of_values - 1].data.uint32_val = get_current_number_of_mounted_devices(device_list);
589
590                 CREATE_NEW_VALUE(rc, v, current_num_of_values);
591
592                 sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "base-netconf-port");
593                 v[current_num_of_values - 1].type = SR_UINT32_T;
594                 v[current_num_of_values - 1].data.uint32_val = get_netconf_port_base();
595
596                 CREATE_NEW_VALUE(rc, v, current_num_of_values);
597
598                 sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "cpu-usage");
599                 v[current_num_of_values - 1].type = SR_DECIMAL64_T;
600                 v[current_num_of_values - 1].data.decimal64_val = cpu_usage;
601
602                 CREATE_NEW_VALUE(rc, v, current_num_of_values);
603
604                 sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "mem-usage");
605                 v[current_num_of_values - 1].type = SR_UINT32_T;
606                 v[current_num_of_values - 1].data.uint32_val = (int)mem_usage;
607
608                 //return the values that we have just created
609                 *values = v;
610                 *values_cnt = current_num_of_values;
611          }
612      else if (sr_xpath_node_name_eq(xpath, "total-ves-notifications"))
613      {
614         sr_val_t *v;
615         /* convenient functions such as this can be found in sysrepo/values.h */
616         size_t current_num_of_values= 0;
617
618         CREATE_NEW_VALUE(rc, v, current_num_of_values);
619
620         sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "normal");
621         v[current_num_of_values - 1].type = SR_UINT32_T;
622         v[current_num_of_values - 1].data.uint32_val = ves_counter.normal;
623
624         CREATE_NEW_VALUE(rc, v, current_num_of_values);
625
626         sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "warning");
627         v[current_num_of_values - 1].type = SR_UINT32_T;
628         v[current_num_of_values - 1].data.uint32_val = ves_counter.warning;
629
630         CREATE_NEW_VALUE(rc, v, current_num_of_values);
631
632         sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "minor");
633         v[current_num_of_values - 1].type = SR_UINT32_T;
634         v[current_num_of_values - 1].data.uint32_val = ves_counter.minor;
635
636         CREATE_NEW_VALUE(rc, v, current_num_of_values);
637
638         sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "major");
639         v[current_num_of_values - 1].type = SR_UINT32_T;
640         v[current_num_of_values - 1].data.uint32_val = ves_counter.major;
641
642         CREATE_NEW_VALUE(rc, v, current_num_of_values);
643
644         sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "critical");
645         v[current_num_of_values - 1].type = SR_UINT32_T;
646         v[current_num_of_values - 1].data.uint32_val = ves_counter.critical;
647
648         //return the values that we have just created
649         *values = v;
650         *values_cnt = current_num_of_values;
651      }
652      else if (sr_xpath_node_name_eq(xpath, "total-netconf-notifications"))
653      {
654         sr_val_t *v;
655         /* convenient functions such as this can be found in sysrepo/values.h */
656         size_t current_num_of_values= 0;
657
658         CREATE_NEW_VALUE(rc, v, current_num_of_values);
659
660         sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "normal");
661         v[current_num_of_values - 1].type = SR_UINT32_T;
662         v[current_num_of_values - 1].data.uint32_val = netconf_counter.normal;
663
664         CREATE_NEW_VALUE(rc, v, current_num_of_values);
665
666         sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "warning");
667         v[current_num_of_values - 1].type = SR_UINT32_T;
668         v[current_num_of_values - 1].data.uint32_val = netconf_counter.warning;
669
670         CREATE_NEW_VALUE(rc, v, current_num_of_values);
671
672         sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "minor");
673         v[current_num_of_values - 1].type = SR_UINT32_T;
674         v[current_num_of_values - 1].data.uint32_val = netconf_counter.minor;
675
676         CREATE_NEW_VALUE(rc, v, current_num_of_values);
677
678         sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "major");
679         v[current_num_of_values - 1].type = SR_UINT32_T;
680         v[current_num_of_values - 1].data.uint32_val = netconf_counter.major;
681
682         CREATE_NEW_VALUE(rc, v, current_num_of_values);
683
684         sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "critical");
685         v[current_num_of_values - 1].type = SR_UINT32_T;
686         v[current_num_of_values - 1].data.uint32_val = netconf_counter.critical;
687
688         //return the values that we have just created
689         *values = v;
690         *values_cnt = current_num_of_values;
691      }
692
693     return SR_ERR_OK;
694 }
695
696 int odl_add_key_pair_cb(const char *xpath, const sr_val_t *input, const size_t input_cnt,
697                 sr_val_t **output, size_t *output_cnt, void *private_ctx)
698 {
699         int rc = SR_ERR_OK;
700         controller_t controller_list[CONTROLLER_LIST_MAX_LEN];
701         int controller_list_size = 0;
702
703         controller_list[0] = controller_details;
704         controller_list_size++;
705
706         for (int i = 0; i < controller_list_size; ++i)
707         {
708                 printf("%d iteration: Got back url=%s and credentials=%s\n", i, controller_list[i].url, controller_list[i].credentials);
709         }
710
711         rc = add_key_pair_to_odl(controller_list, controller_list_size);
712         if (rc != SR_ERR_OK)
713         {
714                 printf("Failed to add key pair to ODL.\n");
715                 return SR_ERR_OPERATION_FAILED;
716         }
717
718         return rc;
719 }
720
721
722 static void
723 sigint_handler(int signum)
724 {
725     exit_application = 1;
726 }
727
728 int
729 main(int argc, char **argv)
730 {
731     sr_conn_ctx_t *connection = NULL;
732     sr_session_ctx_t *session = NULL;
733     sr_subscription_ctx_t *subscription = NULL;
734     int rc = SR_ERR_OK;
735
736     setbuf(stdout, NULL);
737
738     rc = _init_curl_k8s();
739     if (rc != SR_ERR_OK)
740     {
741         fprintf(stderr, "Could not initialize cURL for K8S connection: %s\n", sr_strerror(rc));
742     }
743
744     device_list = new_device_stack();
745     rc = _init_curl();
746     if (rc != SR_ERR_OK)
747     {
748         fprintf(stderr, "Could not initialize cURL: %s\n", sr_strerror(rc));
749     }
750
751     rc = writeSkeletonConfigFile();
752     if (rc != SR_ERR_OK)
753     {
754         fprintf(stderr, "Could not initialize configuration JSON file: %s\n", sr_strerror(rc));
755     }
756
757     /* connect to sysrepo */
758     rc = sr_connect("network-topology-simulator", SR_CONN_DEFAULT, &connection);
759     if (SR_ERR_OK != rc) {
760         fprintf(stderr, "Error by sr_connect: %s\n", sr_strerror(rc));
761         goto cleanup;
762     }
763
764     /* start session */
765     rc = sr_session_start(connection, SR_DS_STARTUP, SR_SESS_DEFAULT, &session);
766     if (SR_ERR_OK != rc) {
767         fprintf(stderr, "Error by sr_session_start: %s\n", sr_strerror(rc));
768         goto cleanup;
769     }
770
771     // setting the values that come in an ENV variable as defaults - ves-heartbeat-period
772     int vesHeartbeatPeriod = getIntFromString(getenv("VesHeartbeatPeriod"), 0);
773
774     sr_val_t value = { 0 };
775     value.type = SR_UINT32_T;
776     value.data.uint32_val = vesHeartbeatPeriod;
777     rc = sr_set_item(session, "/network-topology-simulator:simulator-config/notification-config/ves-heartbeat-period", 
778             &value, SR_EDIT_DEFAULT);
779     if (SR_ERR_OK != rc) {
780         printf("Error by sr_set_item: %s\n", sr_strerror(rc));
781         goto cleanup;
782     }
783
784     rc = ves_heartbeat_period_changed(vesHeartbeatPeriod);
785     if (SR_ERR_OK != rc) {
786         printf("Error by ves_heartbeat_period_changed: %s\n", sr_strerror(rc));
787         goto cleanup;
788     }
789
790     // setting the values that come in an ENV variable as defaults - is-netconf-available
791
792     int isNetconfAvailable = 1;
793
794     char *isNetconfAvailablString = getenv("IsNetconfAvailable");
795     if (isNetconfAvailablString != NULL)
796     {
797         if (strcmp(isNetconfAvailablString, "false") == 0)
798         {
799             isNetconfAvailable = 0;
800         }
801     }
802
803     value = (const sr_val_t) { 0 };
804     value.type = SR_BOOL_T;
805     value.data.bool_val = isNetconfAvailable;
806     rc = sr_set_item(session, "/network-topology-simulator:simulator-config/notification-config/is-netconf-available", 
807             &value, SR_EDIT_DEFAULT);
808     if (SR_ERR_OK != rc) {
809         printf("Error by sr_set_item: %s\n", sr_strerror(rc));
810         goto cleanup;
811     }
812
813     rc = is_netconf_available_changed(isNetconfAvailable);
814     if (SR_ERR_OK != rc) {
815         printf("Error by is_netconf_available_changed: %s\n", sr_strerror(rc));
816         goto cleanup;
817     }
818
819     // setting the values that come in an ENV variable as defaults - is-ves-available
820
821     int isVesAvailable = 1;
822
823     char *isVesAvailablString = getenv("IsVesAvailable");
824     if (isVesAvailablString != NULL)
825     {
826         if (strcmp(isVesAvailablString, "false") == 0)
827         {
828             isVesAvailable = 0;
829         }
830     }
831
832     value = (const sr_val_t) { 0 };
833     value.type = SR_BOOL_T;
834     value.data.bool_val = isVesAvailable;
835     rc = sr_set_item(session, "/network-topology-simulator:simulator-config/notification-config/is-ves-available", 
836             &value, SR_EDIT_DEFAULT);
837     if (SR_ERR_OK != rc) {
838         printf("Error by sr_set_item: %s\n", sr_strerror(rc));
839         goto cleanup;
840     }
841
842     rc = is_ves_available_changed(isVesAvailable);
843     if (SR_ERR_OK != rc) {
844         printf("Error by is_ves_available_changed: %s\n", sr_strerror(rc));
845         goto cleanup;
846     }
847
848     // setting the values that come in an ENV variable as defaults - ves-endpoint-port
849
850     int vesEndpointPort = getIntFromString(getenv("VesEndpointPort"), 8080);
851
852     value = (const sr_val_t) { 0 };
853     value.type = SR_UINT16_T;
854     value.data.uint16_val = vesEndpointPort;
855     rc = sr_set_item(session, "/network-topology-simulator:simulator-config/ves-endpoint-details/ves-endpoint-port", 
856             &value, SR_EDIT_DEFAULT);
857     if (SR_ERR_OK != rc) {
858         printf("Error by sr_set_item: %s\n", sr_strerror(rc));
859         goto cleanup;
860     }
861
862     rc = ves_port_changed(vesEndpointPort);
863     if (SR_ERR_OK != rc) {
864         printf("Error by ves_port_changed: %s\n", sr_strerror(rc));
865         goto cleanup;
866     }
867
868     // setting the values that come in an ENV variable as defaults - ves-endpoint-ip
869
870     value = (const sr_val_t) { 0 };
871     value.type = SR_STRING_T;
872     value.data.string_val = getenv("VesEndpointIp");
873     rc = sr_set_item(session, "/network-topology-simulator:simulator-config/ves-endpoint-details/ves-endpoint-ip", 
874             &value, SR_EDIT_DEFAULT);
875     if (SR_ERR_OK != rc) {
876         printf("Error by sr_set_item: %s\n", sr_strerror(rc));
877         goto cleanup;
878     }
879
880     rc = ves_ip_changed(getenv("VesEndpointIp"));
881     if (SR_ERR_OK != rc) {
882         printf("Error by ves_ip_changed: %s\n", sr_strerror(rc));
883         goto cleanup;
884     }
885
886     // setting the values that come in an ENV variable as defaults - ssh-connections
887
888     int sshConnections = getIntFromString(getenv("SshConnections"), 1);
889
890     value = (const sr_val_t) { 0 };
891     value.type = SR_UINT32_T;
892     value.data.uint32_val = sshConnections;
893     rc = sr_set_item(session, "/network-topology-simulator:simulator-config/ssh-connections",
894             &value, SR_EDIT_DEFAULT);
895     if (SR_ERR_OK != rc) {
896         printf("Error by sr_set_item: %s\n", sr_strerror(rc));
897         goto cleanup;
898     }
899
900     rc = ssh_connections_changed(sshConnections);
901     if (SR_ERR_OK != rc) {
902         printf("Error by ssh_connections_changed: %s\n", sr_strerror(rc));
903         goto cleanup;
904     }
905
906     // setting the values that come in an ENV variable as defaults - tls-connections
907
908     int tlsConnections = getIntFromString(getenv("TlsConnections"), 0);
909
910     value = (const sr_val_t) { 0 };
911     value.type = SR_UINT32_T;
912     value.data.uint32_val = tlsConnections;
913     rc = sr_set_item(session, "/network-topology-simulator:simulator-config/tls-connections",
914             &value, SR_EDIT_DEFAULT);
915     if (SR_ERR_OK != rc) {
916         printf("Error by sr_set_item: %s\n", sr_strerror(rc));
917         goto cleanup;
918     }
919
920     rc = tls_connections_changed(tlsConnections);
921     if (SR_ERR_OK != rc) {
922         printf("Error by tls_connections_changed: %s\n", sr_strerror(rc));
923         goto cleanup;
924     }
925
926     if (strcmp(getenv("K8S_DEPLOYMENT"), "true") == 0)
927     {
928         rc = send_k8s_extend_port();
929         if (rc != SR_ERR_OK)
930         {
931             printf("Could not send the number of ports to k8s cluster\n");
932         }
933     }
934
935     //commit the changes that we have done until now
936     rc = sr_commit(session);
937     if (SR_ERR_OK != rc) {
938         printf("Error by sr_commit: %s\n", sr_strerror(rc));
939         goto cleanup;
940     }
941
942         /* read startup config */
943         printf("\n\n ========== READING STARTUP CONFIG network-topology-simulator: ==========\n\n");
944         print_current_config(session, "network-topology-simulator");
945
946         /* subscribe for changes in running config */
947         rc = sr_module_change_subscribe(session, "network-topology-simulator", simulator_config_change_cb, NULL,
948                         0, SR_SUBSCR_DEFAULT | SR_SUBSCR_APPLY_ONLY, &subscription);
949         if (SR_ERR_OK != rc) {
950                 fprintf(stderr, "Error by sr_module_change_subscribe: %s\n", sr_strerror(rc));
951                 goto cleanup;
952         }
953
954     /* subscribe as state data provider for the ntsimulator state data */
955     rc = sr_dp_get_items_subscribe(session, "/network-topology-simulator:simulator-status", simulator_status_cb, NULL,
956                 SR_SUBSCR_CTX_REUSE, &subscription);
957     if (rc != SR_ERR_OK) {
958         goto cleanup;
959     }
960
961     rc = notification_delay_period_changed(NULL, 0);
962     if (rc != SR_ERR_OK) {
963         printf("Could not write the delay period to file!\n");
964         goto cleanup;
965     }
966
967     rc = _init_curl_odl();
968     if (rc != SR_ERR_OK)
969     {
970         fprintf(stderr, "Could not initialize cURL for ODL connection: %s\n", sr_strerror(rc));
971     }
972
973     rc = sr_rpc_subscribe(session, "/network-topology-simulator:add-key-pair-to-odl", odl_add_key_pair_cb, (void *)session,
974                 SR_SUBSCR_CTX_REUSE, &subscription);
975
976         printf("\n\n ========== STARTUP CONFIG network-topology-simulator APPLIED AS RUNNING ==========\n\n");
977
978     rc = writeSkeletonStatusFile();
979     if (rc != SR_ERR_OK)
980     {
981         fprintf(stderr, "Could not initialize status JSON file: %s\n", sr_strerror(rc));
982     }
983
984     /* loop until ctrl-c is pressed / SIGINT is received */
985     signal(SIGINT, sigint_handler);
986     signal(SIGTERM, sigint_handler);
987     signal(SIGPIPE, SIG_IGN);
988
989     while (!exit_application) {
990
991                 sleep(1);  /* or do some more useful work... */
992     }
993
994     printf("Application exit requested, exiting.\n");
995
996 cleanup:
997     if (NULL != subscription) {
998         sr_unsubscribe(session, subscription);
999     }
1000     if (NULL != session) {
1001         sr_session_stop(session);
1002     }
1003     if (NULL != connection) {
1004         sr_disconnect(connection);
1005     }
1006
1007     clean_current_docker_configuration();
1008     rc = cleanup_curl();
1009     rc = cleanup_curl_odl();
1010     rc = cleanup_curl_k8s();
1011
1012     return rc;
1013 }
1014
1015 static void clean_current_docker_configuration(void)
1016 {
1017     if (strcmp(getenv("K8S_DEPLOYMENT"), "true"))
1018     {
1019         return;
1020     }
1021
1022         printf("Cleaning docker containers...\n");
1023
1024         if (device_list == NULL)
1025         {
1026                 return;
1027         }
1028
1029         for (int i = 0; i < simulated_devices_config; ++i)
1030         {
1031                 stop_device(device_list);
1032         }
1033
1034         printf("Cleaning completed!\n");
1035 }