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