Bug fix.
[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 #include <unistd.h>
25
26 #include "utils.h"
27
28 #define LINE_BUFSIZE 128
29
30 static  CURL *curl; //share the same curl connection for communicating with the Docker Engine API
31 static  CURL *curl_odl; //share the same curl connection for mounting servers in ODL
32 static  CURL *curl_k8s; //share the same curl connection for communicating with the K8S cluster
33
34 /*
35 curl -X POST -H 'Content-Type: application/json' -i http://localhost:5000/scale --data '{"simulatedDevices":2}'
36 */
37
38 static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
39 {
40   size_t realsize = size * nmemb;
41   struct MemoryStruct *mem = (struct MemoryStruct *)userp;
42
43   char *ptr = realloc(mem->memory, mem->size + realsize + 1);
44   if(ptr == NULL) {
45     /* out of memory! */
46     printf("not enough memory (realloc returned NULL)\n");
47     return 0;
48   }
49
50   mem->memory = ptr;
51   memcpy(&(mem->memory[mem->size]), contents, realsize);
52   mem->size += realsize;
53   mem->memory[mem->size] = 0;
54
55   return realsize;
56 }
57
58 static void set_curl_common_info()
59 {
60     struct curl_slist *chunk = NULL;
61     chunk = curl_slist_append(chunk, "Content-Type: application/json");
62     chunk = curl_slist_append(chunk, "Accept: application/json");
63
64     curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
65
66     curl_easy_setopt(curl, CURLOPT_UNIX_SOCKET_PATH, "/var/run/docker.sock");
67
68     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
69     curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 2L); // seconds timeout for a connection
70     curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L); //seconds timeout for an operation
71
72     curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
73 }
74
75 static void set_curl_common_info_odl()
76 {
77     struct curl_slist *chunk = NULL;
78     chunk = curl_slist_append(chunk, "Content-Type: application/xml");
79     chunk = curl_slist_append(chunk, "Accept: application/xml");
80
81     curl_easy_setopt(curl_odl, CURLOPT_HTTPHEADER, chunk);
82
83     curl_easy_setopt(curl_odl, CURLOPT_CONNECTTIMEOUT, 2L); // seconds timeout for a connection
84     curl_easy_setopt(curl_odl, CURLOPT_TIMEOUT, 10L); //seconds timeout for an operation
85
86     curl_easy_setopt(curl_odl, CURLOPT_VERBOSE, 1L);
87 }
88
89 static void set_curl_common_info_k8s()
90 {
91     struct curl_slist *chunk = NULL;
92     chunk = curl_slist_append(chunk, "Content-Type: application/json");
93     chunk = curl_slist_append(chunk, "Accept: application/json");
94
95     curl_easy_setopt(curl_k8s, CURLOPT_HTTPHEADER, chunk);
96
97     curl_easy_setopt(curl_k8s, CURLOPT_CONNECTTIMEOUT, 2L); // seconds timeout for a connection
98     curl_easy_setopt(curl_k8s, CURLOPT_TIMEOUT, 10L); //seconds timeout for an operation
99
100     curl_easy_setopt(curl_k8s, CURLOPT_VERBOSE, 1L);
101 }
102
103 static cJSON* get_docker_container_bindings(void)
104 {
105         struct MemoryStruct curl_response_mem;
106
107         curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
108         curl_response_mem.size = 0;    /* no data at this point */
109
110         CURLcode res;
111
112         curl_easy_reset(curl);
113         set_curl_common_info();
114
115         char url[200];
116         sprintf(url, "http:/v%s/containers/%s/json", getenv("DOCKER_ENGINE_VERSION"), getenv("HOSTNAME"));
117
118         curl_easy_setopt(curl, CURLOPT_URL, url);
119
120     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
121     curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
122
123         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
124
125         res = curl_easy_perform(curl);
126
127         if (res != CURLE_OK)
128         {
129                 return NULL;
130         }
131         else
132         {
133                 cJSON *json_response = cJSON_Parse(curl_response_mem.memory);
134
135                 printf("%lu bytes retrieved\n", (unsigned long)curl_response_mem.size);
136
137                 if (json_response == NULL)
138                 {
139                         printf("Could not parse JSON response for url=\"%s\"\n", url);
140                         return NULL;
141                 }
142
143                 cJSON *hostConfig = cJSON_GetObjectItemCaseSensitive(json_response, "HostConfig");
144
145                 if (hostConfig == NULL)
146                 {
147                         printf("Could not get HostConfig object\n");
148                         return NULL;
149                 }
150
151                 cJSON *binds = cJSON_GetObjectItemCaseSensitive(hostConfig, "Binds");
152
153                 if (binds == NULL)
154                 {
155                         printf("Could not get Binds object\n");
156                         return NULL;
157                 }
158
159                 cJSON *bindsCopy = cJSON_Duplicate(binds, 1);
160
161             cJSON_Delete(json_response);
162
163                 return bindsCopy;
164         }
165
166         return NULL;
167 }
168
169 static cJSON* get_docker_container_network_node(void)
170 {
171     struct MemoryStruct curl_response_mem;
172
173     curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
174     curl_response_mem.size = 0;    /* no data at this point */
175
176     CURLcode res;
177
178     curl_easy_reset(curl);
179     set_curl_common_info();
180
181     char url[200];
182     sprintf(url, "http:/v%s/containers/%s/json", getenv("DOCKER_ENGINE_VERSION"), getenv("HOSTNAME"));
183
184     curl_easy_setopt(curl, CURLOPT_URL, url);
185
186     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
187     curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
188
189     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
190
191     res = curl_easy_perform(curl);
192
193     if (res != CURLE_OK)
194     {
195         return NULL;
196     }
197     else
198     {
199         cJSON *json_response = cJSON_Parse(curl_response_mem.memory);
200
201         printf("%lu bytes retrieved\n", (unsigned long)curl_response_mem.size);
202
203         if (json_response == NULL)
204         {
205             printf("Could not parse JSON response for url=\"%s\"\n", url);
206             return NULL;
207         }
208
209         cJSON *hostConfig = cJSON_GetObjectItemCaseSensitive(json_response, "HostConfig");
210
211         if (hostConfig == NULL)
212         {
213             printf("Could not get HostConfig object\n");
214             return NULL;
215         }
216
217         cJSON *networkMode = cJSON_GetObjectItemCaseSensitive(hostConfig, "NetworkMode");
218
219         if (networkMode == NULL)
220         {
221             printf("Could not get NetworkMode object\n");
222             return NULL;
223         }
224
225         cJSON *networkCopy = cJSON_Duplicate(networkMode, 1);
226
227         cJSON_Delete(json_response);
228
229         return networkCopy;
230     }
231
232     return NULL;
233 }
234
235 static char* create_docker_container_curl(int base_netconf_port, cJSON* managerBinds, cJSON* networkMode, int device_number)
236 {
237     if (managerBinds == NULL)
238     {
239         printf("Could not retrieve JSON object: Binds\n");
240         return NULL;
241     }
242     cJSON *binds = cJSON_Duplicate(managerBinds, 1);
243
244     if (networkMode == NULL)
245         {
246                 printf("Could not retrieve JSON object: NetworkMode\n");
247                 return NULL;
248         }
249         cJSON *netMode = cJSON_Duplicate(networkMode, 1);
250
251         struct MemoryStruct curl_response_mem;
252
253         curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
254         curl_response_mem.size = 0;    /* no data at this point */
255
256         CURLcode res;
257
258         curl_easy_reset(curl);
259         set_curl_common_info();
260
261         char url[100];
262         sprintf(url, "http:/v%s/containers/create", getenv("DOCKER_ENGINE_VERSION"));
263
264         // the docker image name to be used is defined in the Dockerfile of the NTS Manager,
265         // under the MODELS_IMAGE env variable
266         char models_var[50];
267         sprintf(models_var, "%s", getenv("MODELS_IMAGE"));
268
269         curl_easy_setopt(curl, CURLOPT_URL, url);
270
271     cJSON *postDataJson = cJSON_CreateObject();
272
273     if (cJSON_AddStringToObject(postDataJson, "Image", models_var) == NULL)
274     {
275         printf("Could not create JSON object: Image\n");
276         return NULL;
277     }
278
279     char device_name[100];
280     sprintf(device_name, "%s-%d", getenv("CONTAINER_NAME"), device_number);
281
282     if (cJSON_AddStringToObject(postDataJson, "Hostname", device_name) == NULL)
283     {
284         printf("Could not create JSON object: Hostname\n");
285         return NULL;
286     }    
287
288     cJSON *hostConfig = cJSON_CreateObject();
289     if (hostConfig == NULL)
290     {
291         printf("Could not create JSON object: HostConfig\n");
292         return NULL;
293     }
294
295     cJSON_AddItemToObject(postDataJson, "HostConfig", hostConfig);
296
297     cJSON *portBindings = cJSON_CreateObject();
298     if (portBindings == NULL)
299     {
300         printf("Could not create JSON object: PortBindings\n");
301         return NULL;
302     }
303
304     cJSON_AddItemToObject(hostConfig, "PortBindings", portBindings);
305
306     for (int i = 0; i < NETCONF_CONNECTIONS_PER_DEVICE; ++i)
307     {
308         cJSON *port = cJSON_CreateArray();
309                 if (port == NULL)
310                 {
311                 printf("Could not create JSON object: port\n");
312                         return NULL;
313                 }
314
315                 char dockerContainerPort[20];
316                 sprintf(dockerContainerPort, "%d/tcp", 830 + i);
317
318             cJSON_AddItemToObject(portBindings, dockerContainerPort, port);
319
320             cJSON *hostPort = cJSON_CreateObject();
321             if (hostPort == NULL)
322                 {
323                 printf("Could not create JSON object: HostPort\n");
324                         return NULL;
325                 }
326
327             char dockerHostPort[10];
328             sprintf(dockerHostPort, "%d", base_netconf_port + i);
329             if (cJSON_AddStringToObject(hostPort, "HostPort", dockerHostPort) == NULL)
330             {
331                 printf("Could not create JSON object: HostPortString\n");
332                 return NULL;
333             }
334             if (cJSON_AddStringToObject(hostPort, "HostIp", getenv("NTS_IP")) == NULL)
335             {
336                 printf("Could not create JSON object: HostIpString\n");
337                 return NULL;
338             }
339
340             cJSON_AddItemToArray(port, hostPort);
341     }
342
343     cJSON *labels = cJSON_CreateObject();
344     if (labels == NULL)
345         {
346         printf("Could not create JSON object: Labels\n");
347                 return NULL;
348         }
349
350     cJSON_AddItemToObject(postDataJson, "Labels", labels);
351
352     if (cJSON_AddStringToObject(labels, "NTS", "") == NULL)
353     {
354         printf("Could not create JSON object: NTS\n");
355         return NULL;
356     }
357
358         if (cJSON_AddStringToObject(labels, "NTS_Manager", getenv("HOSTNAME")) == NULL)
359     {
360         printf("Could not create JSON object: NTS Manager\n");
361         return NULL;
362     }
363
364     cJSON *env_variables_array = cJSON_CreateArray();
365     if (env_variables_array == NULL)
366         {
367         printf("Could not create JSON object: Env array\n");
368                 return NULL;
369         }
370
371     cJSON_AddItemToObject(postDataJson, "Env", env_variables_array);
372
373     char environment_var[100];
374     sprintf(environment_var, "NTS_IP=%s", getenv("NTS_IP"));
375
376     cJSON *env_var_obj = cJSON_CreateString(environment_var);
377     if (env_var_obj == NULL)
378         {
379         printf("Could not create JSON object: Env array object NTS_IP\n");
380                 return NULL;
381         }
382     cJSON_AddItemToArray(env_variables_array, env_var_obj);
383
384     char *external_nts_ip = getenv("EXTERNAL_NTS_IP");
385     if (external_nts_ip == NULL)
386     {
387         sprintf(environment_var, "EXTERNAL_NTS_IP=%s", getenv("NTS_IP"));
388     }
389     else
390     {
391         sprintf(environment_var, "EXTERNAL_NTS_IP=%s", external_nts_ip);
392     }
393
394     cJSON *env_var_obj_0 = cJSON_CreateString(environment_var);
395     if (env_var_obj_0 == NULL)
396         {
397         printf("Could not create JSON object: Env array object EXTERNAL_NTS_IP\n");
398                 return NULL;
399         }
400     cJSON_AddItemToArray(env_variables_array, env_var_obj_0);
401
402     sprintf(environment_var, "NETCONF_BASE=%d", base_netconf_port);
403     cJSON *env_var_obj_2 = cJSON_CreateString(environment_var);
404     if (env_var_obj_2 == NULL)
405         {
406         printf("Could not create JSON object: Env array object NETCONF_BASE\n");
407                 return NULL;
408         }
409     cJSON_AddItemToArray(env_variables_array, env_var_obj_2);
410
411     char scripts_dir[200];
412     sprintf(scripts_dir, "SCRIPTS_DIR=%s", getenv("SCRIPTS_DIR"));
413     cJSON *env_var_obj_3 = cJSON_CreateString(scripts_dir);
414     if (env_var_obj_3 == NULL)
415     {
416         printf("Could not create JSON object: Env array object SCRIPTS_DIR\n");
417         return NULL;
418     }
419     cJSON_AddItemToArray(env_variables_array, env_var_obj_3);
420
421     char k8s_deployment[50];
422     sprintf(k8s_deployment, "K8S_DEPLOYMENT=%s", getenv("K8S_DEPLOYMENT"));
423     cJSON *env_var_obj_4 = cJSON_CreateString(k8s_deployment);
424     if (env_var_obj_4 == NULL)
425     {
426         printf("Could not create JSON object: Env array object K8S_DEPLOYMENT\n");
427         return NULL;
428     }
429     cJSON_AddItemToArray(env_variables_array, env_var_obj_4);
430
431     char ipv6_enabled[50];
432     sprintf(ipv6_enabled, "IPv6Enabled=%s", getenv("IPv6Enabled"));
433     cJSON *env_var_obj_5 = cJSON_CreateString(ipv6_enabled);
434     if (env_var_obj_5 == NULL)
435     {
436         printf("Could not create JSON object: Env array object IPv6Enabled\n");
437         return NULL;
438     }
439     cJSON_AddItemToArray(env_variables_array, env_var_obj_5);
440
441     cJSON_AddItemToObject(hostConfig, "Binds", binds);
442
443     cJSON_AddItemToObject(hostConfig, "NetworkMode", netMode);
444
445     char *post_data_string = NULL;
446
447     post_data_string = cJSON_PrintUnformatted(postDataJson);
448
449     printf("Post data JSON:\n%s\n", post_data_string);
450
451     if (postDataJson != NULL)
452     {
453         cJSON_Delete(postDataJson);
454     }
455
456     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data_string);
457
458         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
459
460         res = curl_easy_perform(curl);
461
462     if (post_data_string != NULL)
463     {
464         free(post_data_string);
465     }
466
467         if (res != CURLE_OK)
468         {
469                 return NULL;
470         }
471         else
472         {
473                 cJSON *json_response = cJSON_Parse(curl_response_mem.memory);
474                 const cJSON *container_id = NULL;
475
476                 printf("%lu bytes retrieved\n", (unsigned long)curl_response_mem.size);
477
478                 container_id = cJSON_GetObjectItemCaseSensitive(json_response, "Id");
479
480                 if (cJSON_IsString(container_id) && (container_id->valuestring != NULL))
481                 {
482                         printf("Container id: \"%s\"\n", container_id->valuestring);
483
484                         char container_id_short[13];
485
486                         memset(container_id_short, '\0', sizeof(container_id_short));
487                         strncpy(container_id_short, container_id->valuestring, 12);
488
489                         printf("Container id short: \"%s\"\n", container_id_short);
490
491                     cJSON_Delete(json_response);
492                         return strdup(container_id_short);
493                 }
494
495             cJSON_Delete(json_response);
496         }
497
498         return NULL;
499 }
500
501 static int start_docker_container_curl(char *container_id)
502 {
503     struct MemoryStruct curl_response_mem;
504
505     curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
506     curl_response_mem.size = 0;    /* no data at this point */
507
508     CURLcode res;
509
510     curl_easy_reset(curl);
511     set_curl_common_info();
512
513     char url[100];
514     sprintf(url, "http:/v%s/containers/%s/start", getenv("DOCKER_ENGINE_VERSION"), container_id);
515
516     curl_easy_setopt(curl, CURLOPT_URL, url);
517
518     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
519
520     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
521
522     res = curl_easy_perform(curl);
523
524     if (res != CURLE_OK)
525     {
526         return SR_ERR_OPERATION_FAILED;
527     }
528     else
529     {
530         printf("Container %s started successfully!\n", container_id);
531     }
532
533     return SR_ERR_OK;
534 }
535
536 static int rename_docker_container_curl(char *container_id, int device_number)
537 {
538     struct MemoryStruct curl_response_mem;
539
540     curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
541     curl_response_mem.size = 0;    /* no data at this point */
542
543     CURLcode res;
544
545     curl_easy_reset(curl);
546     set_curl_common_info();
547
548     char device_name[100];
549     sprintf(device_name, "%s-%d", getenv("CONTAINER_NAME"), device_number);
550
551     char url[100];
552     sprintf(url, "http:/v%s/containers/%s/rename?name=%s", getenv("DOCKER_ENGINE_VERSION"), container_id,
553                 device_name);
554
555     curl_easy_setopt(curl, CURLOPT_URL, url);
556
557     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
558
559     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
560
561     res = curl_easy_perform(curl);
562
563     if (res != CURLE_OK)
564     {
565         return SR_ERR_OPERATION_FAILED;
566     }
567     else
568     {
569         printf("Container %s renamed successfully to %s!\n", container_id, device_name);
570     }
571
572     return SR_ERR_OK;
573 }
574
575 static int kill_and_remove_docker_container_curl(char *container_id)
576 {
577         struct MemoryStruct curl_response_mem;
578
579         curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
580         curl_response_mem.size = 0;    /* no data at this point */
581
582         CURLcode res;
583
584         curl_easy_reset(curl);
585         set_curl_common_info();
586
587         char url[100];
588         sprintf(url, "http:/v%s/containers/%s?force=true", getenv("DOCKER_ENGINE_VERSION"), container_id);
589
590         curl_easy_setopt(curl, CURLOPT_URL, url);
591
592     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
593     curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
594
595         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
596
597         res = curl_easy_perform(curl);
598
599         if (res != CURLE_OK)
600         {
601                 return SR_ERR_OPERATION_FAILED;
602         }
603         else
604         {
605                 printf("Container %s removed successfully!\n", container_id);
606         }
607
608         return SR_ERR_OK;
609 }
610
611 static int send_mount_device_instance_ssh(char *url, char *credentials, char *device_name, int device_port)
612 {
613         CURLcode res;
614
615         curl_easy_reset(curl_odl);
616         set_curl_common_info_odl();
617
618         char url_for_curl[200];
619         sprintf(url_for_curl, "%s%s_%d", url, device_name, device_port);
620
621         curl_easy_setopt(curl_odl, CURLOPT_URL, url_for_curl);
622
623         char post_data_xml[1500];
624
625         sprintf(post_data_xml,
626             "<node xmlns=\"urn:TBD:params:xml:ns:yang:network-topology\">"
627             "<node-id>%s_%d</node-id>"
628             "<host xmlns=\"urn:opendaylight:netconf-node-topology\">%s</host>"
629             "<port xmlns=\"urn:opendaylight:netconf-node-topology\">%d</port>"
630             "<username xmlns=\"urn:opendaylight:netconf-node-topology\">%s</username>"
631             "<password xmlns=\"urn:opendaylight:netconf-node-topology\">%s</password>"
632             "<tcp-only xmlns=\"urn:opendaylight:netconf-node-topology\">false</tcp-only>"
633             "<keepalive-delay xmlns=\"urn:opendaylight:netconf-node-topology\">120</keepalive-delay>"
634             "<reconnect-on-changed-schema xmlns=\"urn:opendaylight:netconf-node-topology\">false</reconnect-on-changed-schema>"
635             "<sleep-factor xmlns=\"urn:opendaylight:netconf-node-topology\">1.5</sleep-factor>"
636             "<connection-timeout-millis xmlns=\"urn:opendaylight:netconf-node-topology\">20000</connection-timeout-millis>"
637             "<max-connection-attempts xmlns=\"urn:opendaylight:netconf-node-topology\">100</max-connection-attempts>"
638             "<between-attempts-timeout-millis xmlns=\"urn:opendaylight:netconf-node-topology\">2000</between-attempts-timeout-millis>"
639             "</node>",
640                         device_name, device_port, (getenv("EXTERNAL_NTS_IP") == NULL) ? getenv("NTS_IP") : getenv("EXTERNAL_NTS_IP"),
641             device_port, "netconf", "netconf");
642
643         printf("Post data:\n%s\n", post_data_xml);
644
645         curl_easy_setopt(curl_odl, CURLOPT_POSTFIELDS, post_data_xml);
646     curl_easy_setopt(curl_odl, CURLOPT_CUSTOMREQUEST, "PUT");
647     curl_easy_setopt(curl_odl, CURLOPT_USERPWD, credentials);
648
649         res = curl_easy_perform(curl_odl);
650         if (res != CURLE_OK)
651         {
652                 printf("cURL failed to url=%s\n", url_for_curl);
653         }
654
655         long http_response_code = 0;
656         curl_easy_getinfo (curl_odl, CURLINFO_RESPONSE_CODE, &http_response_code);
657         if (http_response_code >= 200 && http_response_code <= 226 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
658         {
659                 printf("cURL succeeded to url=%s\n", url_for_curl);
660         }
661         else
662         {
663             printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
664                 return SR_ERR_OPERATION_FAILED;
665         }
666
667         return SR_ERR_OK;
668 }
669
670 static int send_mount_device_instance_tls(char *url, char *credentials, char *device_name, int device_port)
671 {
672         CURLcode res;
673
674         curl_easy_reset(curl_odl);
675         set_curl_common_info_odl();
676
677         char url_for_curl[200];
678         sprintf(url_for_curl, "%s%s_%d", url, device_name, device_port);
679
680         curl_easy_setopt(curl_odl, CURLOPT_URL, url_for_curl);
681
682         char post_data_xml[1500];
683
684         sprintf(post_data_xml,
685                         "<node xmlns=\"urn:TBD:params:xml:ns:yang:network-topology\">"
686                         "<protocol xmlns=\"urn:opendaylight:netconf-node-topology\">"
687                         "<name>TLS</name>"
688                         "</protocol>"
689                         "<node-id>%s_%d</node-id>"
690                         "<host xmlns=\"urn:opendaylight:netconf-node-topology\">%s</host>"
691                         "<key-based xmlns=\"urn:opendaylight:netconf-node-topology\">"
692                         "<username>%s</username>"
693                         "<key-id>device-key</key-id>"
694                         "</key-based>"
695                         "<port xmlns=\"urn:opendaylight:netconf-node-topology\">%d</port>"
696                         "<tcp-only xmlns=\"urn:opendaylight:netconf-node-topology\">false</tcp-only>"
697                         "<keepalive-delay xmlns=\"urn:opendaylight:netconf-node-topology\">120</keepalive-delay>"
698                         "<reconnect-on-changed-schema xmlns=\"urn:opendaylight:netconf-node-topology\">false</reconnect-on-changed-schema>"
699                         "<sleep-factor xmlns=\"urn:opendaylight:netconf-node-topology\">1.5</sleep-factor>"
700                         "<connection-timeout-millis xmlns=\"urn:opendaylight:netconf-node-topology\">20000</connection-timeout-millis>"
701                         "<max-connection-attempts xmlns=\"urn:opendaylight:netconf-node-topology\">100</max-connection-attempts>"
702                         "<between-attempts-timeout-millis xmlns=\"urn:opendaylight:netconf-node-topology\">2000</between-attempts-timeout-millis>"
703                         "</node>",
704                         device_name, device_port, (getenv("EXTERNAL_NTS_IP") == NULL) ? getenv("NTS_IP") : getenv("EXTERNAL_NTS_IP"), "netconf", device_port);
705
706         printf("Post data:\n%s\n", post_data_xml);
707
708         curl_easy_setopt(curl_odl, CURLOPT_POSTFIELDS, post_data_xml);
709     curl_easy_setopt(curl_odl, CURLOPT_CUSTOMREQUEST, "PUT");
710     curl_easy_setopt(curl_odl, CURLOPT_USERPWD, credentials);
711
712         res = curl_easy_perform(curl_odl);
713         if (res != CURLE_OK)
714         {
715                 printf("cURL failed to url=%s\n", url_for_curl);
716         }
717
718         long http_response_code = 0;
719         curl_easy_getinfo (curl_odl, CURLINFO_RESPONSE_CODE, &http_response_code);
720         if (http_response_code >= 200 && http_response_code <= 226 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
721         {
722                 printf("cURL succeeded to url=%s\n", url_for_curl);
723         }
724         else
725         {
726             printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
727                 return SR_ERR_OPERATION_FAILED;
728         }
729
730         return SR_ERR_OK;
731 }
732
733 static int send_unmount_device_instance(char *url, char *credentials, char *device_name, int device_port)
734 {
735         CURLcode res;
736
737         curl_easy_reset(curl_odl);
738         set_curl_common_info_odl();
739
740         char url_for_curl[200];
741         sprintf(url_for_curl, "%s%s_%d", url, device_name, device_port);
742
743         curl_easy_setopt(curl_odl, CURLOPT_URL, url_for_curl);
744
745         curl_easy_setopt(curl_odl, CURLOPT_POSTFIELDS, "");
746         curl_easy_setopt(curl_odl, CURLOPT_CUSTOMREQUEST, "DELETE");
747         curl_easy_setopt(curl_odl, CURLOPT_USERPWD, credentials);
748
749         res = curl_easy_perform(curl_odl);
750         if (res != CURLE_OK)
751         {
752                 printf("cURL failed to url=%s\n", url_for_curl);
753         }
754
755         long http_response_code = 0;
756         curl_easy_getinfo (curl_odl, CURLINFO_RESPONSE_CODE, &http_response_code);
757         if (http_response_code == 200 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
758         {
759                 printf("cURL succeeded to url=%s\n", url_for_curl);
760         }
761         else
762         {
763                 printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
764                 return SR_ERR_OPERATION_FAILED;
765         }
766
767         return SR_ERR_OK;
768 }
769
770
771 static int send_mount_device(device_t *current_device, controller_t controller_details)
772 {
773         int rc = SR_ERR_OK;
774         bool is_mounted = true;
775     int port = 0;
776
777     char device_name[200];
778     sprintf(device_name, "%s-%d", getenv("CONTAINER_NAME"), current_device->device_number);
779
780         //This is where we hardcoded: 7 devices will have SSH connections and 3 devices will have TLS connections
781         for (int i = 0; i < SSH_CONNECTIONS_PER_DEVICE; ++port, ++i)
782         {
783         
784
785                 rc = send_mount_device_instance_ssh(controller_details.url, controller_details.credentials,
786                                 device_name, current_device->netconf_port + port);
787                 if (rc != SR_ERR_OK)
788                 {
789                         is_mounted = false;
790                 }
791         }
792         for (int i = 0; i < TLS_CONNECTIONS_PER_DEVICE; ++port, ++i)
793         {
794                 rc = send_mount_device_instance_tls(controller_details.url, controller_details.credentials,
795                                 device_name, current_device->netconf_port + port);
796                 if (rc != SR_ERR_OK)
797                 {
798                         is_mounted = false;
799                 }
800         }
801
802         current_device->is_mounted = is_mounted;
803
804         return SR_ERR_OK;
805 }
806
807 static int send_unmount_device(device_t *current_device, controller_t controller_details)
808 {
809         int rc = SR_ERR_OK;
810     char device_name[100];
811     sprintf(device_name, "%s-%d", getenv("CONTAINER_NAME"), current_device->device_number);
812
813         for (int port = 0; port < NETCONF_CONNECTIONS_PER_DEVICE; ++port)
814         {
815                 rc = send_unmount_device_instance(controller_details.url, controller_details.credentials,
816                                 device_name, current_device->netconf_port + port);
817                 if (rc != SR_ERR_OK)
818                 {
819                         printf("Could not send unmount for ODL with url=\"%s\", for device=\"%s\" and port=%d\n",
820                                         controller_details.url, device_name, current_device->netconf_port);
821                 }
822         }
823         current_device->is_mounted = false;
824
825         return SR_ERR_OK;
826 }
827
828 device_stack_t *new_device_stack(void)
829 {
830         device_stack_t *stack = malloc(sizeof(*stack));
831
832         if (stack) {
833                 stack->head = NULL;
834                 stack->stack_size = 0;
835         }
836         return stack;
837 }
838
839 void push_device(device_stack_t *theStack, char *dev_id, int port, int dev_num)
840 {
841         device_t *new_dev = malloc(sizeof(*new_dev));
842
843         if (new_dev) {
844                 new_dev->device_id = strdup(dev_id);
845                 new_dev->netconf_port = port;
846         new_dev->device_number = dev_num;
847                 new_dev->is_mounted = false;
848                 new_dev->operational_state = strdup("not-specified");
849
850                 new_dev->next = theStack->head;
851
852                 theStack->head = new_dev;
853                 theStack->stack_size++;
854         }
855 }
856
857 void pop_device(device_stack_t *theStack)
858 {
859         if (theStack && theStack->head) {
860                 device_t *temp = theStack->head;
861                 theStack->head = theStack->head->next;
862
863                 free(temp->device_id);
864                 free(temp->operational_state);
865                 free(temp);
866                 theStack->stack_size--;
867         }
868 }
869
870 int get_netconf_port_next(device_stack_t *theStack)
871 {
872     if (theStack && theStack->stack_size > 0) {
873         return theStack->head->netconf_port + NETCONF_CONNECTIONS_PER_DEVICE;
874     }
875
876     return get_netconf_port_base();
877 }
878
879 int get_netconf_port_base()
880 {
881     int netconf_port_base;
882
883     netconf_port_base = getIntFromString(getenv("NETCONF_BASE"), 50000);
884
885     return netconf_port_base;
886 }
887
888 // we start numbering the containers from 0
889 int get_device_number_next(device_stack_t *theStack)
890 {
891     if (theStack && theStack->stack_size > 0) {
892         return theStack->head->device_number + 1;
893     }
894
895     return 0;
896 }
897
898 char *get_id_last_device(device_stack_t *theStack)
899 {
900     if (theStack && theStack->head) {
901         return theStack->head->device_id;
902     }
903     return NULL;
904 }
905
906 int get_current_number_of_mounted_devices(device_stack_t *theStack)
907 {
908         int mounted_devices = 0;
909
910         if (theStack && theStack->head)
911         {
912                 device_t *current_device = theStack->head;
913
914                 while (current_device != NULL)
915                 {
916                         if (current_device->is_mounted)
917                         {
918                                 mounted_devices++;
919                         }
920                         current_device = current_device->next;
921                 }
922         }
923
924         return mounted_devices;
925 }
926
927 int get_current_number_of_devices(device_stack_t *theStack)
928 {
929     //TODO implement function for k8s deployment
930     if (strcmp(getenv("K8S_DEPLOYMENT"), "true") == 0)
931     {
932         return 0;
933     }
934
935         struct MemoryStruct curl_response_mem;
936
937         curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
938         curl_response_mem.size = 0;    /* no data at this point */
939
940         CURLcode res;
941
942         curl_easy_reset(curl);
943         set_curl_common_info();
944
945         char url[100];
946         sprintf(url, "http:/v%s/containers/json?all=true&filters={\"label\":[\"NTS_Manager=%s\"],\"status\":[\"running\"]}",
947                         getenv("DOCKER_ENGINE_VERSION"), getenv("HOSTNAME"));
948
949         curl_easy_setopt(curl, CURLOPT_URL, url);
950
951         curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
952         curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
953
954         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
955
956         res = curl_easy_perform(curl);
957
958         if (res != CURLE_OK)
959         {
960                 return SR_ERR_OPERATION_FAILED;
961         }
962         else
963         {
964                 cJSON *json_response = cJSON_Parse(curl_response_mem.memory);
965
966                 printf("%lu bytes retrieved\n", (unsigned long)curl_response_mem.size);
967
968                 if (json_response == NULL || !cJSON_IsArray(json_response))
969                 {
970                         printf("Could not parse JSON response for url=\"%s\"\n", url);
971                         return SR_ERR_OPERATION_FAILED;
972                 }
973
974                 int num_of_devices = cJSON_GetArraySize(json_response);
975                 cJSON_Delete(json_response);
976
977                 return num_of_devices;
978         }
979
980         return 0;
981 }
982
983 static int set_operational_state_of_device(device_stack_t *theStack, char *device_id, char *operational_state)
984 {
985         if (theStack && theStack->head)
986         {
987                 device_t *current_device = theStack->head;
988
989                 while (current_device != NULL)
990                 {
991                         if (strcmp(current_device->device_id, device_id) == 0)
992                         {
993                                 free(current_device->operational_state);
994                                 current_device->operational_state = strdup(operational_state);
995
996                                 return SR_ERR_OK;
997                         }
998
999                         current_device = current_device->next;
1000                 }
1001         }
1002
1003         printf("Could not find device with uuid=\"%s\"\n", device_id);
1004         return SR_ERR_OPERATION_FAILED;
1005 }
1006
1007 char* get_docker_container_operational_state(device_stack_t *theStack, char *container_id)
1008 {
1009         if (theStack && theStack->head)
1010         {
1011                 device_t *current_device = theStack->head;
1012
1013                 while (current_device != NULL)
1014                 {
1015                         if (strcmp(current_device->device_id, container_id) == 0)
1016                         {
1017                                 return current_device->operational_state;
1018                         }
1019
1020                         current_device = current_device->next;
1021                 }
1022         }
1023
1024         return NULL;
1025 }
1026
1027 int start_device(device_stack_t *theStack)
1028 {
1029         int rc = SR_ERR_OK;
1030         static cJSON *managerBindings = NULL, *networkMode = NULL;
1031
1032     if (managerBindings == NULL)
1033     {
1034         managerBindings = get_docker_container_bindings();
1035     }
1036
1037     if (networkMode == NULL)
1038         {
1039                 networkMode = get_docker_container_network_node();
1040         }
1041
1042         int netconf_base = get_netconf_port_next(theStack);
1043     int device_number = get_device_number_next(theStack);
1044
1045         char *dev_id = create_docker_container_curl(netconf_base, managerBindings, networkMode, device_number);
1046     if (dev_id == NULL)
1047     {
1048         printf("ERROR: Could not create docker container!\n");
1049         return SR_ERR_OPERATION_FAILED;
1050     }
1051
1052         push_device(theStack, dev_id, netconf_base, device_number);
1053
1054         rc = start_docker_container_curl(dev_id);
1055         if (rc != SR_ERR_OK)
1056         {
1057                 printf("Could not start device with device_id=\"%s\"\n", dev_id);
1058         }
1059
1060     rc = rename_docker_container_curl(dev_id, device_number);
1061         if (rc != SR_ERR_OK)
1062         {
1063                 printf("Could not rename device with device_id=\"%s\"\n", dev_id);
1064         }
1065
1066         if (dev_id) {
1067                 free(dev_id);
1068         }
1069
1070         return SR_ERR_OK;
1071 }
1072
1073 int _init_curl()
1074 {
1075         curl = curl_easy_init();
1076
1077         if (curl == NULL) {
1078                 printf("cURL initialization error! Aborting call!\n");
1079                 return SR_ERR_OPERATION_FAILED;
1080         }
1081
1082         return SR_ERR_OK;
1083 }
1084
1085 int cleanup_curl()
1086 {
1087         if (curl != NULL)
1088         {
1089                 curl_easy_cleanup(curl);
1090         }
1091
1092         return SR_ERR_OK;
1093 }
1094
1095 int _init_curl_odl()
1096 {
1097         curl_odl = curl_easy_init();
1098
1099         if (curl_odl == NULL) {
1100                 printf("cURL initialization error! Aborting call!\n");
1101                 return SR_ERR_OPERATION_FAILED;
1102         }
1103
1104         return SR_ERR_OK;
1105 }
1106
1107 int cleanup_curl_odl()
1108 {
1109         if (curl_odl != NULL)
1110         {
1111                 curl_easy_cleanup(curl_odl);
1112         }
1113
1114         return SR_ERR_OK;
1115 }
1116
1117 int _init_curl_k8s()
1118 {
1119     curl_k8s = curl_easy_init();
1120
1121     if (curl_k8s == NULL) {
1122         printf("cURL initialization error! Aborting call!\n");
1123         return SR_ERR_OPERATION_FAILED;
1124     }
1125
1126     return SR_ERR_OK;
1127 }
1128
1129 int cleanup_curl_k8s()
1130 {
1131     if (curl_k8s != NULL)
1132     {
1133         curl_easy_cleanup(curl_k8s);
1134     }
1135
1136     return SR_ERR_OK;
1137 }
1138
1139 int stop_device(device_stack_t *theStack)
1140 {
1141         int rc = SR_ERR_OK;
1142         char *last_id = get_id_last_device(theStack);
1143
1144         rc = kill_and_remove_docker_container_curl(last_id);
1145         if (rc != SR_ERR_OK)
1146         {
1147                 printf("Could not kill and remove docker container with uuid=\"%s\"\n", last_id);
1148         }
1149
1150     rc = removeDeviceEntryFromStatusFile(last_id);
1151     if (rc != SR_ERR_OK)
1152     {
1153         printf("Could not remove entry from status file for uuid=\"%s\"\n", last_id);
1154     }
1155
1156         pop_device(theStack);
1157
1158         return SR_ERR_OK;
1159 }
1160
1161 int mount_device(device_stack_t *theStack, controller_t controller_details)
1162 {
1163         int rc;
1164
1165         if (theStack && theStack->head)
1166         {
1167                 device_t *current_device = theStack->head;
1168                 while (current_device != NULL && current_device->is_mounted == true)
1169                 {
1170                         printf("Device \"%s\" is already mounted, skipping...\n", current_device->device_id);
1171                         current_device = current_device->next;
1172                 }
1173
1174                 if (current_device != NULL)
1175                 {
1176                         printf("Sending mount device for device \"%s\"...\n", current_device->device_id);
1177                         rc = send_mount_device(current_device, controller_details);
1178                         if (rc != SR_ERR_OK)
1179                         {
1180                                 return SR_ERR_OPERATION_FAILED;
1181                         }
1182                 }
1183         }
1184
1185         return SR_ERR_OK;
1186 }
1187
1188 int unmount_device(device_stack_t *theStack, controller_t controller_list)
1189 {
1190         int rc;
1191
1192         if (theStack && theStack->head)
1193         {
1194                 device_t *current_device = theStack->head;
1195                 while (current_device != NULL && current_device->is_mounted == false)
1196                 {
1197                         printf("Device \"%s\" is already unmounted, skipping...\n", current_device->device_id);
1198                         current_device = current_device->next;
1199                 }
1200
1201                 if (current_device != NULL)
1202                 {
1203                         printf("Sending unmount device for device \"%s\"...\n", current_device->device_id);
1204                         rc = send_unmount_device(current_device, controller_list);
1205                         if (rc != SR_ERR_OK)
1206                         {
1207                                 return SR_ERR_OPERATION_FAILED;
1208                         }
1209                 }
1210         }
1211
1212         return SR_ERR_OK;
1213 }
1214
1215 int get_docker_containers_operational_state_curl(device_stack_t *theStack)
1216 {
1217
1218     //TODO implement function for k8s deployment
1219     if (strcmp(getenv("K8S_DEPLOYMENT"), "true") == 0)
1220     {
1221         return SR_ERR_OK;
1222     }
1223
1224         int rc = SR_ERR_OK;
1225         struct MemoryStruct curl_response_mem;
1226
1227         curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
1228         curl_response_mem.size = 0;    /* no data at this point */
1229
1230         CURLcode res;
1231
1232         curl_easy_reset(curl);
1233         set_curl_common_info();
1234
1235         char url[100];
1236         sprintf(url, "http:/v%s/containers/json?all=true&filters={\"label\":[\"NTS_Manager=%s\"]}", 
1237     getenv("DOCKER_ENGINE_VERSION"), getenv("HOSTNAME"));
1238
1239         curl_easy_setopt(curl, CURLOPT_URL, url);
1240
1241     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
1242     curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
1243
1244         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
1245
1246         res = curl_easy_perform(curl);
1247
1248         if (res != CURLE_OK)
1249         {
1250                 return SR_ERR_OPERATION_FAILED;
1251         }
1252         else
1253         {
1254                 cJSON *json_response = cJSON_Parse(curl_response_mem.memory);
1255                 const cJSON *container = NULL;
1256
1257                 printf("%lu bytes retrieved\n", (unsigned long)curl_response_mem.size);
1258
1259                 if (json_response == NULL || !cJSON_IsArray(json_response))
1260                 {
1261                         printf("Could not parse JSON response for url=\"%s\"\n", url);
1262                         return SR_ERR_OPERATION_FAILED;
1263                 }
1264
1265             cJSON_ArrayForEach(container, json_response)
1266             {
1267                 cJSON *container_id_long = cJSON_GetObjectItemCaseSensitive(container, "Id");
1268                 cJSON *state = cJSON_GetObjectItemCaseSensitive(container, "State");
1269
1270                         if (cJSON_IsString(container_id_long) && (container_id_long->valuestring != NULL))
1271                         {
1272                                 char container_id_short[13];
1273
1274                                 memset(container_id_short, '\0', sizeof(container_id_short));
1275                                 strncpy(container_id_short, container_id_long->valuestring, 12);
1276
1277                                 if (cJSON_IsString(state) && (state->valuestring != NULL))
1278                                 {
1279                                         rc = set_operational_state_of_device(theStack, container_id_short, state->valuestring);
1280                                         if (rc != SR_ERR_OK)
1281                                         {
1282                                                 printf("Could not set the operational state for the device with uuid=\"%s\"\n", container_id_short);
1283                                                 return SR_ERR_OPERATION_FAILED;
1284                                         }
1285                                 }
1286                         }
1287             }
1288
1289             cJSON_Delete(json_response);
1290         }
1291
1292         return SR_ERR_OK;
1293 }
1294
1295 char* get_docker_container_resource_stats(device_stack_t *theStack)
1296 {
1297     //TOD need to implement this for k8s deployment
1298     if (strcmp(getenv("K8S_DEPLOYMENT"), "true"))
1299     {
1300         return strdup("CPU=0%;RAM=0MiB");
1301     }
1302
1303         char line[LINE_BUFSIZE];
1304         int linenr;
1305         FILE *pipe;
1306
1307         /* Get a pipe where the output from the scripts comes in */
1308         char script[200];
1309         sprintf(script, "/opt/dev/docker_stats.sh %s", getenv("HOSTNAME"));
1310
1311         pipe = popen(script, "r");
1312         if (pipe == NULL) {  /* check for errors */
1313                 printf("Could not open script.\n");
1314                 return NULL;        /* return with exit code indicating error */
1315         }
1316
1317         /* Read script output from the pipe line by line */
1318         linenr = 1;
1319         while (fgets(line, LINE_BUFSIZE, pipe) != NULL) {
1320                 printf("Script output line %d: %s", linenr, line);
1321                 ++linenr;
1322
1323                 pclose(pipe); /* Close the pipe */
1324                 return strdup(line);
1325         }
1326
1327         /* Once here, out of the loop, the script has ended. */
1328         pclose(pipe); /* Close the pipe */
1329         return NULL;     /* return with exit code indicating success. */
1330 }
1331
1332 int notification_delay_period_changed(sr_val_t *val, size_t count)
1333 {
1334         char *stringConfiguration = readConfigFileInString();
1335
1336         if (stringConfiguration == NULL)
1337         {
1338                 printf("Could not read configuration file!\n");
1339                 return SR_ERR_OPERATION_FAILED;
1340         }
1341
1342         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1343         if (jsonConfig == NULL)
1344         {
1345                 free(stringConfiguration);
1346                 const char *error_ptr = cJSON_GetErrorPtr();
1347                 if (error_ptr != NULL)
1348                 {
1349                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
1350                 }
1351                 return SR_ERR_OPERATION_FAILED;
1352         }
1353         //we don't need the string anymore
1354         free(stringConfiguration);
1355         stringConfiguration = NULL;
1356
1357         cJSON *notifConfig = cJSON_GetObjectItemCaseSensitive(jsonConfig, "notification-config");
1358         if (!cJSON_IsObject(notifConfig))
1359         {
1360                 printf("Configuration JSON is not as expected: notification-config is not an object");
1361                 cJSON_Delete(jsonConfig);
1362                 return SR_ERR_OPERATION_FAILED;
1363         }
1364
1365         cJSON *faultNotifDelay = cJSON_GetObjectItemCaseSensitive(notifConfig, "fault-notification-delay-period");
1366         if (!cJSON_IsArray(faultNotifDelay))
1367         {
1368                 printf("Configuration JSON is not as expected: fault-notification-delay-period is not an array.");
1369                 cJSON_Delete(jsonConfig);
1370                 return SR_ERR_OPERATION_FAILED;
1371         }
1372
1373     cJSON_DeleteItemFromObject(notifConfig, "fault-notification-delay-period");
1374
1375     faultNotifDelay = NULL;
1376
1377     faultNotifDelay = cJSON_CreateArray();
1378     if (faultNotifDelay == NULL) 
1379     {
1380         cJSON_Delete(jsonConfig);
1381                 return SR_ERR_OPERATION_FAILED;
1382     }
1383     cJSON_AddItemToObject(notifConfig, "fault-notification-delay-period", faultNotifDelay);
1384
1385     if (val != NULL && count > 0)
1386     {
1387         cJSON *arrayEntry = NULL;
1388         for (size_t i=0; i<count; ++i)
1389         {
1390             arrayEntry = cJSON_CreateNumber(val[i].data.uint32_val);
1391             if (arrayEntry == NULL) 
1392             {
1393                 cJSON_Delete(jsonConfig);
1394                 return SR_ERR_OPERATION_FAILED;
1395             }
1396             cJSON_AddItemToArray(faultNotifDelay, arrayEntry);
1397         }
1398     }
1399     else
1400     {
1401         cJSON *arrayEntry =  cJSON_CreateNumber(0);
1402         if (arrayEntry == NULL) 
1403         {
1404             cJSON_Delete(jsonConfig);
1405             return SR_ERR_OPERATION_FAILED;
1406         }
1407         cJSON_AddItemToArray(faultNotifDelay, arrayEntry);
1408     }
1409
1410         //writing the new JSON to the configuration file
1411         stringConfiguration = cJSON_Print(jsonConfig);
1412         writeConfigFile(stringConfiguration);
1413
1414     if (stringConfiguration != NULL)
1415     {
1416         free(stringConfiguration);
1417         stringConfiguration = NULL;
1418     }
1419
1420         cJSON_Delete(jsonConfig);
1421
1422         return SR_ERR_OK;
1423 }
1424
1425 int ves_heartbeat_period_changed(int period)
1426 {
1427         char *stringConfiguration = readConfigFileInString();
1428
1429         if (stringConfiguration == NULL)
1430         {
1431                 printf("Could not read configuration file!\n");
1432                 return SR_ERR_OPERATION_FAILED;
1433         }
1434
1435         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1436         if (jsonConfig == NULL)
1437         {
1438                 free(stringConfiguration);
1439                 const char *error_ptr = cJSON_GetErrorPtr();
1440                 if (error_ptr != NULL)
1441                 {
1442                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
1443                 }
1444                 return SR_ERR_OPERATION_FAILED;
1445         }
1446         //we don't need the string anymore
1447         free(stringConfiguration);
1448         stringConfiguration = NULL;
1449
1450         cJSON *notifConfig = cJSON_GetObjectItemCaseSensitive(jsonConfig, "notification-config");
1451         if (!cJSON_IsObject(notifConfig))
1452         {
1453                 printf("Configuration JSON is not as expected: notification-config is not an object");
1454                 cJSON_Delete(jsonConfig);
1455                 return SR_ERR_OPERATION_FAILED;
1456         }
1457
1458         cJSON *vesHeartbeatPeriod = cJSON_GetObjectItemCaseSensitive(notifConfig, "ves-heartbeat-period");
1459         if (!cJSON_IsNumber(vesHeartbeatPeriod))
1460         {
1461                 printf("Configuration JSON is not as expected: ves-heartbeat-period is not an object");
1462                 cJSON_Delete(jsonConfig);
1463                 return SR_ERR_OPERATION_FAILED;
1464         }
1465
1466         //we set the value of the fault-notification-delay-period object
1467         cJSON_SetNumberValue(vesHeartbeatPeriod, period);
1468
1469         //writing the new JSON to the configuration file
1470         stringConfiguration = cJSON_Print(jsonConfig);
1471         writeConfigFile(stringConfiguration);
1472
1473     if (stringConfiguration != NULL)
1474     {
1475         free(stringConfiguration);
1476         stringConfiguration = NULL;
1477     }
1478
1479         cJSON_Delete(jsonConfig);
1480
1481         return SR_ERR_OK;
1482 }
1483
1484 static int add_keystore_entry_odl(char *url, char *credentials)
1485 {
1486         CURLcode res;
1487
1488         curl_easy_reset(curl_odl);
1489         set_curl_common_info_odl();
1490
1491         char url_for_curl[200];
1492         sprintf(url_for_curl, "%s", url);
1493
1494         curl_easy_setopt(curl_odl, CURLOPT_URL, url_for_curl);
1495
1496         char post_data_xml[2000];
1497
1498         sprintf(post_data_xml,
1499                         "<input xmlns=\"urn:opendaylight:netconf:keystore\">"
1500                         "<key-credential>"
1501                         "<key-id>device-key</key-id>"
1502                         "<private-key>MIIEpAIBAAKCAQEAueCQaNQWoNmFK6LKu1p8U8ZWdWg/PvDdLsJyzfzl/Qw4UA68"
1503                         "SfFNaY06zZl8QB9W02nr5kWeeMY0VA3adrPgOlvfx3oWlFbkETnMaN4OT3WTQ0Wt"
1504                         "6jAWZDzVfopwpJPAzRPxACDftIqFGagYcF32hZlVNqqnVdbXh0S0EViweqp/dbG4"
1505                         "VDUHSNVbglc+u4UbEzNIFXMdEFsJZpkynOmSiTsIATqIhb+2srkVgLwhfkC2qkuH"
1506                         "QwAHdubuB07ObM2z01UhyEdDvEYGHwtYAGDBL2TAcsI0oGeVkRyuOkV0QY0UN7UE"
1507                         "FI1yTYw+xZ42HgFx3uGwApCImxhbj69GBYWFqwIDAQABAoIBAQCZN9kR8DGu6V7y"
1508                         "t0Ax68asL8O5B/OKaHWKQ9LqpVrXmikZJOxkbzoGldow/CIFoU+q+Zbwu9aDa65a"
1509                         "0wiP7Hoa4Py3q5XNNUrOQDyU/OYC7cI0I83WS0lJ2zOJGYj8wKae5Z81IeQFKGHK"
1510                         "4lsy1OGPAvPRGh7RjUUgRavA2MCwe07rWRuDb/OJFe4Oh56UMEjwMiNBtMNtncog"
1511                         "j1vr/qgRJdf9tf0zlJmLvUJ9+HSFFV9I/97LJyFhb95gAfHkjdVroLVgT3Cho+4P"
1512                         "WtZaKCIGD0OwfOG2nLV4leXvRUk62/LMlB8NI9+JF7Xm+HCKbaWHNWC7mvWSLV58"
1513                         "Zl4AbUWRAoGBANyJ6SFHFRHSPDY026SsdMzXR0eUxBAK7G70oSBKKhY+O1j0ocLE"
1514                         "jI2krHJBhHbLlnvJVyMUaCUOTS5m0uDw9hgSsAqeSL3hL38kxVZw+KNG9Ouno1Fl"
1515                         "KnE/xXHlPQyeGs/P8nAMzHZxQtEsQdQayJEhK2XXHTsy7Q3MxDisfVJ1AoGBANfD"
1516                         "34gB+OMx6pwj7zk3qWbYXSX8xjCZMR0ciko+h4xeMP2N8B0oyoqC+v1ABMAtJ3wG"
1517                         "sGZd0hV9gwM7OUM3SEwkn6oeg1GemWLcn4rlSmTnZc4aeVwrEWlnSNFX3s4g9l4u"
1518                         "k8Ugu4MVJYqH8HuDQ5Ggl6/QAwPzMSEdCW0O+jOfAoGAIBRbegC5+t6m7Yegz4Ja"
1519                         "dxV1g98K6f58x+MDsQu4tYWV4mmrQgaPH2dtwizvlMwmdpkh+LNWNtWuumowkJHc"
1520                         "akIFo3XExQIFg6wYnGtQb4e5xrGa2xMpKlIJaXjb+YLiCYqJDG2ALFZrTrvuU2kV"
1521                         "9a5qfqTc1qigvNolTM0iaaUCgYApmrZWhnLUdEKV2wP813PNxfioI4afxlpHD8LG"
1522                         "sCn48gymR6E+Lihn7vuwq5B+8fYEH1ISWxLwW+RQUjIneNhy/jjfV8TgjyFqg7or"
1523                         "0Sy4KjpiNI6kLBXOakELRNNMkeSPopGR2E7v5rr3bGD9oAD+aqX1G7oJH/KgPPYd"
1524                         "Vl7+ZwKBgQDcHyWYrimjyUgKaQD2GmoO9wdcJYQ59ke9K+OuGlp4ti5arsi7N1tP"
1525                         "B4f09aeELM2ASIuk8Q/Mx0jQFnm8lzRFXdewgvdPoZW/7VufM9O7dGPOc41cm2Dh"
1526                         "yrTcXx/VmUBb+/fnXVEgCv7gylp/wtdTGHQBQJHR81jFBz0lnLj+gg==</private-key>"
1527                         "<passphrase></passphrase>"
1528                         "</key-credential>"
1529                         "</input>");
1530
1531         printf("Post data:\n%s\n", post_data_xml);
1532
1533         curl_easy_setopt(curl_odl, CURLOPT_POSTFIELDS, post_data_xml);
1534         curl_easy_setopt(curl_odl, CURLOPT_CUSTOMREQUEST, "POST");
1535         curl_easy_setopt(curl_odl, CURLOPT_USERPWD, credentials);
1536
1537         res = curl_easy_perform(curl_odl);
1538         if (res != CURLE_OK)
1539         {
1540                 printf("cURL failed to url=%s\n", url_for_curl);
1541         }
1542
1543         long http_response_code = 0;
1544         curl_easy_getinfo (curl_odl, CURLINFO_RESPONSE_CODE, &http_response_code);
1545         if (http_response_code >= 200 && http_response_code <= 226 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
1546         {
1547                 printf("cURL succeeded to url=%s\n", url_for_curl);
1548         }
1549         else
1550         {
1551                 printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
1552                 return SR_ERR_OPERATION_FAILED;
1553         }
1554
1555         return SR_ERR_OK;
1556 }
1557
1558 static int add_private_key_odl(char *url, char *credentials)
1559 {
1560         CURLcode res;
1561
1562         curl_easy_reset(curl_odl);
1563         set_curl_common_info_odl();
1564
1565         char url_for_curl[200];
1566         sprintf(url_for_curl, "%s", url);
1567
1568         curl_easy_setopt(curl_odl, CURLOPT_URL, url_for_curl);
1569
1570         char post_data_xml[4000];
1571
1572         sprintf(post_data_xml,
1573                         "<input xmlns=\"urn:opendaylight:netconf:keystore\">"
1574                         "<private-key>"
1575                         "<name>device-key</name>"
1576                         "<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>"
1577                         "<certificate-chain>MIIECTCCAvGgAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBjDELMAkGA1UEBhMCQ1oxFjAUBgNVBAgMDVNvdXRoIE1vcmF2aWExDTALBgNVBAcMBEJybm8xDzANBgNVBAoMBkNFU05FVDEMMAoGA1UECwwDVE1DMRMwEQYDVQQDDApleGFtcGxlIENBMSIwIAYJKoZIhvcNAQkBFhNleGFtcGxlY2FAbG9jYWxob3N0MB4XDTE1MDczMDA3MjcxOFoXDTM1MDcyNTA3MjcxOFowgYUxCzAJBgNVBAYTAkNaMRYwFAYDVQQIDA1Tb3V0aCBNb3JhdmlhMQ8wDQYDVQQKDAZDRVNORVQxDDAKBgNVBAsMA1RNQzEXMBUGA1UEAwwOZXhhbXBsZSBjbGllbnQxJjAkBgkqhkiG9w0BCQEWF2V4YW1wbGVjbGllbnRAbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAueCQaNQWoNmFK6LKu1p8U8ZWdWg/PvDdLsJyzfzl/Qw4UA68SfFNaY06zZl8QB9W02nr5kWeeMY0VA3adrPgOlvfx3oWlFbkETnMaN4OT3WTQ0Wt6jAWZDzVfopwpJPAzRPxACDftIqFGagYcF32hZlVNqqnVdbXh0S0EViweqp/dbG4VDUHSNVbglc+u4UbEzNIFXMdEFsJZpkynOmSiTsIATqIhb+2srkVgLwhfkC2qkuHQwAHdubuB07ObM2z01UhyEdDvEYGHwtYAGDBL2TAcsI0oGeVkRyuOkV0QY0UN7UEFI1yTYw+xZ42HgFx3uGwApCImxhbj69GBYWFqwIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUXGpLeLnh2cSDARAVA7KrBxGYpo8wHwYDVR0jBBgwFoAUc1YQIqjZsHVwlea0AB4N+ilNI2gwDQYJKoZIhvcNAQELBQADggEBAJPV3RTXFRtNyOU4rjPpYeBAIAFp2aqGc4t2J1c7oPp/1n+lZvjnwtlJpZHxMM783e2ryDQ6dkvXDf8kpwKlg3U3mkJ3xKkDdWrM4QwghXdCN519aa9qmu0zdFL+jUAaWlQ5tsceOrvbusCcbMqiFGk/QfpHqPv52SVWbYyUx7IX7DE+UjgsLHycfV/tlcx4ZE6soTzl9VdgSL/zmzG3rjsr58J80rXckLgBhvijgBlIAJvWfC7D0vaouvBInSFXymdPVoUDZ30cdGLf+hI/i/TfsEMOinLrXVdkSGNo6FXAHKSvXeB9oFKSzhQ7OPyRyqvEPycUSw/qD6FVr80oDDc=</certificate-chain>"
1578                         "</private-key>"
1579                         "</input>");
1580
1581         printf("Post data:\n%s\n", post_data_xml);
1582
1583         curl_easy_setopt(curl_odl, CURLOPT_POSTFIELDS, post_data_xml);
1584         curl_easy_setopt(curl_odl, CURLOPT_CUSTOMREQUEST, "POST");
1585         curl_easy_setopt(curl_odl, CURLOPT_USERPWD, credentials);
1586
1587         res = curl_easy_perform(curl_odl);
1588         if (res != CURLE_OK)
1589         {
1590                 printf("cURL failed to url=%s\n", url_for_curl);
1591         }
1592
1593         long http_response_code = 0;
1594         curl_easy_getinfo (curl_odl, CURLINFO_RESPONSE_CODE, &http_response_code);
1595         if (http_response_code >= 200 && http_response_code <= 226 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
1596         {
1597                 printf("cURL succeeded to url=%s\n", url_for_curl);
1598         }
1599         else
1600         {
1601                 printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
1602                 return SR_ERR_OPERATION_FAILED;
1603         }
1604
1605         return SR_ERR_OK;
1606 }
1607
1608 static int add_trusted_ca_odl(char *url, char *credentials)
1609 {
1610         CURLcode res;
1611
1612         curl_easy_reset(curl_odl);
1613         set_curl_common_info_odl();
1614
1615         char url_for_curl[200];
1616         sprintf(url_for_curl, "%s", url);
1617
1618         curl_easy_setopt(curl_odl, CURLOPT_URL, url_for_curl);
1619
1620         char post_data_xml[2000];
1621
1622         sprintf(post_data_xml,
1623                         "<input xmlns=\"urn:opendaylight:netconf:keystore\">"
1624                         "<trusted-certificate>"
1625                         "<name>test_trusted_cert</name>"
1626                         "<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>"
1627                         "</trusted-certificate>"
1628                         "</input>");
1629
1630         printf("Post data:\n%s\n", post_data_xml);
1631
1632         curl_easy_setopt(curl_odl, CURLOPT_POSTFIELDS, post_data_xml);
1633         curl_easy_setopt(curl_odl, CURLOPT_CUSTOMREQUEST, "POST");
1634         curl_easy_setopt(curl_odl, CURLOPT_USERPWD, credentials);
1635
1636         res = curl_easy_perform(curl_odl);
1637         if (res != CURLE_OK)
1638         {
1639                 printf("cURL failed to url=%s\n", url_for_curl);
1640         }
1641
1642         long http_response_code = 0;
1643         curl_easy_getinfo (curl_odl, CURLINFO_RESPONSE_CODE, &http_response_code);
1644         if (http_response_code >= 200 && http_response_code <= 226 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
1645         {
1646                 printf("cURL succeeded to url=%s\n", url_for_curl);
1647         }
1648         else
1649         {
1650                 printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
1651                 return SR_ERR_OPERATION_FAILED;
1652         }
1653
1654         return SR_ERR_OK;
1655 }
1656
1657 int add_key_pair_to_odl(controller_t *controller_list, int controller_list_size)
1658 {
1659         int rc = SR_ERR_OK;
1660
1661         rc = add_keystore_entry_odl(controller_list[0].url_for_keystore_add, controller_list[0].credentials);
1662         if (rc != SR_ERR_OK)
1663         {
1664                 printf("Failed to add keystore entry to ODL.\n");
1665         }
1666
1667         rc = add_private_key_odl(controller_list[0].url_for_private_key_add, controller_list[0].credentials);
1668         if (rc != SR_ERR_OK)
1669         {
1670                 printf("Failed to add private key entry to ODL.\n");
1671         }
1672
1673         rc = add_trusted_ca_odl(controller_list[0].url_for_trusted_ca_add, controller_list[0].credentials);
1674         if (rc != SR_ERR_OK)
1675         {
1676                 printf("Failed to add trusted CA entry to ODL.\n");
1677         }
1678
1679         return SR_ERR_OK;
1680 }
1681
1682 int ves_ip_changed(char *new_ip)
1683 {
1684     char *stringConfiguration = readConfigFileInString();
1685
1686     if (stringConfiguration == NULL)
1687     {
1688         printf("Could not read configuration file!\n");
1689         return SR_ERR_OPERATION_FAILED;
1690     }
1691
1692     cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1693     if (jsonConfig == NULL)
1694     {
1695         free(stringConfiguration);
1696         const char *error_ptr = cJSON_GetErrorPtr();
1697         if (error_ptr != NULL)
1698         {
1699             fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
1700         }
1701         return SR_ERR_OPERATION_FAILED;
1702     }
1703     //we don't need the string anymore
1704     free(stringConfiguration);
1705     stringConfiguration = NULL;
1706
1707     cJSON *vesDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "ves-endpoint-details");
1708     if (!cJSON_IsObject(vesDetails))
1709     {
1710         printf("Configuration JSON is not as expected: ves-endpoint-details is not an object");
1711         cJSON_Delete(jsonConfig);
1712         return SR_ERR_OPERATION_FAILED;
1713     }
1714
1715     cJSON *vesIp = cJSON_GetObjectItemCaseSensitive(vesDetails, "ves-endpoint-ip");
1716     if (!cJSON_IsString(vesIp))
1717     {
1718         printf("Configuration JSON is not as expected: ves-endpoint-ip is not a string");
1719         cJSON_Delete(jsonConfig);
1720         return SR_ERR_OPERATION_FAILED;
1721     }
1722
1723     //we set the value of the fault-notification-delay-period object
1724     cJSON_ReplaceItemInObject(vesDetails, "ves-endpoint-ip", cJSON_CreateString(new_ip));
1725
1726     //writing the new JSON to the configuration file
1727     stringConfiguration = cJSON_Print(jsonConfig);
1728     writeConfigFile(stringConfiguration);
1729
1730     if (stringConfiguration != NULL)
1731     {
1732         free(stringConfiguration);
1733         stringConfiguration = NULL;
1734     }
1735
1736     cJSON_Delete(jsonConfig);
1737
1738     return SR_ERR_OK;
1739 }
1740
1741 int ves_port_changed(int new_port)
1742 {
1743         char *stringConfiguration = readConfigFileInString();
1744
1745         if (stringConfiguration == NULL)
1746         {
1747                 printf("Could not read configuration file!\n");
1748                 return SR_ERR_OPERATION_FAILED;
1749         }
1750
1751         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1752         if (jsonConfig == NULL)
1753         {
1754                 free(stringConfiguration);
1755                 const char *error_ptr = cJSON_GetErrorPtr();
1756                 if (error_ptr != NULL)
1757                 {
1758                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
1759                 }
1760                 return SR_ERR_OPERATION_FAILED;
1761         }
1762         //we don't need the string anymore
1763         free(stringConfiguration);
1764         stringConfiguration = NULL;
1765
1766         cJSON *vesDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "ves-endpoint-details");
1767         if (!cJSON_IsObject(vesDetails))
1768         {
1769                 printf("Configuration JSON is not as expected: ves-endpoint-details is not an object");
1770                 cJSON_Delete(jsonConfig);
1771                 return SR_ERR_OPERATION_FAILED;
1772         }
1773
1774         cJSON *vesPort = cJSON_GetObjectItemCaseSensitive(vesDetails, "ves-endpoint-port");
1775         if (!cJSON_IsNumber(vesPort))
1776         {
1777                 printf("Configuration JSON is not as expected: ves-endpoint-port is not a number.");
1778                 cJSON_Delete(jsonConfig);
1779                 return SR_ERR_OPERATION_FAILED;
1780         }
1781
1782         //we set the value of the fault-notification-delay-period object
1783         cJSON_SetNumberValue(vesPort, new_port);
1784
1785         //writing the new JSON to the configuration file
1786         stringConfiguration = cJSON_Print(jsonConfig);
1787         writeConfigFile(stringConfiguration);
1788
1789     if (stringConfiguration != NULL)
1790     {
1791         free(stringConfiguration);
1792         stringConfiguration = NULL;
1793     }
1794
1795         cJSON_Delete(jsonConfig);
1796
1797         return SR_ERR_OK;
1798 }
1799
1800 int ves_username_changed(char *new_username)
1801 {
1802     char *stringConfiguration = readConfigFileInString();
1803
1804     if (stringConfiguration == NULL)
1805     {
1806         printf("Could not read configuration file!\n");
1807         return SR_ERR_OPERATION_FAILED;
1808     }
1809
1810     cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1811     if (jsonConfig == NULL)
1812     {
1813         free(stringConfiguration);
1814         const char *error_ptr = cJSON_GetErrorPtr();
1815         if (error_ptr != NULL)
1816         {
1817             fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
1818         }
1819         return SR_ERR_OPERATION_FAILED;
1820     }
1821     //we don't need the string anymore
1822     free(stringConfiguration);
1823     stringConfiguration = NULL;
1824
1825     cJSON *vesDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "ves-endpoint-details");
1826     if (!cJSON_IsObject(vesDetails))
1827     {
1828         printf("Configuration JSON is not as expected: ves-endpoint-details is not an object");
1829         cJSON_Delete(jsonConfig);
1830         return SR_ERR_OPERATION_FAILED;
1831     }
1832
1833     cJSON *vesUsername = cJSON_GetObjectItemCaseSensitive(vesDetails, "ves-endpoint-username");
1834     if (!cJSON_IsString(vesUsername))
1835     {
1836         printf("Configuration JSON is not as expected: ves-endpoint-username is not a string");
1837         cJSON_Delete(jsonConfig);
1838         return SR_ERR_OPERATION_FAILED;
1839     }
1840
1841     //we set the value of the fault-notification-delay-period object
1842     cJSON_ReplaceItemInObject(vesDetails, "ves-endpoint-username", cJSON_CreateString(new_username));
1843
1844     //writing the new JSON to the configuration file
1845     stringConfiguration = cJSON_Print(jsonConfig);
1846     writeConfigFile(stringConfiguration);
1847
1848     if (stringConfiguration != NULL)
1849     {
1850         free(stringConfiguration);
1851         stringConfiguration = NULL;
1852     }
1853
1854     cJSON_Delete(jsonConfig);
1855
1856     return SR_ERR_OK;
1857 }
1858
1859 int ves_password_changed(char *new_password)
1860 {
1861     char *stringConfiguration = readConfigFileInString();
1862
1863     if (stringConfiguration == NULL)
1864     {
1865         printf("Could not read configuration file!\n");
1866         return SR_ERR_OPERATION_FAILED;
1867     }
1868
1869     cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1870     if (jsonConfig == NULL)
1871     {
1872         free(stringConfiguration);
1873         const char *error_ptr = cJSON_GetErrorPtr();
1874         if (error_ptr != NULL)
1875         {
1876             fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
1877         }
1878         return SR_ERR_OPERATION_FAILED;
1879     }
1880     //we don't need the string anymore
1881     free(stringConfiguration);
1882     stringConfiguration = NULL;
1883
1884     cJSON *vesDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "ves-endpoint-details");
1885     if (!cJSON_IsObject(vesDetails))
1886     {
1887         printf("Configuration JSON is not as expected: ves-endpoint-details is not an object");
1888         cJSON_Delete(jsonConfig);
1889         return SR_ERR_OPERATION_FAILED;
1890     }
1891
1892     cJSON *vesPassword = cJSON_GetObjectItemCaseSensitive(vesDetails, "ves-endpoint-password");
1893     if (!cJSON_IsString(vesPassword))
1894     {
1895         printf("Configuration JSON is not as expected: ves-endpoint-password is not a string");
1896         cJSON_Delete(jsonConfig);
1897         return SR_ERR_OPERATION_FAILED;
1898     }
1899
1900     //we set the value of the fault-notification-delay-period object
1901     cJSON_ReplaceItemInObject(vesDetails, "ves-endpoint-password", cJSON_CreateString(new_password));
1902
1903     //writing the new JSON to the configuration file
1904     stringConfiguration = cJSON_Print(jsonConfig);
1905     writeConfigFile(stringConfiguration);
1906
1907     if (stringConfiguration != NULL)
1908     {
1909         free(stringConfiguration);
1910         stringConfiguration = NULL;
1911     }
1912
1913     cJSON_Delete(jsonConfig);
1914
1915     return SR_ERR_OK;
1916 }
1917
1918 int ves_auth_method_changed(char *new_auth_method)
1919 {
1920     char *stringConfiguration = readConfigFileInString();
1921
1922     if (stringConfiguration == NULL)
1923     {
1924         printf("Could not read configuration file!\n");
1925         return SR_ERR_OPERATION_FAILED;
1926     }
1927
1928     cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1929     if (jsonConfig == NULL)
1930     {
1931         free(stringConfiguration);
1932         const char *error_ptr = cJSON_GetErrorPtr();
1933         if (error_ptr != NULL)
1934         {
1935             fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
1936         }
1937         return SR_ERR_OPERATION_FAILED;
1938     }
1939     //we don't need the string anymore
1940     free(stringConfiguration);
1941     stringConfiguration = NULL;
1942
1943     cJSON *vesDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "ves-endpoint-details");
1944     if (!cJSON_IsObject(vesDetails))
1945     {
1946         printf("Configuration JSON is not as expected: ves-endpoint-details is not an object");
1947         cJSON_Delete(jsonConfig);
1948         return SR_ERR_OPERATION_FAILED;
1949     }
1950
1951     cJSON *vesAuthMethod = cJSON_GetObjectItemCaseSensitive(vesDetails, "ves-endpoint-auth-method");
1952     if (!cJSON_IsString(vesAuthMethod))
1953     {
1954         printf("Configuration JSON is not as expected: ves-endpoint-auth-method is not a string");
1955         cJSON_Delete(jsonConfig);
1956         return SR_ERR_OPERATION_FAILED;
1957     }
1958
1959     //we set the value of the fault-notification-delay-period object
1960     cJSON_ReplaceItemInObject(vesDetails, "ves-endpoint-auth-method", cJSON_CreateString(new_auth_method));
1961
1962     //writing the new JSON to the configuration file
1963     stringConfiguration = cJSON_Print(jsonConfig);
1964     writeConfigFile(stringConfiguration);
1965
1966     if (stringConfiguration != NULL)
1967     {
1968         free(stringConfiguration);
1969         stringConfiguration = NULL;
1970     }
1971
1972     cJSON_Delete(jsonConfig);
1973
1974     return SR_ERR_OK;
1975 }
1976
1977 int ves_registration_changed(cJSON_bool new_bool)
1978 {
1979         char *stringConfiguration = readConfigFileInString();
1980
1981         if (stringConfiguration == NULL)
1982         {
1983                 printf("Could not read configuration file!\n");
1984                 return SR_ERR_OPERATION_FAILED;
1985         }
1986
1987         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1988         if (jsonConfig == NULL)
1989         {
1990                 free(stringConfiguration);
1991                 const char *error_ptr = cJSON_GetErrorPtr();
1992                 if (error_ptr != NULL)
1993                 {
1994                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
1995                 }
1996                 return SR_ERR_OPERATION_FAILED;
1997         }
1998         //we don't need the string anymore
1999         free(stringConfiguration);
2000         stringConfiguration = NULL;
2001
2002         cJSON *vesDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "ves-endpoint-details");
2003         if (!cJSON_IsObject(vesDetails))
2004         {
2005                 printf("Configuration JSON is not as expected: ves-endpoint-details is not an object");
2006                 cJSON_Delete(jsonConfig);
2007                 return SR_ERR_OPERATION_FAILED;
2008         }
2009
2010         cJSON *vesRegistration = cJSON_GetObjectItemCaseSensitive(vesDetails, "ves-registration");
2011         if (!cJSON_IsBool(vesRegistration))
2012         {
2013                 printf("Configuration JSON is not as expected: ves-registration is not a bool.");
2014                 cJSON_Delete(jsonConfig);
2015                 return SR_ERR_OPERATION_FAILED;
2016         }
2017
2018         //we set the value of the ves-registration object
2019         cJSON_ReplaceItemInObject(vesDetails, "ves-registration", cJSON_CreateBool(new_bool));
2020
2021         //writing the new JSON to the configuration file
2022         stringConfiguration = cJSON_Print(jsonConfig);
2023         writeConfigFile(stringConfiguration);
2024
2025     if (stringConfiguration != NULL)
2026     {
2027         free(stringConfiguration);
2028         stringConfiguration = NULL;
2029     }
2030
2031         cJSON_Delete(jsonConfig);
2032
2033         return SR_ERR_OK;
2034 }
2035
2036 int is_netconf_available_changed(cJSON_bool new_bool)
2037 {
2038         char *stringConfiguration = readConfigFileInString();
2039
2040         if (stringConfiguration == NULL)
2041         {
2042                 printf("Could not read configuration file!\n");
2043                 return SR_ERR_OPERATION_FAILED;
2044         }
2045
2046         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
2047         if (jsonConfig == NULL)
2048         {
2049                 free(stringConfiguration);
2050                 const char *error_ptr = cJSON_GetErrorPtr();
2051                 if (error_ptr != NULL)
2052                 {
2053                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
2054                 }
2055                 return SR_ERR_OPERATION_FAILED;
2056         }
2057         //we don't need the string anymore
2058         free(stringConfiguration);
2059         stringConfiguration = NULL;
2060
2061         cJSON *notifConfig = cJSON_GetObjectItemCaseSensitive(jsonConfig, "notification-config");
2062         if (!cJSON_IsObject(notifConfig))
2063         {
2064                 printf("Configuration JSON is not as expected: notification-config is not an object");
2065                 cJSON_Delete(jsonConfig);
2066                 return SR_ERR_OPERATION_FAILED;
2067         }
2068
2069         cJSON *isNetconfAvailable = cJSON_GetObjectItemCaseSensitive(notifConfig, "is-netconf-available");
2070         if (!cJSON_IsBool(isNetconfAvailable))
2071         {
2072                 printf("Configuration JSON is not as expected: is-netconf-available is not a bool.");
2073                 cJSON_Delete(jsonConfig);
2074                 return SR_ERR_OPERATION_FAILED;
2075         }
2076
2077         //we set the value of the ves-registration object
2078         cJSON_ReplaceItemInObject(notifConfig, "is-netconf-available", cJSON_CreateBool(new_bool));
2079
2080         //writing the new JSON to the configuration file
2081         stringConfiguration = cJSON_Print(jsonConfig);
2082         writeConfigFile(stringConfiguration);
2083
2084     if (stringConfiguration != NULL)
2085     {
2086         free(stringConfiguration);
2087         stringConfiguration = NULL;
2088     }
2089
2090         cJSON_Delete(jsonConfig);
2091
2092         return SR_ERR_OK;
2093 }
2094
2095 int is_ves_available_changed(cJSON_bool new_bool)
2096 {
2097         char *stringConfiguration = readConfigFileInString();
2098
2099         if (stringConfiguration == NULL)
2100         {
2101                 printf("Could not read configuration file!\n");
2102                 return SR_ERR_OPERATION_FAILED;
2103         }
2104
2105         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
2106         if (jsonConfig == NULL)
2107         {
2108                 free(stringConfiguration);
2109                 const char *error_ptr = cJSON_GetErrorPtr();
2110                 if (error_ptr != NULL)
2111                 {
2112                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
2113                 }
2114                 return SR_ERR_OPERATION_FAILED;
2115         }
2116         //we don't need the string anymore
2117         free(stringConfiguration);
2118         stringConfiguration = NULL;
2119
2120         cJSON *notifConfig = cJSON_GetObjectItemCaseSensitive(jsonConfig, "notification-config");
2121         if (!cJSON_IsObject(notifConfig))
2122         {
2123                 printf("Configuration JSON is not as expected: notification-config is not an object");
2124                 cJSON_Delete(jsonConfig);
2125                 return SR_ERR_OPERATION_FAILED;
2126         }
2127
2128         cJSON *isVesAvailable = cJSON_GetObjectItemCaseSensitive(notifConfig, "is-ves-available");
2129         if (!cJSON_IsBool(isVesAvailable))
2130         {
2131                 printf("Configuration JSON is not as expected: is-ves-available is not a bool.");
2132                 cJSON_Delete(jsonConfig);
2133                 return SR_ERR_OPERATION_FAILED;
2134         }
2135
2136         //we set the value of the ves-registration object
2137         cJSON_ReplaceItemInObject(notifConfig, "is-ves-available", cJSON_CreateBool(new_bool));
2138
2139         //writing the new JSON to the configuration file
2140         stringConfiguration = cJSON_Print(jsonConfig);
2141         writeConfigFile(stringConfiguration);
2142
2143     if (stringConfiguration != NULL)
2144     {
2145         free(stringConfiguration);
2146         stringConfiguration = NULL;
2147     }
2148
2149         cJSON_Delete(jsonConfig);
2150
2151         return SR_ERR_OK;
2152 }
2153
2154     int ssh_connections_changed(int number)
2155     {
2156     char *stringConfiguration = readConfigFileInString();
2157
2158     if (stringConfiguration == NULL)
2159     {
2160         printf("Could not read configuration file!\n");
2161         return SR_ERR_OPERATION_FAILED;
2162     }
2163
2164     cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
2165     if (jsonConfig == NULL)
2166     {
2167         free(stringConfiguration);
2168         const char *error_ptr = cJSON_GetErrorPtr();
2169         if (error_ptr != NULL)
2170         {
2171             fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
2172         }
2173         return SR_ERR_OPERATION_FAILED;
2174     }
2175     //we don't need the string anymore
2176     free(stringConfiguration);
2177     stringConfiguration = NULL;
2178
2179     cJSON *sshConnections = cJSON_GetObjectItemCaseSensitive(jsonConfig, "ssh-connections");
2180     if (!cJSON_IsNumber(sshConnections))
2181     {
2182         printf("Configuration JSON is not as expected: ssh-connections is not an object");
2183         cJSON_Delete(jsonConfig);
2184         return SR_ERR_OPERATION_FAILED;
2185     }
2186
2187     //we set the value of the ssh-connections object
2188     cJSON_SetNumberValue(sshConnections, number);
2189
2190     //writing the new JSON to the configuration file
2191     stringConfiguration = cJSON_Print(jsonConfig);
2192     writeConfigFile(stringConfiguration);
2193
2194     if (stringConfiguration != NULL)
2195     {
2196         free(stringConfiguration);
2197         stringConfiguration = NULL;
2198     }
2199
2200     cJSON_Delete(jsonConfig);
2201
2202     return SR_ERR_OK;
2203 }
2204
2205 int tls_connections_changed(int number)
2206     {
2207     char *stringConfiguration = readConfigFileInString();
2208
2209     if (stringConfiguration == NULL)
2210     {
2211         printf("Could not read configuration file!\n");
2212         return SR_ERR_OPERATION_FAILED;
2213     }
2214
2215     cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
2216     if (jsonConfig == NULL)
2217     {
2218         free(stringConfiguration);
2219         const char *error_ptr = cJSON_GetErrorPtr();
2220         if (error_ptr != NULL)
2221         {
2222             fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
2223         }
2224         return SR_ERR_OPERATION_FAILED;
2225     }
2226     //we don't need the string anymore
2227     free(stringConfiguration);
2228     stringConfiguration = NULL;
2229
2230     cJSON *tlsConnections = cJSON_GetObjectItemCaseSensitive(jsonConfig, "tls-connections");
2231     if (!cJSON_IsNumber(tlsConnections))
2232     {
2233         printf("Configuration JSON is not as expected: tls-connections is not an object");
2234         cJSON_Delete(jsonConfig);
2235         return SR_ERR_OPERATION_FAILED;
2236     }
2237
2238     //we set the value of the tls-connections object
2239     cJSON_SetNumberValue(tlsConnections, number);
2240
2241     //writing the new JSON to the configuration file
2242     stringConfiguration = cJSON_Print(jsonConfig);
2243     writeConfigFile(stringConfiguration);
2244
2245     if (stringConfiguration != NULL)
2246     {
2247         free(stringConfiguration);
2248         stringConfiguration = NULL;
2249     }
2250
2251     cJSON_Delete(jsonConfig);
2252
2253     return SR_ERR_OK;
2254 }
2255
2256 /*
2257 curl -X POST -H 'Content-Type: application/json' -i http://localhost:5000/extend-ports --data '{"number-of-ports":12}'
2258 */
2259 int send_k8s_extend_port(void)
2260 {
2261     int num_of_ports = getSshConnectionsFromConfigJson() + getTlsConnectionsFromConfigJson();
2262
2263     CURLcode res;
2264
2265     curl_easy_reset(curl_k8s);
2266     set_curl_common_info_k8s();
2267
2268     char url_for_curl[100];
2269     sprintf(url_for_curl, "http://localhost:5000/extend-ports");
2270
2271     curl_easy_setopt(curl_k8s, CURLOPT_URL, url_for_curl);
2272
2273     char post_data_json[1500];
2274
2275     sprintf(post_data_json,
2276             "{\"number-of-ports\":%d}",
2277             num_of_ports);
2278
2279     printf("Post data:\n%s\n", post_data_json);
2280
2281     curl_easy_setopt(curl_k8s, CURLOPT_POSTFIELDS, post_data_json);
2282     curl_easy_setopt(curl_k8s, CURLOPT_CUSTOMREQUEST, "POST");
2283
2284     res = curl_easy_perform(curl_k8s);
2285     if (res != CURLE_OK)
2286     {
2287         printf("cURL failed to url=%s\n", url_for_curl);
2288     }
2289
2290     long http_response_code = 0;
2291     curl_easy_getinfo (curl_k8s, CURLINFO_RESPONSE_CODE, &http_response_code);
2292     if (http_response_code >= 200 && http_response_code <= 226 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
2293     {
2294         printf("cURL succeeded to url=%s\n", url_for_curl);
2295     }
2296     else
2297     {
2298         printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
2299         return SR_ERR_OPERATION_FAILED;
2300     }
2301
2302     return SR_ERR_OK;
2303 }
2304
2305 /*
2306 curl -X POST -H 'Content-Type: application/json' -i http://localhost:5000/scale --data '{"simulatedDevices":2}'
2307 */
2308 int send_k8s_scale(int number_of_devices)
2309 {
2310     CURLcode res;
2311
2312     curl_easy_reset(curl_k8s);
2313     set_curl_common_info_k8s();
2314
2315     char url_for_curl[100];
2316     sprintf(url_for_curl, "http://localhost:5000/scale");
2317
2318     curl_easy_setopt(curl_k8s, CURLOPT_URL, url_for_curl);
2319
2320     char post_data_json[1500];
2321
2322     sprintf(post_data_json,
2323             "{\"simulatedDevices\":%d}",
2324             number_of_devices);
2325
2326     printf("Post data:\n%s\n", post_data_json);
2327
2328     curl_easy_setopt(curl_k8s, CURLOPT_POSTFIELDS, post_data_json);
2329     curl_easy_setopt(curl_k8s, CURLOPT_CUSTOMREQUEST, "POST");
2330
2331     res = curl_easy_perform(curl_k8s);
2332     if (res != CURLE_OK)
2333     {
2334         printf("cURL failed to url=%s\n", url_for_curl);
2335     }
2336
2337     long http_response_code = 0;
2338     curl_easy_getinfo (curl_k8s, CURLINFO_RESPONSE_CODE, &http_response_code);
2339     if (http_response_code >= 200 && http_response_code <= 226 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
2340     {
2341         printf("cURL succeeded to url=%s\n", url_for_curl);
2342     }
2343     else
2344     {
2345         printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
2346         return SR_ERR_OPERATION_FAILED;
2347     }
2348
2349     return SR_ERR_OK;
2350 }
2351
2352 int controller_ip_changed(char *new_ip)
2353 {
2354         char *stringConfiguration = readConfigFileInString();
2355
2356         if (stringConfiguration == NULL)
2357         {
2358                 printf("Could not read configuration file!\n");
2359                 return SR_ERR_OPERATION_FAILED;
2360         }
2361
2362         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
2363         if (jsonConfig == NULL)
2364         {
2365                 free(stringConfiguration);
2366                 const char *error_ptr = cJSON_GetErrorPtr();
2367                 if (error_ptr != NULL)
2368                 {
2369                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
2370                 }
2371                 return SR_ERR_OPERATION_FAILED;
2372         }
2373         //we don't need the string anymore
2374         free(stringConfiguration);
2375         stringConfiguration = NULL;
2376
2377         cJSON *controllerDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "controller-details");
2378         if (!cJSON_IsObject(controllerDetails))
2379         {
2380                 printf("Configuration JSON is not as expected: controller-details is not an object");
2381                 cJSON_Delete(jsonConfig);
2382                 return SR_ERR_OPERATION_FAILED;
2383         }
2384
2385         cJSON *controllerIp = cJSON_GetObjectItemCaseSensitive(controllerDetails, "controller-ip");
2386         if (!cJSON_IsString(controllerIp))
2387         {
2388                 printf("Configuration JSON is not as expected: controller-ip is not a string");
2389                 cJSON_Delete(jsonConfig);
2390                 return SR_ERR_OPERATION_FAILED;
2391         }
2392
2393         //we set the value of the fault-notification-delay-period object
2394         cJSON_ReplaceItemInObject(controllerDetails, "controller-ip", cJSON_CreateString(new_ip));
2395
2396         //writing the new JSON to the configuration file
2397         stringConfiguration = cJSON_Print(jsonConfig);
2398         writeConfigFile(stringConfiguration);
2399
2400     if (stringConfiguration != NULL)
2401     {
2402         free(stringConfiguration);
2403         stringConfiguration = NULL;
2404     }
2405
2406         cJSON_Delete(jsonConfig);
2407
2408         return SR_ERR_OK;
2409 }
2410
2411 int controller_port_changed(int new_port)
2412 {
2413         char *stringConfiguration = readConfigFileInString();
2414
2415         if (stringConfiguration == NULL)
2416         {
2417                 printf("Could not read configuration file!\n");
2418                 return SR_ERR_OPERATION_FAILED;
2419         }
2420
2421         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
2422         if (jsonConfig == NULL)
2423         {
2424                 free(stringConfiguration);
2425                 const char *error_ptr = cJSON_GetErrorPtr();
2426                 if (error_ptr != NULL)
2427                 {
2428                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
2429                 }
2430                 return SR_ERR_OPERATION_FAILED;
2431         }
2432         //we don't need the string anymore
2433         free(stringConfiguration);
2434         stringConfiguration = NULL;
2435
2436         cJSON *controllerDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "controller-details");
2437         if (!cJSON_IsObject(controllerDetails))
2438         {
2439                 printf("Configuration JSON is not as expected: controller-details is not an object");
2440                 cJSON_Delete(jsonConfig);
2441                 return SR_ERR_OPERATION_FAILED;
2442         }
2443
2444         cJSON *controllerPort = cJSON_GetObjectItemCaseSensitive(controllerDetails, "controller-port");
2445         if (!cJSON_IsNumber(controllerPort))
2446         {
2447                 printf("Configuration JSON is not as expected: controller-port is not a number.");
2448                 cJSON_Delete(jsonConfig);
2449                 return SR_ERR_OPERATION_FAILED;
2450         }
2451
2452         //we set the value of the fault-notification-delay-period object
2453         cJSON_SetNumberValue(controllerPort, new_port);
2454
2455         //writing the new JSON to the configuration file
2456         stringConfiguration = cJSON_Print(jsonConfig);
2457         writeConfigFile(stringConfiguration);
2458
2459     if (stringConfiguration != NULL)
2460     {
2461         free(stringConfiguration);
2462         stringConfiguration = NULL;
2463     }
2464
2465         cJSON_Delete(jsonConfig);
2466
2467         return SR_ERR_OK;
2468 }
2469
2470 int controller_netconf_call_home_port_changed(int new_port)
2471 {
2472         char *stringConfiguration = readConfigFileInString();
2473
2474         if (stringConfiguration == NULL)
2475         {
2476                 printf("Could not read configuration file!\n");
2477                 return SR_ERR_OPERATION_FAILED;
2478         }
2479
2480         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
2481         if (jsonConfig == NULL)
2482         {
2483                 free(stringConfiguration);
2484                 const char *error_ptr = cJSON_GetErrorPtr();
2485                 if (error_ptr != NULL)
2486                 {
2487                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
2488                 }
2489                 return SR_ERR_OPERATION_FAILED;
2490         }
2491         //we don't need the string anymore
2492         free(stringConfiguration);
2493         stringConfiguration = NULL;
2494
2495         cJSON *controllerDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "controller-details");
2496         if (!cJSON_IsObject(controllerDetails))
2497         {
2498                 printf("Configuration JSON is not as expected: controller-details is not an object");
2499                 cJSON_Delete(jsonConfig);
2500                 return SR_ERR_OPERATION_FAILED;
2501         }
2502
2503         cJSON *netconfCallHomePort = cJSON_GetObjectItemCaseSensitive(controllerDetails, "netconf-call-home-port");
2504         if (!cJSON_IsNumber(netconfCallHomePort))
2505         {
2506                 printf("Configuration JSON is not as expected: netconf-call-home-port is not a number.");
2507                 cJSON_Delete(jsonConfig);
2508                 return SR_ERR_OPERATION_FAILED;
2509         }
2510
2511         //we set the value of the fault-notification-delay-period object
2512         cJSON_SetNumberValue(netconfCallHomePort, new_port);
2513
2514         //writing the new JSON to the configuration file
2515         stringConfiguration = cJSON_Print(jsonConfig);
2516         writeConfigFile(stringConfiguration);
2517
2518     if (stringConfiguration != NULL)
2519     {
2520         free(stringConfiguration);
2521         stringConfiguration = NULL;
2522     }
2523
2524         cJSON_Delete(jsonConfig);
2525
2526         return SR_ERR_OK;
2527 }
2528
2529 int controller_username_changed(char *new_username)
2530 {
2531         char *stringConfiguration = readConfigFileInString();
2532
2533         if (stringConfiguration == NULL)
2534         {
2535                 printf("Could not read configuration file!\n");
2536                 return SR_ERR_OPERATION_FAILED;
2537         }
2538
2539         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
2540         if (jsonConfig == NULL)
2541         {
2542                 free(stringConfiguration);
2543                 const char *error_ptr = cJSON_GetErrorPtr();
2544                 if (error_ptr != NULL)
2545                 {
2546                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
2547                 }
2548                 return SR_ERR_OPERATION_FAILED;
2549         }
2550         //we don't need the string anymore
2551         free(stringConfiguration);
2552         stringConfiguration = NULL;
2553
2554         cJSON *controllerDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "controller-details");
2555         if (!cJSON_IsObject(controllerDetails))
2556         {
2557                 printf("Configuration JSON is not as expected: controller-details is not an object");
2558                 cJSON_Delete(jsonConfig);
2559                 return SR_ERR_OPERATION_FAILED;
2560         }
2561
2562         cJSON *controllerUsername = cJSON_GetObjectItemCaseSensitive(controllerDetails, "controller-username");
2563         if (!cJSON_IsString(controllerUsername))
2564         {
2565                 printf("Configuration JSON is not as expected: controller-username is not a string");
2566                 cJSON_Delete(jsonConfig);
2567                 return SR_ERR_OPERATION_FAILED;
2568         }
2569
2570         //we set the value of the fault-notification-delay-period object
2571         cJSON_ReplaceItemInObject(controllerDetails, "controller-username", cJSON_CreateString(new_username));
2572
2573         //writing the new JSON to the configuration file
2574         stringConfiguration = cJSON_Print(jsonConfig);
2575         writeConfigFile(stringConfiguration);
2576
2577     if (stringConfiguration != NULL)
2578     {
2579         free(stringConfiguration);
2580         stringConfiguration = NULL;
2581     }
2582
2583         cJSON_Delete(jsonConfig);
2584
2585         return SR_ERR_OK;
2586 }
2587
2588 int controller_password_changed(char *new_password)
2589 {
2590         char *stringConfiguration = readConfigFileInString();
2591
2592         if (stringConfiguration == NULL)
2593         {
2594                 printf("Could not read configuration file!\n");
2595                 return SR_ERR_OPERATION_FAILED;
2596         }
2597
2598         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
2599         if (jsonConfig == NULL)
2600         {
2601                 free(stringConfiguration);
2602                 const char *error_ptr = cJSON_GetErrorPtr();
2603                 if (error_ptr != NULL)
2604                 {
2605                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
2606                 }
2607                 return SR_ERR_OPERATION_FAILED;
2608         }
2609         //we don't need the string anymore
2610         free(stringConfiguration);
2611         stringConfiguration = NULL;
2612
2613         cJSON *controllerDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "controller-details");
2614         if (!cJSON_IsObject(controllerDetails))
2615         {
2616                 printf("Configuration JSON is not as expected: controller-details is not an object");
2617                 cJSON_Delete(jsonConfig);
2618                 return SR_ERR_OPERATION_FAILED;
2619         }
2620
2621         cJSON *controllerPassword = cJSON_GetObjectItemCaseSensitive(controllerDetails, "controller-password");
2622         if (!cJSON_IsString(controllerPassword))
2623         {
2624                 printf("Configuration JSON is not as expected: controller-password is not a string");
2625                 cJSON_Delete(jsonConfig);
2626                 return SR_ERR_OPERATION_FAILED;
2627         }
2628
2629         //we set the value of the fault-notification-delay-period object
2630         cJSON_ReplaceItemInObject(controllerDetails, "controller-password", cJSON_CreateString(new_password));
2631
2632         //writing the new JSON to the configuration file
2633         stringConfiguration = cJSON_Print(jsonConfig);
2634         writeConfigFile(stringConfiguration);
2635
2636     if (stringConfiguration != NULL)
2637     {
2638         free(stringConfiguration);
2639         stringConfiguration = NULL;
2640     }
2641
2642         cJSON_Delete(jsonConfig);
2643
2644         return SR_ERR_OK;
2645 }
2646
2647 int netconf_call_home_changed(cJSON_bool new_bool)
2648 {
2649         char *stringConfiguration = readConfigFileInString();
2650
2651         if (stringConfiguration == NULL)
2652         {
2653                 printf("Could not read configuration file!\n");
2654                 return SR_ERR_OPERATION_FAILED;
2655         }
2656
2657         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
2658         if (jsonConfig == NULL)
2659         {
2660                 free(stringConfiguration);
2661                 const char *error_ptr = cJSON_GetErrorPtr();
2662                 if (error_ptr != NULL)
2663                 {
2664                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
2665                 }
2666                 return SR_ERR_OPERATION_FAILED;
2667         }
2668         //we don't need the string anymore
2669         free(stringConfiguration);
2670         stringConfiguration = NULL;
2671
2672         cJSON *netconfCallHome = cJSON_GetObjectItemCaseSensitive(jsonConfig, "netconf-call-home");
2673         if (!cJSON_IsBool(netconfCallHome))
2674         {
2675                 printf("Configuration JSON is not as expected: netconf-call-home is not a bool.");
2676                 cJSON_Delete(jsonConfig);
2677                 return SR_ERR_OPERATION_FAILED;
2678         }
2679
2680         //we set the value of the ves-registration object
2681         cJSON_ReplaceItemInObject(jsonConfig, "netconf-call-home", cJSON_CreateBool(new_bool));
2682
2683         //writing the new JSON to the configuration file
2684         stringConfiguration = cJSON_Print(jsonConfig);
2685         writeConfigFile(stringConfiguration);
2686
2687     if (stringConfiguration != NULL)
2688     {
2689         free(stringConfiguration);
2690         stringConfiguration = NULL;
2691     }
2692
2693         cJSON_Delete(jsonConfig);
2694
2695         return SR_ERR_OK;
2696 }
2697
2698 static int start_device_notification(char *exec_id)
2699 {
2700     struct MemoryStruct curl_response_mem;
2701
2702     curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
2703     curl_response_mem.size = 0;    /* no data at this point */
2704
2705     CURLcode res;
2706
2707     curl_easy_reset(curl);
2708     set_curl_common_info();
2709
2710     char url[500];
2711     sprintf(url, "http:/v%s/exec/%s/start", getenv("DOCKER_ENGINE_VERSION"), exec_id);
2712
2713     curl_easy_setopt(curl, CURLOPT_URL, url);
2714
2715     cJSON *postDataJson = cJSON_CreateObject();
2716
2717     if (cJSON_AddFalseToObject(postDataJson, "Detach") == NULL)
2718     {
2719         printf("Could not create JSON object: Detach\n");
2720         return SR_ERR_OPERATION_FAILED;
2721     }
2722
2723     if (cJSON_AddFalseToObject(postDataJson, "Tty") == NULL)
2724     {
2725         printf("Could not create JSON object: Tty\n");
2726         return SR_ERR_OPERATION_FAILED;
2727     }
2728
2729     char *post_data_string = NULL;
2730
2731     post_data_string = cJSON_PrintUnformatted(postDataJson);
2732
2733     printf("Post data JSON:\n%s\n", post_data_string);
2734
2735     if (postDataJson != NULL)
2736     {
2737         cJSON_Delete(postDataJson);
2738     }
2739
2740     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data_string);
2741
2742     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
2743
2744     res = curl_easy_perform(curl);
2745
2746     if (post_data_string != NULL)
2747     {
2748         free(post_data_string);
2749     }
2750
2751     if (res != CURLE_OK)
2752     {
2753         return SR_ERR_OPERATION_FAILED;
2754     }
2755     else
2756     {
2757         cJSON *json_response = cJSON_Parse(curl_response_mem.memory);
2758         const cJSON *message = NULL;
2759
2760         printf("%lu bytes retrieved\n", (unsigned long)curl_response_mem.size);
2761
2762         message = cJSON_GetObjectItemCaseSensitive(json_response, "message");
2763
2764         if (cJSON_IsString(message) && (message->valuestring != NULL))
2765         {
2766             printf("Message: \"%s\"\n", message->valuestring);
2767         }
2768
2769         cJSON_Delete(json_response);
2770     }
2771
2772     return SR_ERR_OK;
2773 }
2774
2775 static int inspect_device_notification_execution(char *exec_id)
2776 {
2777     int rc = SR_ERR_OK;
2778
2779     struct MemoryStruct curl_response_mem;
2780
2781     curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
2782     curl_response_mem.size = 0;    /* no data at this point */
2783
2784     CURLcode res;
2785
2786     curl_easy_reset(curl);
2787     set_curl_common_info();
2788
2789     char url[500];
2790     sprintf(url, "http:/v%s/exec/%s/json", getenv("DOCKER_ENGINE_VERSION"), exec_id);
2791
2792     curl_easy_setopt(curl, CURLOPT_URL, url);
2793
2794     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
2795     curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
2796
2797     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
2798
2799     res = curl_easy_perform(curl);
2800
2801     if (res != CURLE_OK)
2802     {
2803         rc = SR_ERR_OPERATION_FAILED;
2804     }
2805     else
2806     {
2807         cJSON *json_response = cJSON_Parse(curl_response_mem.memory);
2808         const cJSON *exit_code = NULL;
2809
2810         exit_code = cJSON_GetObjectItemCaseSensitive(json_response, "ExitCode");
2811
2812         if (cJSON_IsNumber(exit_code))
2813         {
2814             rc = exit_code->valueint;
2815         }
2816         else
2817         {
2818             printf("Exit code is not a number!\n");
2819             rc = SR_ERR_OPERATION_FAILED;
2820         }
2821         
2822         cJSON_Delete(json_response);
2823     }
2824
2825     return rc;
2826 }
2827
2828 int invoke_device_notification(char *device_id, char *module_name, char *notification_string)
2829 {
2830     int rc = SR_ERR_OK;
2831
2832     printf("Device-name = %s\nModule-name = %s\nNotification-object = %s\n", device_id, module_name, notification_string);
2833
2834     struct MemoryStruct curl_response_mem;
2835
2836     curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
2837     curl_response_mem.size = 0;    /* no data at this point */
2838
2839     CURLcode res;
2840
2841     curl_easy_reset(curl);
2842     set_curl_common_info();
2843
2844     char url[300];
2845     sprintf(url, "http:/v%s/containers/%s/exec", getenv("DOCKER_ENGINE_VERSION"), device_id);
2846
2847     curl_easy_setopt(curl, CURLOPT_URL, url);
2848
2849     cJSON *postDataJson = cJSON_CreateObject();
2850
2851     if (cJSON_AddFalseToObject(postDataJson, "AtttachStdin") == NULL)
2852     {
2853         printf("Could not create JSON object: AtttachStdin\n");
2854         rc = SR_ERR_OPERATION_FAILED;
2855         goto cleanup;
2856     }
2857
2858     if (cJSON_AddTrueToObject(postDataJson, "AtttachStdout") == NULL)
2859     {
2860         printf("Could not create JSON object: AtttachStdout\n");
2861         rc = SR_ERR_OPERATION_FAILED;
2862         goto cleanup;
2863     }
2864
2865     if (cJSON_AddTrueToObject(postDataJson, "AtttachStderr") == NULL)
2866     {
2867         printf("Could not create JSON object: AtttachStderr\n");
2868         rc = SR_ERR_OPERATION_FAILED;
2869         goto cleanup;
2870     }
2871
2872     if (cJSON_AddTrueToObject(postDataJson, "Privileged") == NULL)
2873     {
2874         printf("Could not create JSON object: Privileged\n");
2875         rc = SR_ERR_OPERATION_FAILED;
2876         goto cleanup;
2877     }
2878
2879     if (cJSON_AddStringToObject(postDataJson, "User", "root") == NULL)
2880     {
2881         printf("Could not create JSON object: User\n");
2882         rc = SR_ERR_OPERATION_FAILED;
2883         goto cleanup;
2884     }
2885
2886     cJSON *cmd_array = cJSON_CreateArray();
2887     if (cmd_array == NULL)
2888     {
2889         printf("Could not create JSON object: Cmd array\n");
2890         rc = SR_ERR_OPERATION_FAILED;
2891         goto cleanup;
2892     }
2893
2894     cJSON_AddItemToObject(postDataJson, "Cmd", cmd_array);
2895
2896     cJSON *cmd_string_1 = cJSON_CreateString("sh");
2897     cJSON_AddItemToArray(cmd_array, cmd_string_1);
2898
2899     cJSON *cmd_string_2 = cJSON_CreateString("-c");
2900     cJSON_AddItemToArray(cmd_array, cmd_string_2);
2901
2902     //some notifications require a really long notification object
2903     char string_command[1000000];
2904     sprintf(string_command, "/usr/local/bin/generic-notifications %s '%s'", module_name, notification_string);
2905
2906     cJSON *cmd_string_3 = cJSON_CreateString(string_command);
2907     cJSON_AddItemToArray(cmd_array, cmd_string_3);
2908
2909     char *post_data_string = NULL;
2910
2911     post_data_string = cJSON_PrintUnformatted(postDataJson);
2912
2913     printf("Post data JSON:\n%s\n", post_data_string);
2914
2915     if (postDataJson != NULL)
2916     {
2917         cJSON_Delete(postDataJson);
2918     }
2919
2920     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data_string);
2921
2922     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
2923
2924     res = curl_easy_perform(curl);
2925
2926     if (post_data_string != NULL)
2927     {
2928         free(post_data_string);
2929     }
2930
2931     if (res != CURLE_OK)
2932     {
2933         rc = SR_ERR_OPERATION_FAILED;
2934         goto cleanup;
2935     }
2936     else
2937     {
2938         cJSON *json_response = cJSON_Parse(curl_response_mem.memory);
2939         const cJSON *exec_id = NULL;
2940
2941         exec_id = cJSON_GetObjectItemCaseSensitive(json_response, "Id");
2942
2943         if (cJSON_IsString(exec_id) && (exec_id->valuestring != NULL))
2944         {
2945             printf("Exec id: \"%s\"\n", exec_id->valuestring);
2946
2947             rc = start_device_notification(exec_id->valuestring);
2948             if (rc != SR_ERR_OK)
2949             {
2950                 printf("Could not start the execution of the notification...\n");
2951             }
2952
2953             sleep(1);
2954
2955             rc = inspect_device_notification_execution(exec_id->valuestring);
2956         }
2957
2958         cJSON_Delete(json_response);
2959     }
2960
2961 cleanup:
2962     if (device_id != NULL)
2963     {
2964         free(device_id);
2965     }
2966     if (module_name != NULL)
2967     {
2968         free(module_name);
2969     }
2970     if (notification_string != NULL)
2971     {
2972         free(notification_string);
2973     }
2974
2975     return rc;
2976 }
2977
2978 int pull_docker_image_of_simulated_device()
2979 {
2980     struct MemoryStruct curl_response_mem;
2981
2982     curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
2983     curl_response_mem.size = 0;    /* no data at this point */
2984
2985     CURLcode res;
2986
2987     curl_easy_reset(curl);
2988     set_curl_common_info();
2989
2990     char url[300];
2991     sprintf(url, "http:/v%s/images/create?fromImage=%s", getenv("DOCKER_ENGINE_VERSION"), getenv("MODELS_IMAGE"));
2992
2993     curl_easy_setopt(curl, CURLOPT_URL, url);
2994
2995     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
2996
2997     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
2998
2999     curl_easy_setopt(curl, CURLOPT_TIMEOUT, 300L);
3000
3001     res = curl_easy_perform(curl);
3002
3003     if (res != CURLE_OK)
3004     {
3005         return SR_ERR_OPERATION_FAILED;
3006     }
3007
3008     return SR_ERR_OK;
3009 }