Fix TLS issues. Fix VES faultNotification issues.
[sim/o1-interface.git] / ntsimulator / src / ntsimulator-manager / simulator-operations.c
1 /*
2  * simulator-operations.c
3  *
4  *  Created on: Mar 9, 2019
5  *      Author: parallels
6  */
7
8 #include "simulator-operations.h"
9 #include "sysrepo.h"
10 #include "sysrepo/values.h"
11 #include <string.h>
12 #include <math.h>
13 #include <linux/limits.h>
14
15 #include "utils.h"
16
17 #define LINE_BUFSIZE 128
18
19 static  CURL *curl; //share the same curl connection for communicating with the Docker Engine API
20 static  CURL *curl_odl; //share the same curl connection for mounting servers in ODL
21
22 static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
23 {
24   size_t realsize = size * nmemb;
25   struct MemoryStruct *mem = (struct MemoryStruct *)userp;
26
27   char *ptr = realloc(mem->memory, mem->size + realsize + 1);
28   if(ptr == NULL) {
29     /* out of memory! */
30     printf("not enough memory (realloc returned NULL)\n");
31     return 0;
32   }
33
34   mem->memory = ptr;
35   memcpy(&(mem->memory[mem->size]), contents, realsize);
36   mem->size += realsize;
37   mem->memory[mem->size] = 0;
38
39   return realsize;
40 }
41
42 static void set_curl_common_info()
43 {
44         struct curl_slist *chunk = NULL;
45         chunk = curl_slist_append(chunk, "Content-Type: application/json");
46         chunk = curl_slist_append(chunk, "Accept: application/json");
47
48     curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
49
50         curl_easy_setopt(curl, CURLOPT_UNIX_SOCKET_PATH, "/var/run/docker.sock");
51
52         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
53     curl_easy_setopt(curl_odl, CURLOPT_CONNECTTIMEOUT, 2L); // seconds timeout for a connection
54     curl_easy_setopt(curl_odl, CURLOPT_TIMEOUT, 5L); //seconds timeout for an operation
55
56     curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
57 }
58
59 static void set_curl_common_info_odl()
60 {
61         struct curl_slist *chunk = NULL;
62         chunk = curl_slist_append(chunk, "Content-Type: application/xml");
63         chunk = curl_slist_append(chunk, "Accept: application/xml");
64
65     curl_easy_setopt(curl_odl, CURLOPT_HTTPHEADER, chunk);
66
67     curl_easy_setopt(curl_odl, CURLOPT_CONNECTTIMEOUT, 2L); // seconds timeout for a connection
68     curl_easy_setopt(curl_odl, CURLOPT_TIMEOUT, 5L); //seconds timeout for an operation
69
70     curl_easy_setopt(curl_odl, CURLOPT_VERBOSE, 1L);
71 }
72
73 static cJSON* get_docker_container_bindings(void)
74 {
75         struct MemoryStruct curl_response_mem;
76
77         curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
78         curl_response_mem.size = 0;    /* no data at this point */
79
80         CURLcode res;
81
82         curl_easy_reset(curl);
83         set_curl_common_info();
84
85         char url[100];
86         sprintf(url, "http:/v%s/containers/NTS_Manager/json", getenv("DOCKER_ENGINE_VERSION"));
87
88         curl_easy_setopt(curl, CURLOPT_URL, url);
89
90     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
91     curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
92
93         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
94
95         res = curl_easy_perform(curl);
96
97         if (res != CURLE_OK)
98         {
99                 return NULL;
100         }
101         else
102         {
103                 cJSON *json_response = cJSON_Parse(curl_response_mem.memory);
104
105                 printf("%lu bytes retrieved\n", (unsigned long)curl_response_mem.size);
106
107                 if (json_response == NULL)
108                 {
109                         printf("Could not parse JSON response for url=\"%s\"\n", url);
110                         return NULL;
111                 }
112
113                 cJSON *hostConfig = cJSON_GetObjectItemCaseSensitive(json_response, "HostConfig");
114
115                 if (hostConfig == NULL)
116                 {
117                         printf("Could not get HostConfig object\n");
118                         return NULL;
119                 }
120
121                 cJSON *binds = cJSON_GetObjectItemCaseSensitive(hostConfig, "Binds");
122
123                 if (binds == NULL)
124                 {
125                         printf("Could not get Binds object\n");
126                         return NULL;
127                 }
128
129                 cJSON *bindsCopy = cJSON_Duplicate(binds, 1);
130
131             cJSON_Delete(json_response);
132
133                 return bindsCopy;
134         }
135
136         return NULL;
137 }
138
139 static char* create_docker_container_curl(int base_netconf_port, cJSON* managerBinds)
140 {
141         if (managerBinds == NULL)
142         {
143                 printf("Could not retrieve JSON object: Binds\n");
144                 return NULL;
145         }
146         cJSON *binds = cJSON_Duplicate(managerBinds, 1);
147
148         struct MemoryStruct curl_response_mem;
149
150         curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
151         curl_response_mem.size = 0;    /* no data at this point */
152
153         CURLcode res;
154
155         curl_easy_reset(curl);
156         set_curl_common_info();
157
158         char url[100];
159         sprintf(url, "http:/v%s/containers/create", getenv("DOCKER_ENGINE_VERSION"));
160
161         // the docker image name to be used is defined in the Dockerfile of the NTS Manager,
162         // under the MODELS_IMAGE env variable
163         char models_var[50];
164         sprintf(models_var, "%s", getenv("MODELS_IMAGE"));
165
166         curl_easy_setopt(curl, CURLOPT_URL, url);
167
168     cJSON *postDataJson = cJSON_CreateObject();
169
170     if (cJSON_AddStringToObject(postDataJson, "Image", models_var) == NULL)
171         {
172         printf("Could not create JSON object: Image\n");
173                 return NULL;
174         }
175
176     cJSON *hostConfig = cJSON_CreateObject();
177     if (hostConfig == NULL)
178         {
179         printf("Could not create JSON object: HostConfig\n");
180                 return NULL;
181         }
182
183     cJSON_AddItemToObject(postDataJson, "HostConfig", hostConfig);
184
185     cJSON *portBindings = cJSON_CreateObject();
186     if (portBindings == NULL)
187         {
188         printf("Could not create JSON object: PortBindings\n");
189                 return NULL;
190         }
191
192     cJSON_AddItemToObject(hostConfig, "PortBindings", portBindings);
193
194     for (int i = 0; i < NETCONF_CONNECTIONS_PER_DEVICE; ++i)
195     {
196         cJSON *port = cJSON_CreateArray();
197                 if (port == NULL)
198                 {
199                 printf("Could not create JSON object: port\n");
200                         return NULL;
201                 }
202
203                 char dockerContainerPort[20];
204                 sprintf(dockerContainerPort, "%d/tcp", 830 + i);
205
206             cJSON_AddItemToObject(portBindings, dockerContainerPort, port);
207
208             cJSON *hostPort = cJSON_CreateObject();
209             if (hostPort == NULL)
210                 {
211                 printf("Could not create JSON object: HostPort\n");
212                         return NULL;
213                 }
214
215             char dockerHostPort[10];
216             sprintf(dockerHostPort, "%d", base_netconf_port + i);
217             if (cJSON_AddStringToObject(hostPort, "HostPort", dockerHostPort) == NULL)
218             {
219                 printf("Could not create JSON object: HostPortString\n");
220                 return NULL;
221             }
222             if (cJSON_AddStringToObject(hostPort, "HostIp", getenv("NTS_IP")) == NULL)
223             {
224                 printf("Could not create JSON object: HostIpString\n");
225                 return NULL;
226             }
227
228             cJSON_AddItemToArray(port, hostPort);
229     }
230
231     cJSON *labels = cJSON_CreateObject();
232     if (labels == NULL)
233         {
234         printf("Could not create JSON object: Labels\n");
235                 return NULL;
236         }
237
238     cJSON_AddItemToObject(postDataJson, "Labels", labels);
239
240     if (cJSON_AddStringToObject(labels, "NTS", "") == NULL)
241     {
242         printf("Could not create JSON object: NTS\n");
243         return NULL;
244     }
245
246     cJSON *env_variables_array = cJSON_CreateArray();
247     if (env_variables_array == NULL)
248         {
249         printf("Could not create JSON object: Env array\n");
250                 return NULL;
251         }
252
253     cJSON_AddItemToObject(postDataJson, "Env", env_variables_array);
254
255     char environment_var[50];
256     sprintf(environment_var, "NTS_IP=%s", getenv("NTS_IP"));
257
258     cJSON *env_var_obj = cJSON_CreateString(environment_var);
259     if (env_var_obj == NULL)
260         {
261         printf("Could not create JSON object: Env array object NTS_IP\n");
262                 return NULL;
263         }
264     cJSON_AddItemToArray(env_variables_array, env_var_obj);
265
266     sprintf(environment_var, "NETCONF_BASE=%d", base_netconf_port);
267     cJSON *env_var_obj_2 = cJSON_CreateString(environment_var);
268     if (env_var_obj_2 == NULL)
269         {
270         printf("Could not create JSON object: Env array object NETCONF_BASE\n");
271                 return NULL;
272         }
273     cJSON_AddItemToArray(env_variables_array, env_var_obj_2);
274
275         char scripts_dir[200];
276         sprintf(scripts_dir, "SCRIPTS_DIR=%s", getenv("SCRIPTS_DIR"));
277         cJSON *env_var_obj_3 = cJSON_CreateString(scripts_dir);
278         if (env_var_obj_3 == NULL)
279         {
280                 printf("Could not create JSON object: Env array object SCRIPTS_DIR\n");
281                 return NULL;
282         }
283         cJSON_AddItemToArray(env_variables_array, env_var_obj_3);
284
285     cJSON_AddItemToObject(hostConfig, "Binds", binds);
286
287     char *post_data_string = NULL;
288
289     post_data_string = cJSON_PrintUnformatted(postDataJson);
290
291     printf("Post data JSON:\n%s\n", post_data_string);
292
293     if (postDataJson != NULL)
294     {
295         cJSON_Delete(postDataJson);
296     }
297
298     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data_string);
299
300         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
301
302         res = curl_easy_perform(curl);
303
304         if (res != CURLE_OK)
305         {
306                 return NULL;
307         }
308         else
309         {
310                 cJSON *json_response = cJSON_Parse(curl_response_mem.memory);
311                 const cJSON *container_id = NULL;
312
313                 printf("%lu bytes retrieved\n", (unsigned long)curl_response_mem.size);
314
315                 container_id = cJSON_GetObjectItemCaseSensitive(json_response, "Id");
316
317                 if (cJSON_IsString(container_id) && (container_id->valuestring != NULL))
318                 {
319                         printf("Container id: \"%s\"\n", container_id->valuestring);
320
321                         char container_id_short[13];
322
323                         memset(container_id_short, '\0', sizeof(container_id_short));
324                         strncpy(container_id_short, container_id->valuestring, 12);
325
326                         printf("Container id short: \"%s\"\n", container_id_short);
327
328                     cJSON_Delete(json_response);
329                         return strdup(container_id_short);
330                 }
331
332             cJSON_Delete(json_response);
333         }
334
335         return NULL;
336 }
337
338 static int start_docker_container_curl(char *container_id)
339 {
340         struct MemoryStruct curl_response_mem;
341
342         curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
343         curl_response_mem.size = 0;    /* no data at this point */
344
345         CURLcode res;
346
347         curl_easy_reset(curl);
348         set_curl_common_info();
349
350         char url[100];
351         sprintf(url, "http:/v%s/containers/%s/start", getenv("DOCKER_ENGINE_VERSION"), container_id);
352
353         curl_easy_setopt(curl, CURLOPT_URL, url);
354
355     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
356
357         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
358
359         res = curl_easy_perform(curl);
360
361         if (res != CURLE_OK)
362         {
363                 return SR_ERR_OPERATION_FAILED;
364         }
365         else
366         {
367                 printf("Container %s started successfully!\n", container_id);
368         }
369
370         return SR_ERR_OK;
371 }
372
373 static int kill_and_remove_docker_container_curl(char *container_id)
374 {
375         struct MemoryStruct curl_response_mem;
376
377         curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
378         curl_response_mem.size = 0;    /* no data at this point */
379
380         CURLcode res;
381
382         curl_easy_reset(curl);
383         set_curl_common_info();
384
385         char url[100];
386         sprintf(url, "http:/v%s/containers/%s?force=true", getenv("DOCKER_ENGINE_VERSION"), container_id);
387
388         curl_easy_setopt(curl, CURLOPT_URL, url);
389
390     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
391     curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
392
393         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
394
395         res = curl_easy_perform(curl);
396
397         if (res != CURLE_OK)
398         {
399                 return SR_ERR_OPERATION_FAILED;
400         }
401         else
402         {
403                 printf("Container %s removed successfully!\n", container_id);
404         }
405
406         return SR_ERR_OK;
407 }
408
409 static int send_mount_device_instance_ssh(char *url, char *credentials, char *device_name, int device_port)
410 {
411         CURLcode res;
412
413         curl_easy_reset(curl_odl);
414         set_curl_common_info_odl();
415
416         char url_for_curl[200];
417         sprintf(url_for_curl, "%s%s_%d", url, device_name, device_port);
418
419         curl_easy_setopt(curl_odl, CURLOPT_URL, url_for_curl);
420
421         char post_data_xml[1500];
422
423         sprintf(post_data_xml,
424                         "<node xmlns=\"urn:TBD:params:xml:ns:yang:network-topology\">"
425                         "<node-id>%s_%d</node-id>"
426                         "<host xmlns=\"urn:opendaylight:netconf-node-topology\">%s</host>"
427                         "<port xmlns=\"urn:opendaylight:netconf-node-topology\">%d</port>"
428                         "<username xmlns=\"urn:opendaylight:netconf-node-topology\">%s</username>"
429                         "<password xmlns=\"urn:opendaylight:netconf-node-topology\">%s</password>"
430                         "<tcp-only xmlns=\"urn:opendaylight:netconf-node-topology\">false</tcp-only>"
431                         "<keepalive-delay xmlns=\"urn:opendaylight:netconf-node-topology\">120</keepalive-delay>"
432                         "<reconnect-on-changed-schema xmlns=\"urn:opendaylight:netconf-node-topology\">false</reconnect-on-changed-schema>"
433                         "<sleep-factor xmlns=\"urn:opendaylight:netconf-node-topology\">1.5</sleep-factor>"
434                         "<connection-timeout-millis xmlns=\"urn:opendaylight:netconf-node-topology\">20000</connection-timeout-millis>"
435                         "<max-connection-attempts xmlns=\"urn:opendaylight:netconf-node-topology\">100</max-connection-attempts>"
436                         "<between-attempts-timeout-millis xmlns=\"urn:opendaylight:netconf-node-topology\">2000</between-attempts-timeout-millis>"
437                         "</node>",
438                         device_name, device_port, getenv("NTS_IP"), device_port, "netconf", "netconf");
439
440         printf("Post data:\n%s\n", post_data_xml);
441
442         curl_easy_setopt(curl_odl, CURLOPT_POSTFIELDS, post_data_xml);
443     curl_easy_setopt(curl_odl, CURLOPT_CUSTOMREQUEST, "PUT");
444     curl_easy_setopt(curl_odl, CURLOPT_USERPWD, credentials);
445
446         res = curl_easy_perform(curl_odl);
447         if (res != CURLE_OK)
448         {
449                 printf("cURL failed to url=%s\n", url_for_curl);
450         }
451
452         long http_response_code = 0;
453         curl_easy_getinfo (curl_odl, CURLINFO_RESPONSE_CODE, &http_response_code);
454         if (http_response_code >= 200 && http_response_code <= 226 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
455         {
456                 printf("cURL succeeded to url=%s\n", url_for_curl);
457         }
458         else
459         {
460             printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
461                 return SR_ERR_OPERATION_FAILED;
462         }
463
464         return SR_ERR_OK;
465 }
466
467 static int send_mount_device_instance_tls(char *url, char *credentials, char *device_name, int device_port)
468 {
469         CURLcode res;
470
471         curl_easy_reset(curl_odl);
472         set_curl_common_info_odl();
473
474         char url_for_curl[200];
475         sprintf(url_for_curl, "%s%s_%d", url, device_name, device_port);
476
477         curl_easy_setopt(curl_odl, CURLOPT_URL, url_for_curl);
478
479         char post_data_xml[1500];
480
481         sprintf(post_data_xml,
482                         "<node xmlns=\"urn:TBD:params:xml:ns:yang:network-topology\">"
483                         "<protocol xmlns=\"urn:opendaylight:netconf-node-topology\">"
484                         "<name>TLS</name>"
485                         "</protocol>"
486                         "<node-id>%s_%d</node-id>"
487                         "<host xmlns=\"urn:opendaylight:netconf-node-topology\">%s</host>"
488                         "<key-based xmlns=\"urn:opendaylight:netconf-node-topology\">"
489                         "<username>%s</username>"
490                         "<key-id>device-key</key-id>"
491                         "</key-based>"
492                         "<port xmlns=\"urn:opendaylight:netconf-node-topology\">%d</port>"
493                         "<tcp-only xmlns=\"urn:opendaylight:netconf-node-topology\">false</tcp-only>"
494                         "<keepalive-delay xmlns=\"urn:opendaylight:netconf-node-topology\">120</keepalive-delay>"
495                         "<reconnect-on-changed-schema xmlns=\"urn:opendaylight:netconf-node-topology\">false</reconnect-on-changed-schema>"
496                         "<sleep-factor xmlns=\"urn:opendaylight:netconf-node-topology\">1.5</sleep-factor>"
497                         "<connection-timeout-millis xmlns=\"urn:opendaylight:netconf-node-topology\">20000</connection-timeout-millis>"
498                         "<max-connection-attempts xmlns=\"urn:opendaylight:netconf-node-topology\">100</max-connection-attempts>"
499                         "<between-attempts-timeout-millis xmlns=\"urn:opendaylight:netconf-node-topology\">2000</between-attempts-timeout-millis>"
500                         "</node>",
501                         device_name, device_port, getenv("NTS_IP"), "netconf", device_port);
502
503         printf("Post data:\n%s\n", post_data_xml);
504
505         curl_easy_setopt(curl_odl, CURLOPT_POSTFIELDS, post_data_xml);
506     curl_easy_setopt(curl_odl, CURLOPT_CUSTOMREQUEST, "PUT");
507     curl_easy_setopt(curl_odl, CURLOPT_USERPWD, credentials);
508
509         res = curl_easy_perform(curl_odl);
510         if (res != CURLE_OK)
511         {
512                 printf("cURL failed to url=%s\n", url_for_curl);
513         }
514
515         long http_response_code = 0;
516         curl_easy_getinfo (curl_odl, CURLINFO_RESPONSE_CODE, &http_response_code);
517         if (http_response_code >= 200 && http_response_code <= 226 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
518         {
519                 printf("cURL succeeded to url=%s\n", url_for_curl);
520         }
521         else
522         {
523             printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
524                 return SR_ERR_OPERATION_FAILED;
525         }
526
527         return SR_ERR_OK;
528 }
529
530 static int send_unmount_device_instance(char *url, char *credentials, char *device_name, int device_port)
531 {
532         CURLcode res;
533
534         curl_easy_reset(curl_odl);
535         set_curl_common_info_odl();
536
537         char url_for_curl[200];
538         sprintf(url_for_curl, "%s%s_%d", url, device_name, device_port);
539
540         curl_easy_setopt(curl_odl, CURLOPT_URL, url_for_curl);
541
542         curl_easy_setopt(curl_odl, CURLOPT_POSTFIELDS, "");
543         curl_easy_setopt(curl_odl, CURLOPT_CUSTOMREQUEST, "DELETE");
544         curl_easy_setopt(curl_odl, CURLOPT_USERPWD, credentials);
545
546         res = curl_easy_perform(curl_odl);
547         if (res != CURLE_OK)
548         {
549                 printf("cURL failed to url=%s\n", url_for_curl);
550         }
551
552         long http_response_code = 0;
553         curl_easy_getinfo (curl_odl, CURLINFO_RESPONSE_CODE, &http_response_code);
554         if (http_response_code == 200 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
555         {
556                 printf("cURL succeeded to url=%s\n", url_for_curl);
557         }
558         else
559         {
560                 printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
561                 return SR_ERR_OPERATION_FAILED;
562         }
563
564
565         return SR_ERR_OK;
566 }
567
568
569 static int send_mount_device(device_t *current_device, controller_t controller_details)
570 {
571         int rc = SR_ERR_OK;
572         bool is_mounted = true;
573
574         //This is where we hardcoded: 7 devices will have SSH connections and 3 devices will have TLS connections
575         for (int port = 0; port < NETCONF_CONNECTIONS_PER_DEVICE - 3; ++port)
576         {
577                 rc = send_mount_device_instance_ssh(controller_details.url, controller_details.credentials,
578                                 current_device->device_id, current_device->netconf_port + port);
579                 if (rc != SR_ERR_OK)
580                 {
581                         is_mounted = false;
582                 }
583         }
584         for (int port = NETCONF_CONNECTIONS_PER_DEVICE - 3; port < NETCONF_CONNECTIONS_PER_DEVICE; ++port)
585         {
586                 rc = send_mount_device_instance_tls(controller_details.url, controller_details.credentials,
587                                 current_device->device_id, current_device->netconf_port + port);
588                 if (rc != SR_ERR_OK)
589                 {
590                         is_mounted = false;
591                 }
592         }
593
594         current_device->is_mounted = is_mounted;
595
596         return SR_ERR_OK;
597 }
598
599 static int send_unmount_device(device_t *current_device, controller_t controller_details)
600 {
601         int rc = SR_ERR_OK;
602
603         for (int port = 0; port < NETCONF_CONNECTIONS_PER_DEVICE; ++port)
604         {
605                 rc = send_unmount_device_instance(controller_details.url, controller_details.credentials,
606                                 current_device->device_id, current_device->netconf_port + port);
607                 if (rc != SR_ERR_OK)
608                 {
609                         printf("Could not send unmount for ODL with url=\"%s\", for device=\"%s\" and port=%d\n",
610                                         controller_details.url, current_device->device_id, current_device->netconf_port);
611                 }
612         }
613         current_device->is_mounted = false;
614
615         return SR_ERR_OK;
616 }
617
618 device_stack_t *new_device_stack(void)
619 {
620         device_stack_t *stack = malloc(sizeof(*stack));
621
622         if (stack) {
623                 stack->head = NULL;
624                 stack->stack_size = 0;
625         }
626         return stack;
627 }
628
629 void push_device(device_stack_t *theStack, char *dev_id, int port)
630 {
631         device_t *new_dev = malloc(sizeof(*new_dev));
632
633         if (new_dev) {
634                 new_dev->device_id = strdup(dev_id);
635                 new_dev->netconf_port = port;
636                 new_dev->is_mounted = false;
637                 new_dev->operational_state = strdup("not-specified");
638
639                 new_dev->next = theStack->head;
640
641                 theStack->head = new_dev;
642                 theStack->stack_size++;
643         }
644 }
645
646 void pop_device(device_stack_t *theStack)
647 {
648         if (theStack && theStack->head) {
649                 device_t *temp = theStack->head;
650                 theStack->head = theStack->head->next;
651
652                 free(temp->device_id);
653                 free(temp->operational_state);
654                 free(temp);
655                 theStack->stack_size--;
656         }
657 }
658
659 int get_netconf_port_next(device_stack_t *theStack)
660 {
661         if (theStack && theStack->stack_size > 0) {
662                 return theStack->head->netconf_port + NETCONF_CONNECTIONS_PER_DEVICE;
663         }
664
665         return get_netconf_port_base();
666 }
667
668 int get_netconf_port_base()
669 {
670         int netconf_port_base = 0, rc;
671
672         char *netconf_base_string = getenv("NETCONF_BASE");
673
674         if (netconf_base_string != NULL)
675         {
676                 rc = sscanf(netconf_base_string, "%d", &netconf_port_base);
677                 if (rc != 1)
678                 {
679                         printf("Could not get the NETCONF_BASE port! Using the default 30.000...\n");
680                         netconf_port_base = 30000;
681                 }
682         }
683
684         return netconf_port_base;
685 }
686
687
688 char *get_id_last_device(device_stack_t *theStack)
689 {
690         if (theStack && theStack->head) {
691                 return theStack->head->device_id;
692         }
693         return NULL;
694 }
695
696 int get_current_number_of_mounted_devices(device_stack_t *theStack)
697 {
698         int mounted_devices = 0;
699
700         if (theStack && theStack->head)
701         {
702                 device_t *current_device = theStack->head;
703
704                 while (current_device != NULL)
705                 {
706                         if (current_device->is_mounted)
707                         {
708                                 mounted_devices++;
709                         }
710                         current_device = current_device->next;
711                 }
712         }
713
714         return mounted_devices;
715 }
716
717 int get_current_number_of_devices(device_stack_t *theStack)
718 {
719         struct MemoryStruct curl_response_mem;
720
721         curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
722         curl_response_mem.size = 0;    /* no data at this point */
723
724         CURLcode res;
725
726         curl_easy_reset(curl);
727         set_curl_common_info();
728
729         char url[100];
730         sprintf(url, "http:/v%s/containers/json?all=true&filters={\"label\":[\"NTS\"],\"status\":[\"running\"]}",
731                         getenv("DOCKER_ENGINE_VERSION"));
732
733         curl_easy_setopt(curl, CURLOPT_URL, url);
734
735         curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
736         curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
737
738         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
739
740         res = curl_easy_perform(curl);
741
742         if (res != CURLE_OK)
743         {
744                 return SR_ERR_OPERATION_FAILED;
745         }
746         else
747         {
748                 cJSON *json_response = cJSON_Parse(curl_response_mem.memory);
749
750                 printf("%lu bytes retrieved\n", (unsigned long)curl_response_mem.size);
751
752                 if (json_response == NULL || !cJSON_IsArray(json_response))
753                 {
754                         printf("Could not parse JSON response for url=\"%s\"\n", url);
755                         return SR_ERR_OPERATION_FAILED;
756                 }
757
758                 int num_of_devices = cJSON_GetArraySize(json_response);
759                 cJSON_Delete(json_response);
760
761                 return num_of_devices;
762         }
763
764         return 0;
765 }
766
767 static int set_operational_state_of_device(device_stack_t *theStack, char *device_id, char *operational_state)
768 {
769         if (theStack && theStack->head)
770         {
771                 device_t *current_device = theStack->head;
772
773                 while (current_device != NULL)
774                 {
775                         if (strcmp(current_device->device_id, device_id) == 0)
776                         {
777                                 free(current_device->operational_state);
778                                 current_device->operational_state = strdup(operational_state);
779
780                                 return SR_ERR_OK;
781                         }
782
783                         current_device = current_device->next;
784                 }
785         }
786
787         printf("Could not find device with uuid=\"%s\"\n", device_id);
788         return SR_ERR_OPERATION_FAILED;
789 }
790
791 char* get_docker_container_operational_state(device_stack_t *theStack, char *container_id)
792 {
793         if (theStack && theStack->head)
794         {
795                 device_t *current_device = theStack->head;
796
797                 while (current_device != NULL)
798                 {
799                         if (strcmp(current_device->device_id, container_id) == 0)
800                         {
801                                 return current_device->operational_state;
802                         }
803
804                         current_device = current_device->next;
805                 }
806         }
807
808         return NULL;
809 }
810
811 int start_device(device_stack_t *theStack)
812 {
813         int rc = SR_ERR_OK;
814         static cJSON* managerBindings = NULL;
815
816         if (managerBindings == NULL)
817         {
818                 managerBindings = get_docker_container_bindings();
819         }
820
821         int netconf_base = get_netconf_port_next(theStack);
822
823         char *dev_id = create_docker_container_curl(netconf_base, managerBindings);
824
825         push_device(theStack, dev_id, netconf_base);
826
827         rc = start_docker_container_curl(dev_id);
828         if (rc != SR_ERR_OK)
829         {
830                 printf("Could not start device with device_id=\"%s\"\n", dev_id);
831         }
832
833         if (dev_id) {
834                 free(dev_id);
835         }
836
837         return SR_ERR_OK;
838 }
839
840 int _init_curl()
841 {
842         curl = curl_easy_init();
843
844         if (curl == NULL) {
845                 printf("cURL initialization error! Aborting call!\n");
846                 return SR_ERR_OPERATION_FAILED;
847         }
848
849         return SR_ERR_OK;
850 }
851
852 int cleanup_curl()
853 {
854         if (curl != NULL)
855         {
856                 curl_easy_cleanup(curl);
857         }
858
859         return SR_ERR_OK;
860 }
861
862 int _init_curl_odl()
863 {
864         curl_odl = curl_easy_init();
865
866         if (curl_odl == NULL) {
867                 printf("cURL initialization error! Aborting call!\n");
868                 return SR_ERR_OPERATION_FAILED;
869         }
870
871         return SR_ERR_OK;
872 }
873
874 int cleanup_curl_odl()
875 {
876         if (curl_odl != NULL)
877         {
878                 curl_easy_cleanup(curl_odl);
879         }
880
881         return SR_ERR_OK;
882 }
883
884 int stop_device(device_stack_t *theStack)
885 {
886         int rc = SR_ERR_OK;
887         char *last_id = get_id_last_device(theStack);
888
889         rc = kill_and_remove_docker_container_curl(last_id);
890         if (rc != SR_ERR_OK)
891         {
892                 printf("Could not kill and remove docker container with uuid=\"%s\"\n", last_id);
893         }
894
895         pop_device(theStack);
896
897         return SR_ERR_OK;
898 }
899
900 int mount_device(device_stack_t *theStack, controller_t controller_details)
901 {
902         int rc;
903
904         if (theStack && theStack->head)
905         {
906                 device_t *current_device = theStack->head;
907                 while (current_device != NULL && current_device->is_mounted == true)
908                 {
909                         printf("Device \"%s\" is already mounted, skipping...\n", current_device->device_id);
910                         current_device = current_device->next;
911                 }
912
913                 if (current_device != NULL)
914                 {
915                         printf("Sending mount device for device \"%s\"...\n", current_device->device_id);
916                         rc = send_mount_device(current_device, controller_details);
917                         if (rc != SR_ERR_OK)
918                         {
919                                 return SR_ERR_OPERATION_FAILED;
920                         }
921                 }
922         }
923
924         return SR_ERR_OK;
925 }
926
927 int unmount_device(device_stack_t *theStack, controller_t controller_list)
928 {
929         int rc;
930
931         if (theStack && theStack->head)
932         {
933                 device_t *current_device = theStack->head;
934                 while (current_device != NULL && current_device->is_mounted == false)
935                 {
936                         printf("Device \"%s\" is already unmounted, skipping...\n", current_device->device_id);
937                         current_device = current_device->next;
938                 }
939
940                 if (current_device != NULL)
941                 {
942                         printf("Sending unmount device for device \"%s\"...\n", current_device->device_id);
943                         rc = send_unmount_device(current_device, controller_list);
944                         if (rc != SR_ERR_OK)
945                         {
946                                 return SR_ERR_OPERATION_FAILED;
947                         }
948                 }
949         }
950
951         return SR_ERR_OK;
952 }
953
954 int get_docker_containers_operational_state_curl(device_stack_t *theStack)
955 {
956         int rc = SR_ERR_OK;
957         struct MemoryStruct curl_response_mem;
958
959         curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
960         curl_response_mem.size = 0;    /* no data at this point */
961
962         CURLcode res;
963
964         curl_easy_reset(curl);
965         set_curl_common_info();
966
967         char url[100];
968         sprintf(url, "http:/v%s/containers/json?all=true&filters={\"label\":[\"NTS\"]}", getenv("DOCKER_ENGINE_VERSION"));
969
970         curl_easy_setopt(curl, CURLOPT_URL, url);
971
972     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
973     curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
974
975         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
976
977         res = curl_easy_perform(curl);
978
979         if (res != CURLE_OK)
980         {
981                 return SR_ERR_OPERATION_FAILED;
982         }
983         else
984         {
985                 cJSON *json_response = cJSON_Parse(curl_response_mem.memory);
986                 const cJSON *container = NULL;
987
988                 printf("%lu bytes retrieved\n", (unsigned long)curl_response_mem.size);
989
990                 if (json_response == NULL || !cJSON_IsArray(json_response))
991                 {
992                         printf("Could not parse JSON response for url=\"%s\"\n", url);
993                         return SR_ERR_OPERATION_FAILED;
994                 }
995
996             cJSON_ArrayForEach(container, json_response)
997             {
998                 cJSON *container_id_long = cJSON_GetObjectItemCaseSensitive(container, "Id");
999                 cJSON *state = cJSON_GetObjectItemCaseSensitive(container, "State");
1000
1001                         if (cJSON_IsString(container_id_long) && (container_id_long->valuestring != NULL))
1002                         {
1003                                 char container_id_short[13];
1004
1005                                 memset(container_id_short, '\0', sizeof(container_id_short));
1006                                 strncpy(container_id_short, container_id_long->valuestring, 12);
1007
1008                                 if (cJSON_IsString(state) && (state->valuestring != NULL))
1009                                 {
1010                                         rc = set_operational_state_of_device(theStack, container_id_short, state->valuestring);
1011                                         if (rc != SR_ERR_OK)
1012                                         {
1013                                                 printf("Could not set the operational state for the device with uuid=\"%s\"\n", container_id_short);
1014                                         }
1015                                 }
1016                         }
1017             }
1018
1019             cJSON_Delete(json_response);
1020         }
1021
1022         return SR_ERR_OK;
1023 }
1024
1025 char* get_docker_container_resource_stats(device_stack_t *theStack)
1026 {
1027         char line[LINE_BUFSIZE];
1028         int linenr;
1029         FILE *pipe;
1030
1031         /* Get a pipe where the output from the scripts comes in */
1032         char script[200];
1033         sprintf(script, "%s/docker_stats.sh", getenv("SCRIPTS_DIR"));
1034
1035         pipe = popen(script, "r");
1036         if (pipe == NULL) {  /* check for errors */
1037                 printf("Could not open script.\n");
1038                 return NULL;        /* return with exit code indicating error */
1039         }
1040
1041         /* Read script output from the pipe line by line */
1042         linenr = 1;
1043         while (fgets(line, LINE_BUFSIZE, pipe) != NULL) {
1044                 printf("Script output line %d: %s", linenr, line);
1045                 ++linenr;
1046
1047                 pclose(pipe); /* Close the pipe */
1048                 return strdup(line);
1049         }
1050
1051         /* Once here, out of the loop, the script has ended. */
1052         pclose(pipe); /* Close the pipe */
1053         return NULL;     /* return with exit code indicating success. */
1054 }
1055
1056 int notification_delay_period_changed(int period)
1057 {
1058         char *stringConfiguration = readConfigFileInString();
1059
1060         if (stringConfiguration == NULL)
1061         {
1062                 printf("Could not read configuration file!\n");
1063                 return SR_ERR_OPERATION_FAILED;
1064         }
1065
1066         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1067         if (jsonConfig == NULL)
1068         {
1069                 free(stringConfiguration);
1070                 const char *error_ptr = cJSON_GetErrorPtr();
1071                 if (error_ptr != NULL)
1072                 {
1073                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
1074                 }
1075                 return SR_ERR_OPERATION_FAILED;
1076         }
1077         //we don't need the string anymore
1078         free(stringConfiguration);
1079         stringConfiguration = NULL;
1080
1081         cJSON *notifConfig = cJSON_GetObjectItemCaseSensitive(jsonConfig, "notification-config");
1082         if (!cJSON_IsObject(notifConfig))
1083         {
1084                 printf("Configuration JSON is not as expected: notification-config is not an object");
1085                 free(jsonConfig);
1086                 return SR_ERR_OPERATION_FAILED;
1087         }
1088
1089         cJSON *faultNotifDelay = cJSON_GetObjectItemCaseSensitive(notifConfig, "fault-notification-delay-period");
1090         if (!cJSON_IsNumber(faultNotifDelay))
1091         {
1092                 printf("Configuration JSON is not as expected: fault-notification-delay-period is not an object");
1093                 free(jsonConfig);
1094                 return SR_ERR_OPERATION_FAILED;
1095         }
1096
1097         //we set the value of the fault-notification-delay-period object
1098         cJSON_SetNumberValue(faultNotifDelay, period);
1099
1100         //writing the new JSON to the configuration file
1101         stringConfiguration = cJSON_Print(jsonConfig);
1102         writeConfigFile(stringConfiguration);
1103
1104         free(jsonConfig);
1105
1106         return SR_ERR_OK;
1107 }
1108
1109 int ves_heartbeat_period_changed(int period)
1110 {
1111         char *stringConfiguration = readConfigFileInString();
1112
1113         if (stringConfiguration == NULL)
1114         {
1115                 printf("Could not read configuration file!\n");
1116                 return SR_ERR_OPERATION_FAILED;
1117         }
1118
1119         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1120         if (jsonConfig == NULL)
1121         {
1122                 free(stringConfiguration);
1123                 const char *error_ptr = cJSON_GetErrorPtr();
1124                 if (error_ptr != NULL)
1125                 {
1126                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
1127                 }
1128                 return SR_ERR_OPERATION_FAILED;
1129         }
1130         //we don't need the string anymore
1131         free(stringConfiguration);
1132         stringConfiguration = NULL;
1133
1134         cJSON *notifConfig = cJSON_GetObjectItemCaseSensitive(jsonConfig, "notification-config");
1135         if (!cJSON_IsObject(notifConfig))
1136         {
1137                 printf("Configuration JSON is not as expected: notification-config is not an object");
1138                 free(jsonConfig);
1139                 return SR_ERR_OPERATION_FAILED;
1140         }
1141
1142         cJSON *vesHeartbeatPeriod = cJSON_GetObjectItemCaseSensitive(notifConfig, "ves-heartbeat-period");
1143         if (!cJSON_IsNumber(vesHeartbeatPeriod))
1144         {
1145                 printf("Configuration JSON is not as expected: ves-heartbeat-period is not an object");
1146                 free(jsonConfig);
1147                 return SR_ERR_OPERATION_FAILED;
1148         }
1149
1150         //we set the value of the fault-notification-delay-period object
1151         cJSON_SetNumberValue(vesHeartbeatPeriod, period);
1152
1153         //writing the new JSON to the configuration file
1154         stringConfiguration = cJSON_Print(jsonConfig);
1155         writeConfigFile(stringConfiguration);
1156
1157         free(jsonConfig);
1158
1159         return SR_ERR_OK;
1160 }
1161
1162 static int add_keystore_entry_odl(char *url, char *credentials)
1163 {
1164         CURLcode res;
1165
1166         curl_easy_reset(curl_odl);
1167         set_curl_common_info_odl();
1168
1169         char url_for_curl[200];
1170         sprintf(url_for_curl, "%s", url);
1171
1172         curl_easy_setopt(curl_odl, CURLOPT_URL, url_for_curl);
1173
1174         char post_data_xml[2000];
1175
1176         sprintf(post_data_xml,
1177                         "<input xmlns=\"urn:opendaylight:netconf:keystore\">"
1178                         "<key-credential>"
1179                         "<key-id>device-key</key-id>"
1180                         "<private-key>MIIEpAIBAAKCAQEAueCQaNQWoNmFK6LKu1p8U8ZWdWg/PvDdLsJyzfzl/Qw4UA68"
1181                         "SfFNaY06zZl8QB9W02nr5kWeeMY0VA3adrPgOlvfx3oWlFbkETnMaN4OT3WTQ0Wt"
1182                         "6jAWZDzVfopwpJPAzRPxACDftIqFGagYcF32hZlVNqqnVdbXh0S0EViweqp/dbG4"
1183                         "VDUHSNVbglc+u4UbEzNIFXMdEFsJZpkynOmSiTsIATqIhb+2srkVgLwhfkC2qkuH"
1184                         "QwAHdubuB07ObM2z01UhyEdDvEYGHwtYAGDBL2TAcsI0oGeVkRyuOkV0QY0UN7UE"
1185                         "FI1yTYw+xZ42HgFx3uGwApCImxhbj69GBYWFqwIDAQABAoIBAQCZN9kR8DGu6V7y"
1186                         "t0Ax68asL8O5B/OKaHWKQ9LqpVrXmikZJOxkbzoGldow/CIFoU+q+Zbwu9aDa65a"
1187                         "0wiP7Hoa4Py3q5XNNUrOQDyU/OYC7cI0I83WS0lJ2zOJGYj8wKae5Z81IeQFKGHK"
1188                         "4lsy1OGPAvPRGh7RjUUgRavA2MCwe07rWRuDb/OJFe4Oh56UMEjwMiNBtMNtncog"
1189                         "j1vr/qgRJdf9tf0zlJmLvUJ9+HSFFV9I/97LJyFhb95gAfHkjdVroLVgT3Cho+4P"
1190                         "WtZaKCIGD0OwfOG2nLV4leXvRUk62/LMlB8NI9+JF7Xm+HCKbaWHNWC7mvWSLV58"
1191                         "Zl4AbUWRAoGBANyJ6SFHFRHSPDY026SsdMzXR0eUxBAK7G70oSBKKhY+O1j0ocLE"
1192                         "jI2krHJBhHbLlnvJVyMUaCUOTS5m0uDw9hgSsAqeSL3hL38kxVZw+KNG9Ouno1Fl"
1193                         "KnE/xXHlPQyeGs/P8nAMzHZxQtEsQdQayJEhK2XXHTsy7Q3MxDisfVJ1AoGBANfD"
1194                         "34gB+OMx6pwj7zk3qWbYXSX8xjCZMR0ciko+h4xeMP2N8B0oyoqC+v1ABMAtJ3wG"
1195                         "sGZd0hV9gwM7OUM3SEwkn6oeg1GemWLcn4rlSmTnZc4aeVwrEWlnSNFX3s4g9l4u"
1196                         "k8Ugu4MVJYqH8HuDQ5Ggl6/QAwPzMSEdCW0O+jOfAoGAIBRbegC5+t6m7Yegz4Ja"
1197                         "dxV1g98K6f58x+MDsQu4tYWV4mmrQgaPH2dtwizvlMwmdpkh+LNWNtWuumowkJHc"
1198                         "akIFo3XExQIFg6wYnGtQb4e5xrGa2xMpKlIJaXjb+YLiCYqJDG2ALFZrTrvuU2kV"
1199                         "9a5qfqTc1qigvNolTM0iaaUCgYApmrZWhnLUdEKV2wP813PNxfioI4afxlpHD8LG"
1200                         "sCn48gymR6E+Lihn7vuwq5B+8fYEH1ISWxLwW+RQUjIneNhy/jjfV8TgjyFqg7or"
1201                         "0Sy4KjpiNI6kLBXOakELRNNMkeSPopGR2E7v5rr3bGD9oAD+aqX1G7oJH/KgPPYd"
1202                         "Vl7+ZwKBgQDcHyWYrimjyUgKaQD2GmoO9wdcJYQ59ke9K+OuGlp4ti5arsi7N1tP"
1203                         "B4f09aeELM2ASIuk8Q/Mx0jQFnm8lzRFXdewgvdPoZW/7VufM9O7dGPOc41cm2Dh"
1204                         "yrTcXx/VmUBb+/fnXVEgCv7gylp/wtdTGHQBQJHR81jFBz0lnLj+gg==</private-key>"
1205                         "<passphrase></passphrase>"
1206                         "</key-credential>"
1207                         "</input>");
1208
1209         printf("Post data:\n%s\n", post_data_xml);
1210
1211         curl_easy_setopt(curl_odl, CURLOPT_POSTFIELDS, post_data_xml);
1212         curl_easy_setopt(curl_odl, CURLOPT_CUSTOMREQUEST, "POST");
1213         curl_easy_setopt(curl_odl, CURLOPT_USERPWD, credentials);
1214
1215         res = curl_easy_perform(curl_odl);
1216         if (res != CURLE_OK)
1217         {
1218                 printf("cURL failed to url=%s\n", url_for_curl);
1219         }
1220
1221         long http_response_code = 0;
1222         curl_easy_getinfo (curl_odl, CURLINFO_RESPONSE_CODE, &http_response_code);
1223         if (http_response_code >= 200 && http_response_code <= 226 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
1224         {
1225                 printf("cURL succeeded to url=%s\n", url_for_curl);
1226         }
1227         else
1228         {
1229                 printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
1230                 return SR_ERR_OPERATION_FAILED;
1231         }
1232
1233         return SR_ERR_OK;
1234 }
1235
1236 static int add_private_key_odl(char *url, char *credentials)
1237 {
1238         CURLcode res;
1239
1240         curl_easy_reset(curl_odl);
1241         set_curl_common_info_odl();
1242
1243         char url_for_curl[200];
1244         sprintf(url_for_curl, "%s", url);
1245
1246         curl_easy_setopt(curl_odl, CURLOPT_URL, url_for_curl);
1247
1248         char post_data_xml[4000];
1249
1250         sprintf(post_data_xml,
1251                         "<input xmlns=\"urn:opendaylight:netconf:keystore\">"
1252                         "<private-key>"
1253                         "<name>device-key</name>"
1254                         "<data>MIIEpAIBAAKCAQEAueCQaNQWoNmFK6LKu1p8U8ZWdWg/PvDdLsJyzfzl/Qw4UA68SfFNaY06zZl8QB9W02nr5kWeeMY0VA3adrPgOlvfx3oWlFbkETnMaN4OT3WTQ0Wt6jAWZDzVfopwpJPAzRPxACDftIqFGagYcF32hZlVNqqnVdbXh0S0EViweqp/dbG4VDUHSNVbglc+u4UbEzNIFXMdEFsJZpkynOmSiTsIATqIhb+2srkVgLwhfkC2qkuHQwAHdubuB07ObM2z01UhyEdDvEYGHwtYAGDBL2TAcsI0oGeVkRyuOkV0QY0UN7UEFI1yTYw+xZ42HgFx3uGwApCImxhbj69GBYWFqwIDAQABAoIBAQCZN9kR8DGu6V7yt0Ax68asL8O5B/OKaHWKQ9LqpVrXmikZJOxkbzoGldow/CIFoU+q+Zbwu9aDa65a0wiP7Hoa4Py3q5XNNUrOQDyU/OYC7cI0I83WS0lJ2zOJGYj8wKae5Z81IeQFKGHK4lsy1OGPAvPRGh7RjUUgRavA2MCwe07rWRuDb/OJFe4Oh56UMEjwMiNBtMNtncogj1vr/qgRJdf9tf0zlJmLvUJ9+HSFFV9I/97LJyFhb95gAfHkjdVroLVgT3Cho+4PWtZaKCIGD0OwfOG2nLV4leXvRUk62/LMlB8NI9+JF7Xm+HCKbaWHNWC7mvWSLV58Zl4AbUWRAoGBANyJ6SFHFRHSPDY026SsdMzXR0eUxBAK7G70oSBKKhY+O1j0ocLEjI2krHJBhHbLlnvJVyMUaCUOTS5m0uDw9hgSsAqeSL3hL38kxVZw+KNG9Ouno1FlKnE/xXHlPQyeGs/P8nAMzHZxQtEsQdQayJEhK2XXHTsy7Q3MxDisfVJ1AoGBANfD34gB+OMx6pwj7zk3qWbYXSX8xjCZMR0ciko+h4xeMP2N8B0oyoqC+v1ABMAtJ3wGsGZd0hV9gwM7OUM3SEwkn6oeg1GemWLcn4rlSmTnZc4aeVwrEWlnSNFX3s4g9l4uk8Ugu4MVJYqH8HuDQ5Ggl6/QAwPzMSEdCW0O+jOfAoGAIBRbegC5+t6m7Yegz4JadxV1g98K6f58x+MDsQu4tYWV4mmrQgaPH2dtwizvlMwmdpkh+LNWNtWuumowkJHcakIFo3XExQIFg6wYnGtQb4e5xrGa2xMpKlIJaXjb+YLiCYqJDG2ALFZrTrvuU2kV9a5qfqTc1qigvNolTM0iaaUCgYApmrZWhnLUdEKV2wP813PNxfioI4afxlpHD8LGsCn48gymR6E+Lihn7vuwq5B+8fYEH1ISWxLwW+RQUjIneNhy/jjfV8TgjyFqg7or0Sy4KjpiNI6kLBXOakELRNNMkeSPopGR2E7v5rr3bGD9oAD+aqX1G7oJH/KgPPYdVl7+ZwKBgQDcHyWYrimjyUgKaQD2GmoO9wdcJYQ59ke9K+OuGlp4ti5arsi7N1tPB4f09aeELM2ASIuk8Q/Mx0jQFnm8lzRFXdewgvdPoZW/7VufM9O7dGPOc41cm2DhyrTcXx/VmUBb+/fnXVEgCv7gylp/wtdTGHQBQJHR81jFBz0lnLj+gg==</data>"
1255                         "<certificate-chain>MIIECTCCAvGgAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBjDELMAkGA1UEBhMCQ1oxFjAUBgNVBAgMDVNvdXRoIE1vcmF2aWExDTALBgNVBAcMBEJybm8xDzANBgNVBAoMBkNFU05FVDEMMAoGA1UECwwDVE1DMRMwEQYDVQQDDApleGFtcGxlIENBMSIwIAYJKoZIhvcNAQkBFhNleGFtcGxlY2FAbG9jYWxob3N0MB4XDTE1MDczMDA3MjcxOFoXDTM1MDcyNTA3MjcxOFowgYUxCzAJBgNVBAYTAkNaMRYwFAYDVQQIDA1Tb3V0aCBNb3JhdmlhMQ8wDQYDVQQKDAZDRVNORVQxDDAKBgNVBAsMA1RNQzEXMBUGA1UEAwwOZXhhbXBsZSBjbGllbnQxJjAkBgkqhkiG9w0BCQEWF2V4YW1wbGVjbGllbnRAbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAueCQaNQWoNmFK6LKu1p8U8ZWdWg/PvDdLsJyzfzl/Qw4UA68SfFNaY06zZl8QB9W02nr5kWeeMY0VA3adrPgOlvfx3oWlFbkETnMaN4OT3WTQ0Wt6jAWZDzVfopwpJPAzRPxACDftIqFGagYcF32hZlVNqqnVdbXh0S0EViweqp/dbG4VDUHSNVbglc+u4UbEzNIFXMdEFsJZpkynOmSiTsIATqIhb+2srkVgLwhfkC2qkuHQwAHdubuB07ObM2z01UhyEdDvEYGHwtYAGDBL2TAcsI0oGeVkRyuOkV0QY0UN7UEFI1yTYw+xZ42HgFx3uGwApCImxhbj69GBYWFqwIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUXGpLeLnh2cSDARAVA7KrBxGYpo8wHwYDVR0jBBgwFoAUc1YQIqjZsHVwlea0AB4N+ilNI2gwDQYJKoZIhvcNAQELBQADggEBAJPV3RTXFRtNyOU4rjPpYeBAIAFp2aqGc4t2J1c7oPp/1n+lZvjnwtlJpZHxMM783e2ryDQ6dkvXDf8kpwKlg3U3mkJ3xKkDdWrM4QwghXdCN519aa9qmu0zdFL+jUAaWlQ5tsceOrvbusCcbMqiFGk/QfpHqPv52SVWbYyUx7IX7DE+UjgsLHycfV/tlcx4ZE6soTzl9VdgSL/zmzG3rjsr58J80rXckLgBhvijgBlIAJvWfC7D0vaouvBInSFXymdPVoUDZ30cdGLf+hI/i/TfsEMOinLrXVdkSGNo6FXAHKSvXeB9oFKSzhQ7OPyRyqvEPycUSw/qD6FVr80oDDc=</certificate-chain>"
1256                         "</private-key>"
1257                         "</input>");
1258
1259         printf("Post data:\n%s\n", post_data_xml);
1260
1261         curl_easy_setopt(curl_odl, CURLOPT_POSTFIELDS, post_data_xml);
1262         curl_easy_setopt(curl_odl, CURLOPT_CUSTOMREQUEST, "POST");
1263         curl_easy_setopt(curl_odl, CURLOPT_USERPWD, credentials);
1264
1265         res = curl_easy_perform(curl_odl);
1266         if (res != CURLE_OK)
1267         {
1268                 printf("cURL failed to url=%s\n", url_for_curl);
1269         }
1270
1271         long http_response_code = 0;
1272         curl_easy_getinfo (curl_odl, CURLINFO_RESPONSE_CODE, &http_response_code);
1273         if (http_response_code >= 200 && http_response_code <= 226 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
1274         {
1275                 printf("cURL succeeded to url=%s\n", url_for_curl);
1276         }
1277         else
1278         {
1279                 printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
1280                 return SR_ERR_OPERATION_FAILED;
1281         }
1282
1283         return SR_ERR_OK;
1284 }
1285
1286 static int add_trusted_ca_odl(char *url, char *credentials)
1287 {
1288         CURLcode res;
1289
1290         curl_easy_reset(curl_odl);
1291         set_curl_common_info_odl();
1292
1293         char url_for_curl[200];
1294         sprintf(url_for_curl, "%s", url);
1295
1296         curl_easy_setopt(curl_odl, CURLOPT_URL, url_for_curl);
1297
1298         char post_data_xml[2000];
1299
1300         sprintf(post_data_xml,
1301                         "<input xmlns=\"urn:opendaylight:netconf:keystore\">"
1302                         "<trusted-certificate>"
1303                         "<name>test_trusted_cert</name>"
1304                         "<certificate>MIID7TCCAtWgAwIBAgIJAMtE1NGAR5KoMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJDWjEWMBQGA1UECAwNU291dGggTW9yYXZpYTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwGQ0VTTkVUMQwwCgYDVQQLDANUTUMxEzARBgNVBAMMCmV4YW1wbGUgQ0ExIjAgBgkqhkiG9w0BCQEWE2V4YW1wbGVjYUBsb2NhbGhvc3QwHhcNMTQwNzI0MTQxOTAyWhcNMjQwNzIxMTQxOTAyWjCBjDELMAkGA1UEBhMCQ1oxFjAUBgNVBAgMDVNvdXRoIE1vcmF2aWExDTALBgNVBAcMBEJybm8xDzANBgNVBAoMBkNFU05FVDEMMAoGA1UECwwDVE1DMRMwEQYDVQQDDApleGFtcGxlIENBMSIwIAYJKoZIhvcNAQkBFhNleGFtcGxlY2FAbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArD3TDHPAMT2Z84orK4lMlarbgooIUCcRZyLe+QM+8KY8Hn+mGaxPEOTSL3ywszqefB/Utm2hPKLHX684iRC14ID9WDGHxPjvoPArhgFhfV+qnPfxKTgxZC12uOj4u1V9y+SkTCocFbRfXVBGpojrBuDHXkDMDEWNvr8/52YCv7bGaiBwUHolcLCUbmtKILCG0RNJyTaJpXQdAeq5Z1SJotpbfYFFtAXB32hVoLug1dzl2tjG9sb1wq3QaDExcbC5w6P65qOkNoyym9ne6QlQagCqVDyFn3vcqkRaTjvZmxauCeUxXgJoXkyWcm0lM1KMHdoTArmchw2Dz0yHHSyDAQIDAQABo1AwTjAdBgNVHQ4EFgQUc1YQIqjZsHVwlea0AB4N+ilNI2gwHwYDVR0jBBgwFoAUc1YQIqjZsHVwlea0AB4N+ilNI2gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAI/1KH60qnw9Xs2RGfi0/IKf5EynXt4bQX8EIyVKwSkYKe04zZxYfLIl/Q2HOPYoFmm3daj5ddr0ZS1i4p4fTUhstjsYWvXs3W/HhVmFUslakkn3PrswhP77fCk6eEJLxdfyJ1C7Uudq2m1isZbKih+XF0mG1LxJaDMocSz4eAya7M5brwjy8DoOmA1TnLQFCVcpn+sCr7VC4wE/JqxyVhBCk/MuGqqM3B1j90bGFZ112ZOecyE0EDSr6IbiRBtmeNbEwOFjKXhNLYdxpBZ9D8A/368OckZkCrVLGuJNxK9UwCVTe8IhotHUqU9EqFDmxdV8oIdU/OzUwwNPA/Bd/9g==</certificate>"
1305                         "</trusted-certificate>"
1306                         "</input>");
1307
1308         printf("Post data:\n%s\n", post_data_xml);
1309
1310         curl_easy_setopt(curl_odl, CURLOPT_POSTFIELDS, post_data_xml);
1311         curl_easy_setopt(curl_odl, CURLOPT_CUSTOMREQUEST, "POST");
1312         curl_easy_setopt(curl_odl, CURLOPT_USERPWD, credentials);
1313
1314         res = curl_easy_perform(curl_odl);
1315         if (res != CURLE_OK)
1316         {
1317                 printf("cURL failed to url=%s\n", url_for_curl);
1318         }
1319
1320         long http_response_code = 0;
1321         curl_easy_getinfo (curl_odl, CURLINFO_RESPONSE_CODE, &http_response_code);
1322         if (http_response_code >= 200 && http_response_code <= 226 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
1323         {
1324                 printf("cURL succeeded to url=%s\n", url_for_curl);
1325         }
1326         else
1327         {
1328                 printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
1329                 return SR_ERR_OPERATION_FAILED;
1330         }
1331
1332         return SR_ERR_OK;
1333 }
1334
1335 int add_key_pair_to_odl(controller_t *controller_list, int controller_list_size)
1336 {
1337         int rc = SR_ERR_OK;
1338
1339         rc = add_keystore_entry_odl(controller_list[0].url_for_keystore_add, controller_list[0].credentials);
1340         if (rc != SR_ERR_OK)
1341         {
1342                 printf("Failed to add keystore entry to ODL.\n");
1343         }
1344
1345         rc = add_private_key_odl(controller_list[0].url_for_private_key_add, controller_list[0].credentials);
1346         if (rc != SR_ERR_OK)
1347         {
1348                 printf("Failed to add private key entry to ODL.\n");
1349         }
1350
1351         rc = add_trusted_ca_odl(controller_list[0].url_for_trusted_ca_add, controller_list[0].credentials);
1352         if (rc != SR_ERR_OK)
1353         {
1354                 printf("Failed to add trusted CA entry to ODL.\n");
1355         }
1356
1357         return SR_ERR_OK;
1358 }
1359
1360 int ves_ip_changed(char *new_ip)
1361 {
1362         char *stringConfiguration = readConfigFileInString();
1363
1364         if (stringConfiguration == NULL)
1365         {
1366                 printf("Could not read configuration file!\n");
1367                 return SR_ERR_OPERATION_FAILED;
1368         }
1369
1370         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1371         if (jsonConfig == NULL)
1372         {
1373                 free(stringConfiguration);
1374                 const char *error_ptr = cJSON_GetErrorPtr();
1375                 if (error_ptr != NULL)
1376                 {
1377                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
1378                 }
1379                 return SR_ERR_OPERATION_FAILED;
1380         }
1381         //we don't need the string anymore
1382         free(stringConfiguration);
1383         stringConfiguration = NULL;
1384
1385         cJSON *vesDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "ves-endpoint-details");
1386         if (!cJSON_IsObject(vesDetails))
1387         {
1388                 printf("Configuration JSON is not as expected: ves-endpoint-details is not an object");
1389                 free(jsonConfig);
1390                 return SR_ERR_OPERATION_FAILED;
1391         }
1392
1393         cJSON *vesIp = cJSON_GetObjectItemCaseSensitive(vesDetails, "ves-endpoint-ip");
1394         if (!cJSON_IsString(vesIp))
1395         {
1396                 printf("Configuration JSON is not as expected: ves-endpoint-ip is not a string");
1397                 free(jsonConfig);
1398                 return SR_ERR_OPERATION_FAILED;
1399         }
1400
1401         //we set the value of the fault-notification-delay-period object
1402         cJSON_ReplaceItemInObject(vesDetails, "ves-endpoint-ip", cJSON_CreateString(new_ip));
1403
1404         //writing the new JSON to the configuration file
1405         stringConfiguration = cJSON_Print(jsonConfig);
1406         writeConfigFile(stringConfiguration);
1407
1408         free(jsonConfig);
1409
1410         return SR_ERR_OK;
1411 }
1412
1413 int ves_port_changed(int new_port)
1414 {
1415         char *stringConfiguration = readConfigFileInString();
1416
1417         if (stringConfiguration == NULL)
1418         {
1419                 printf("Could not read configuration file!\n");
1420                 return SR_ERR_OPERATION_FAILED;
1421         }
1422
1423         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1424         if (jsonConfig == NULL)
1425         {
1426                 free(stringConfiguration);
1427                 const char *error_ptr = cJSON_GetErrorPtr();
1428                 if (error_ptr != NULL)
1429                 {
1430                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
1431                 }
1432                 return SR_ERR_OPERATION_FAILED;
1433         }
1434         //we don't need the string anymore
1435         free(stringConfiguration);
1436         stringConfiguration = NULL;
1437
1438         cJSON *vesDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "ves-endpoint-details");
1439         if (!cJSON_IsObject(vesDetails))
1440         {
1441                 printf("Configuration JSON is not as expected: ves-endpoint-details is not an object");
1442                 free(jsonConfig);
1443                 return SR_ERR_OPERATION_FAILED;
1444         }
1445
1446         cJSON *vesPort = cJSON_GetObjectItemCaseSensitive(vesDetails, "ves-endpoint-port");
1447         if (!cJSON_IsNumber(vesPort))
1448         {
1449                 printf("Configuration JSON is not as expected: ves-endpoint-port is not a number.");
1450                 free(jsonConfig);
1451                 return SR_ERR_OPERATION_FAILED;
1452         }
1453
1454         //we set the value of the fault-notification-delay-period object
1455         cJSON_SetNumberValue(vesPort, new_port);
1456
1457         //writing the new JSON to the configuration file
1458         stringConfiguration = cJSON_Print(jsonConfig);
1459         writeConfigFile(stringConfiguration);
1460
1461         free(jsonConfig);
1462
1463         return SR_ERR_OK;
1464 }
1465
1466 int ves_registration_changed(cJSON_bool new_bool)
1467 {
1468         char *stringConfiguration = readConfigFileInString();
1469
1470         if (stringConfiguration == NULL)
1471         {
1472                 printf("Could not read configuration file!\n");
1473                 return SR_ERR_OPERATION_FAILED;
1474         }
1475
1476         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1477         if (jsonConfig == NULL)
1478         {
1479                 free(stringConfiguration);
1480                 const char *error_ptr = cJSON_GetErrorPtr();
1481                 if (error_ptr != NULL)
1482                 {
1483                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
1484                 }
1485                 return SR_ERR_OPERATION_FAILED;
1486         }
1487         //we don't need the string anymore
1488         free(stringConfiguration);
1489         stringConfiguration = NULL;
1490
1491         cJSON *vesDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "ves-endpoint-details");
1492         if (!cJSON_IsObject(vesDetails))
1493         {
1494                 printf("Configuration JSON is not as expected: ves-endpoint-details is not an object");
1495                 free(jsonConfig);
1496                 return SR_ERR_OPERATION_FAILED;
1497         }
1498
1499         cJSON *vesRegistration = cJSON_GetObjectItemCaseSensitive(vesDetails, "ves-registration");
1500         if (!cJSON_IsBool(vesRegistration))
1501         {
1502                 printf("Configuration JSON is not as expected: ves-registration is not a bool.");
1503                 free(jsonConfig);
1504                 return SR_ERR_OPERATION_FAILED;
1505         }
1506
1507         //we set the value of the ves-registration object
1508         cJSON_ReplaceItemInObject(vesDetails, "ves-registration", cJSON_CreateBool(new_bool));
1509
1510         //writing the new JSON to the configuration file
1511         stringConfiguration = cJSON_Print(jsonConfig);
1512         writeConfigFile(stringConfiguration);
1513
1514         free(jsonConfig);
1515
1516         return SR_ERR_OK;
1517 }
1518
1519 int is_netconf_available_changed(cJSON_bool new_bool)
1520 {
1521         char *stringConfiguration = readConfigFileInString();
1522
1523         if (stringConfiguration == NULL)
1524         {
1525                 printf("Could not read configuration file!\n");
1526                 return SR_ERR_OPERATION_FAILED;
1527         }
1528
1529         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1530         if (jsonConfig == NULL)
1531         {
1532                 free(stringConfiguration);
1533                 const char *error_ptr = cJSON_GetErrorPtr();
1534                 if (error_ptr != NULL)
1535                 {
1536                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
1537                 }
1538                 return SR_ERR_OPERATION_FAILED;
1539         }
1540         //we don't need the string anymore
1541         free(stringConfiguration);
1542         stringConfiguration = NULL;
1543
1544         cJSON *notifConfig = cJSON_GetObjectItemCaseSensitive(jsonConfig, "notification-config");
1545         if (!cJSON_IsObject(notifConfig))
1546         {
1547                 printf("Configuration JSON is not as expected: notification-config is not an object");
1548                 free(jsonConfig);
1549                 return SR_ERR_OPERATION_FAILED;
1550         }
1551
1552         cJSON *isNetconfAvailable = cJSON_GetObjectItemCaseSensitive(notifConfig, "is-netconf-available");
1553         if (!cJSON_IsBool(isNetconfAvailable))
1554         {
1555                 printf("Configuration JSON is not as expected: is-netconf-available is not a bool.");
1556                 free(jsonConfig);
1557                 return SR_ERR_OPERATION_FAILED;
1558         }
1559
1560         //we set the value of the ves-registration object
1561         cJSON_ReplaceItemInObject(notifConfig, "is-netconf-available", cJSON_CreateBool(new_bool));
1562
1563         //writing the new JSON to the configuration file
1564         stringConfiguration = cJSON_Print(jsonConfig);
1565         writeConfigFile(stringConfiguration);
1566
1567         free(jsonConfig);
1568
1569         return SR_ERR_OK;
1570 }
1571
1572 int is_ves_available_changed(cJSON_bool new_bool)
1573 {
1574         char *stringConfiguration = readConfigFileInString();
1575
1576         if (stringConfiguration == NULL)
1577         {
1578                 printf("Could not read configuration file!\n");
1579                 return SR_ERR_OPERATION_FAILED;
1580         }
1581
1582         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1583         if (jsonConfig == NULL)
1584         {
1585                 free(stringConfiguration);
1586                 const char *error_ptr = cJSON_GetErrorPtr();
1587                 if (error_ptr != NULL)
1588                 {
1589                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
1590                 }
1591                 return SR_ERR_OPERATION_FAILED;
1592         }
1593         //we don't need the string anymore
1594         free(stringConfiguration);
1595         stringConfiguration = NULL;
1596
1597         cJSON *notifConfig = cJSON_GetObjectItemCaseSensitive(jsonConfig, "notification-config");
1598         if (!cJSON_IsObject(notifConfig))
1599         {
1600                 printf("Configuration JSON is not as expected: notification-config is not an object");
1601                 free(jsonConfig);
1602                 return SR_ERR_OPERATION_FAILED;
1603         }
1604
1605         cJSON *isVesAvailable = cJSON_GetObjectItemCaseSensitive(notifConfig, "is-ves-available");
1606         if (!cJSON_IsBool(isVesAvailable))
1607         {
1608                 printf("Configuration JSON is not as expected: is-ves-available is not a bool.");
1609                 free(jsonConfig);
1610                 return SR_ERR_OPERATION_FAILED;
1611         }
1612
1613         //we set the value of the ves-registration object
1614         cJSON_ReplaceItemInObject(notifConfig, "is-ves-available", cJSON_CreateBool(new_bool));
1615
1616         //writing the new JSON to the configuration file
1617         stringConfiguration = cJSON_Print(jsonConfig);
1618         writeConfigFile(stringConfiguration);
1619
1620         free(jsonConfig);
1621
1622         return SR_ERR_OK;
1623 }