Add simulator enhancements.
[sim/o1-interface.git] / ntsimulator / src / ntsimulator-manager / simulator-operations.c
1 /*************************************************************************
2 *
3 * Copyright 2019 highstreet technologies GmbH and others
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 ***************************************************************************/
17
18 #include "simulator-operations.h"
19 #include "sysrepo.h"
20 #include "sysrepo/values.h"
21 #include <string.h>
22 #include <math.h>
23 #include <linux/limits.h>
24
25 #include "utils.h"
26
27 #define LINE_BUFSIZE 128
28
29 static  CURL *curl; //share the same curl connection for communicating with the Docker Engine API
30 static  CURL *curl_odl; //share the same curl connection for mounting servers in ODL
31 static  CURL *curl_k8s; //share the same curl connection for communicating with the K8S cluster
32
33 /*
34 curl -X POST -H 'Content-Type: application/json' -i http://localhost:5000/scale --data '{"simulatedDevices":2}'
35 */
36
37 static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
38 {
39   size_t realsize = size * nmemb;
40   struct MemoryStruct *mem = (struct MemoryStruct *)userp;
41
42   char *ptr = realloc(mem->memory, mem->size + realsize + 1);
43   if(ptr == NULL) {
44     /* out of memory! */
45     printf("not enough memory (realloc returned NULL)\n");
46     return 0;
47   }
48
49   mem->memory = ptr;
50   memcpy(&(mem->memory[mem->size]), contents, realsize);
51   mem->size += realsize;
52   mem->memory[mem->size] = 0;
53
54   return realsize;
55 }
56
57 static void set_curl_common_info()
58 {
59     struct curl_slist *chunk = NULL;
60     chunk = curl_slist_append(chunk, "Content-Type: application/json");
61     chunk = curl_slist_append(chunk, "Accept: application/json");
62
63     curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
64
65     curl_easy_setopt(curl, CURLOPT_UNIX_SOCKET_PATH, "/var/run/docker.sock");
66
67     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
68     curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 2L); // seconds timeout for a connection
69     curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L); //seconds timeout for an operation
70
71     curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
72 }
73
74 static void set_curl_common_info_odl()
75 {
76     struct curl_slist *chunk = NULL;
77     chunk = curl_slist_append(chunk, "Content-Type: application/xml");
78     chunk = curl_slist_append(chunk, "Accept: application/xml");
79
80     curl_easy_setopt(curl_odl, CURLOPT_HTTPHEADER, chunk);
81
82     curl_easy_setopt(curl_odl, CURLOPT_CONNECTTIMEOUT, 2L); // seconds timeout for a connection
83     curl_easy_setopt(curl_odl, CURLOPT_TIMEOUT, 10L); //seconds timeout for an operation
84
85     curl_easy_setopt(curl_odl, CURLOPT_VERBOSE, 1L);
86 }
87
88 static void set_curl_common_info_k8s()
89 {
90     struct curl_slist *chunk = NULL;
91     chunk = curl_slist_append(chunk, "Content-Type: application/json");
92     chunk = curl_slist_append(chunk, "Accept: application/json");
93
94     curl_easy_setopt(curl_k8s, CURLOPT_HTTPHEADER, chunk);
95
96     curl_easy_setopt(curl_k8s, CURLOPT_CONNECTTIMEOUT, 2L); // seconds timeout for a connection
97     curl_easy_setopt(curl_k8s, CURLOPT_TIMEOUT, 10L); //seconds timeout for an operation
98
99     curl_easy_setopt(curl_k8s, CURLOPT_VERBOSE, 1L);
100 }
101
102 static cJSON* get_docker_container_bindings(void)
103 {
104         struct MemoryStruct curl_response_mem;
105
106         curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
107         curl_response_mem.size = 0;    /* no data at this point */
108
109         CURLcode res;
110
111         curl_easy_reset(curl);
112         set_curl_common_info();
113
114         char url[200];
115         sprintf(url, "http:/v%s/containers/%s/json", getenv("DOCKER_ENGINE_VERSION"), getenv("HOSTNAME"));
116
117         curl_easy_setopt(curl, CURLOPT_URL, url);
118
119     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
120     curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
121
122         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
123
124         res = curl_easy_perform(curl);
125
126         if (res != CURLE_OK)
127         {
128                 return NULL;
129         }
130         else
131         {
132                 cJSON *json_response = cJSON_Parse(curl_response_mem.memory);
133
134                 printf("%lu bytes retrieved\n", (unsigned long)curl_response_mem.size);
135
136                 if (json_response == NULL)
137                 {
138                         printf("Could not parse JSON response for url=\"%s\"\n", url);
139                         return NULL;
140                 }
141
142                 cJSON *hostConfig = cJSON_GetObjectItemCaseSensitive(json_response, "HostConfig");
143
144                 if (hostConfig == NULL)
145                 {
146                         printf("Could not get HostConfig object\n");
147                         return NULL;
148                 }
149
150                 cJSON *binds = cJSON_GetObjectItemCaseSensitive(hostConfig, "Binds");
151
152                 if (binds == NULL)
153                 {
154                         printf("Could not get Binds object\n");
155                         return NULL;
156                 }
157
158                 cJSON *bindsCopy = cJSON_Duplicate(binds, 1);
159
160             cJSON_Delete(json_response);
161
162                 return bindsCopy;
163         }
164
165         return NULL;
166 }
167
168 static cJSON* get_docker_container_network_node(void)
169 {
170     struct MemoryStruct curl_response_mem;
171
172     curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
173     curl_response_mem.size = 0;    /* no data at this point */
174
175     CURLcode res;
176
177     curl_easy_reset(curl);
178     set_curl_common_info();
179
180     char url[200];
181     sprintf(url, "http:/v%s/containers/%s/json", getenv("DOCKER_ENGINE_VERSION"), getenv("HOSTNAME"));
182
183     curl_easy_setopt(curl, CURLOPT_URL, url);
184
185     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
186     curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
187
188     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
189
190     res = curl_easy_perform(curl);
191
192     if (res != CURLE_OK)
193     {
194         return NULL;
195     }
196     else
197     {
198         cJSON *json_response = cJSON_Parse(curl_response_mem.memory);
199
200         printf("%lu bytes retrieved\n", (unsigned long)curl_response_mem.size);
201
202         if (json_response == NULL)
203         {
204             printf("Could not parse JSON response for url=\"%s\"\n", url);
205             return NULL;
206         }
207
208         cJSON *hostConfig = cJSON_GetObjectItemCaseSensitive(json_response, "HostConfig");
209
210         if (hostConfig == NULL)
211         {
212             printf("Could not get HostConfig object\n");
213             return NULL;
214         }
215
216         cJSON *networkMode = cJSON_GetObjectItemCaseSensitive(hostConfig, "NetworkMode");
217
218         if (networkMode == NULL)
219         {
220             printf("Could not get NetworkMode object\n");
221             return NULL;
222         }
223
224         cJSON *networkCopy = cJSON_Duplicate(networkMode, 1);
225
226         cJSON_Delete(json_response);
227
228         return networkCopy;
229     }
230
231     return NULL;
232 }
233
234 static char* create_docker_container_curl(int base_netconf_port, cJSON* managerBinds, cJSON* networkMode)
235 {
236     if (managerBinds == NULL)
237     {
238         printf("Could not retrieve JSON object: Binds\n");
239         return NULL;
240     }
241     cJSON *binds = cJSON_Duplicate(managerBinds, 1);
242
243     if (networkMode == NULL)
244         {
245                 printf("Could not retrieve JSON object: NetworkMode\n");
246                 return NULL;
247         }
248         cJSON *netMode = cJSON_Duplicate(networkMode, 1);
249
250         struct MemoryStruct curl_response_mem;
251
252         curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
253         curl_response_mem.size = 0;    /* no data at this point */
254
255         CURLcode res;
256
257         curl_easy_reset(curl);
258         set_curl_common_info();
259
260         char url[100];
261         sprintf(url, "http:/v%s/containers/create", getenv("DOCKER_ENGINE_VERSION"));
262
263         // the docker image name to be used is defined in the Dockerfile of the NTS Manager,
264         // under the MODELS_IMAGE env variable
265         char models_var[50];
266         sprintf(models_var, "%s", getenv("MODELS_IMAGE"));
267
268         curl_easy_setopt(curl, CURLOPT_URL, url);
269
270     cJSON *postDataJson = cJSON_CreateObject();
271
272     if (cJSON_AddStringToObject(postDataJson, "Image", models_var) == NULL)
273         {
274         printf("Could not create JSON object: Image\n");
275                 return NULL;
276         }
277
278     cJSON *hostConfig = cJSON_CreateObject();
279     if (hostConfig == NULL)
280         {
281         printf("Could not create JSON object: HostConfig\n");
282                 return NULL;
283         }
284
285     cJSON_AddItemToObject(postDataJson, "HostConfig", hostConfig);
286
287     cJSON *portBindings = cJSON_CreateObject();
288     if (portBindings == NULL)
289         {
290         printf("Could not create JSON object: PortBindings\n");
291                 return NULL;
292         }
293
294     cJSON_AddItemToObject(hostConfig, "PortBindings", portBindings);
295
296     for (int i = 0; i < NETCONF_CONNECTIONS_PER_DEVICE; ++i)
297     {
298         cJSON *port = cJSON_CreateArray();
299                 if (port == NULL)
300                 {
301                 printf("Could not create JSON object: port\n");
302                         return NULL;
303                 }
304
305                 char dockerContainerPort[20];
306                 sprintf(dockerContainerPort, "%d/tcp", 830 + i);
307
308             cJSON_AddItemToObject(portBindings, dockerContainerPort, port);
309
310             cJSON *hostPort = cJSON_CreateObject();
311             if (hostPort == NULL)
312                 {
313                 printf("Could not create JSON object: HostPort\n");
314                         return NULL;
315                 }
316
317             char dockerHostPort[10];
318             sprintf(dockerHostPort, "%d", base_netconf_port + i);
319             if (cJSON_AddStringToObject(hostPort, "HostPort", dockerHostPort) == NULL)
320             {
321                 printf("Could not create JSON object: HostPortString\n");
322                 return NULL;
323             }
324             if (cJSON_AddStringToObject(hostPort, "HostIp", getenv("NTS_IP")) == NULL)
325             {
326                 printf("Could not create JSON object: HostIpString\n");
327                 return NULL;
328             }
329
330             cJSON_AddItemToArray(port, hostPort);
331     }
332
333     cJSON *labels = cJSON_CreateObject();
334     if (labels == NULL)
335         {
336         printf("Could not create JSON object: Labels\n");
337                 return NULL;
338         }
339
340     cJSON_AddItemToObject(postDataJson, "Labels", labels);
341
342     if (cJSON_AddStringToObject(labels, "NTS", "") == NULL)
343     {
344         printf("Could not create JSON object: NTS\n");
345         return NULL;
346     }
347
348         if (cJSON_AddStringToObject(labels, "NTS_Manager", getenv("HOSTNAME")) == NULL)
349     {
350         printf("Could not create JSON object: NTS Manager\n");
351         return NULL;
352     }
353
354     cJSON *env_variables_array = cJSON_CreateArray();
355     if (env_variables_array == NULL)
356         {
357         printf("Could not create JSON object: Env array\n");
358                 return NULL;
359         }
360
361     cJSON_AddItemToObject(postDataJson, "Env", env_variables_array);
362
363     char environment_var[50];
364     sprintf(environment_var, "NTS_IP=%s", getenv("NTS_IP"));
365
366     cJSON *env_var_obj = cJSON_CreateString(environment_var);
367     if (env_var_obj == NULL)
368         {
369         printf("Could not create JSON object: Env array object NTS_IP\n");
370                 return NULL;
371         }
372     cJSON_AddItemToArray(env_variables_array, env_var_obj);
373
374     sprintf(environment_var, "NETCONF_BASE=%d", base_netconf_port);
375     cJSON *env_var_obj_2 = cJSON_CreateString(environment_var);
376     if (env_var_obj_2 == NULL)
377         {
378         printf("Could not create JSON object: Env array object NETCONF_BASE\n");
379                 return NULL;
380         }
381     cJSON_AddItemToArray(env_variables_array, env_var_obj_2);
382
383     char scripts_dir[200];
384     sprintf(scripts_dir, "SCRIPTS_DIR=%s", getenv("SCRIPTS_DIR"));
385     cJSON *env_var_obj_3 = cJSON_CreateString(scripts_dir);
386     if (env_var_obj_3 == NULL)
387     {
388         printf("Could not create JSON object: Env array object SCRIPTS_DIR\n");
389         return NULL;
390     }
391     cJSON_AddItemToArray(env_variables_array, env_var_obj_3);
392
393     char k8s_deployment[50];
394     sprintf(k8s_deployment, "K8S_DEPLOYMENT=%s", getenv("K8S_DEPLOYMENT"));
395     cJSON *env_var_obj_4 = cJSON_CreateString(k8s_deployment);
396     if (env_var_obj_4 == NULL)
397     {
398         printf("Could not create JSON object: Env array object K8S_DEPLOYMENT\n");
399         return NULL;
400     }
401     cJSON_AddItemToArray(env_variables_array, env_var_obj_4);
402
403     cJSON_AddItemToObject(hostConfig, "Binds", binds);
404
405     cJSON_AddItemToObject(hostConfig, "NetworkMode", netMode);
406
407     char *post_data_string = NULL;
408
409     post_data_string = cJSON_PrintUnformatted(postDataJson);
410
411     printf("Post data JSON:\n%s\n", post_data_string);
412
413     if (postDataJson != NULL)
414     {
415         cJSON_Delete(postDataJson);
416     }
417
418     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data_string);
419
420         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
421
422         res = curl_easy_perform(curl);
423
424     if (post_data_string != NULL)
425     {
426         free(post_data_string);
427     }
428
429         if (res != CURLE_OK)
430         {
431                 return NULL;
432         }
433         else
434         {
435                 cJSON *json_response = cJSON_Parse(curl_response_mem.memory);
436                 const cJSON *container_id = NULL;
437
438                 printf("%lu bytes retrieved\n", (unsigned long)curl_response_mem.size);
439
440                 container_id = cJSON_GetObjectItemCaseSensitive(json_response, "Id");
441
442                 if (cJSON_IsString(container_id) && (container_id->valuestring != NULL))
443                 {
444                         printf("Container id: \"%s\"\n", container_id->valuestring);
445
446                         char container_id_short[13];
447
448                         memset(container_id_short, '\0', sizeof(container_id_short));
449                         strncpy(container_id_short, container_id->valuestring, 12);
450
451                         printf("Container id short: \"%s\"\n", container_id_short);
452
453                     cJSON_Delete(json_response);
454                         return strdup(container_id_short);
455                 }
456
457             cJSON_Delete(json_response);
458         }
459
460         return NULL;
461 }
462
463 static int start_docker_container_curl(char *container_id)
464 {
465     struct MemoryStruct curl_response_mem;
466
467     curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
468     curl_response_mem.size = 0;    /* no data at this point */
469
470     CURLcode res;
471
472     curl_easy_reset(curl);
473     set_curl_common_info();
474
475     char url[100];
476     sprintf(url, "http:/v%s/containers/%s/start", getenv("DOCKER_ENGINE_VERSION"), container_id);
477
478     curl_easy_setopt(curl, CURLOPT_URL, url);
479
480     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
481
482     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
483
484     res = curl_easy_perform(curl);
485
486     if (res != CURLE_OK)
487     {
488         return SR_ERR_OPERATION_FAILED;
489     }
490     else
491     {
492         printf("Container %s started successfully!\n", container_id);
493     }
494
495     return SR_ERR_OK;
496 }
497
498 static int rename_docker_container_curl(char *container_id, int device_number)
499 {
500     struct MemoryStruct curl_response_mem;
501
502     curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
503     curl_response_mem.size = 0;    /* no data at this point */
504
505     CURLcode res;
506
507     curl_easy_reset(curl);
508     set_curl_common_info();
509
510     char device_name[100];
511     sprintf(device_name, "%s-%d", getenv("CONTAINER_NAME"), device_number);
512
513     char url[100];
514     sprintf(url, "http:/v%s/containers/%s/rename?name=%s", getenv("DOCKER_ENGINE_VERSION"), container_id,
515                 device_name);
516
517     curl_easy_setopt(curl, CURLOPT_URL, url);
518
519     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
520
521     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
522
523     res = curl_easy_perform(curl);
524
525     if (res != CURLE_OK)
526     {
527         return SR_ERR_OPERATION_FAILED;
528     }
529     else
530     {
531         printf("Container %s renamed successfully to %s!\n", container_id, device_name);
532     }
533
534     return SR_ERR_OK;
535 }
536
537 static int kill_and_remove_docker_container_curl(char *container_id)
538 {
539         struct MemoryStruct curl_response_mem;
540
541         curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
542         curl_response_mem.size = 0;    /* no data at this point */
543
544         CURLcode res;
545
546         curl_easy_reset(curl);
547         set_curl_common_info();
548
549         char url[100];
550         sprintf(url, "http:/v%s/containers/%s?force=true", getenv("DOCKER_ENGINE_VERSION"), container_id);
551
552         curl_easy_setopt(curl, CURLOPT_URL, url);
553
554     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
555     curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
556
557         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
558
559         res = curl_easy_perform(curl);
560
561         if (res != CURLE_OK)
562         {
563                 return SR_ERR_OPERATION_FAILED;
564         }
565         else
566         {
567                 printf("Container %s removed successfully!\n", container_id);
568         }
569
570         return SR_ERR_OK;
571 }
572
573 static int send_mount_device_instance_ssh(char *url, char *credentials, char *device_name, int device_port)
574 {
575         CURLcode res;
576
577         curl_easy_reset(curl_odl);
578         set_curl_common_info_odl();
579
580         char url_for_curl[200];
581         sprintf(url_for_curl, "%s%s_%d", url, device_name, device_port);
582
583         curl_easy_setopt(curl_odl, CURLOPT_URL, url_for_curl);
584
585         char post_data_xml[1500];
586
587         sprintf(post_data_xml,
588             "<node xmlns=\"urn:TBD:params:xml:ns:yang:network-topology\">"
589             "<node-id>%s_%d</node-id>"
590             "<host xmlns=\"urn:opendaylight:netconf-node-topology\">%s</host>"
591             "<port xmlns=\"urn:opendaylight:netconf-node-topology\">%d</port>"
592             "<username xmlns=\"urn:opendaylight:netconf-node-topology\">%s</username>"
593             "<password xmlns=\"urn:opendaylight:netconf-node-topology\">%s</password>"
594             "<tcp-only xmlns=\"urn:opendaylight:netconf-node-topology\">false</tcp-only>"
595             "<keepalive-delay xmlns=\"urn:opendaylight:netconf-node-topology\">120</keepalive-delay>"
596             "<reconnect-on-changed-schema xmlns=\"urn:opendaylight:netconf-node-topology\">false</reconnect-on-changed-schema>"
597             "<sleep-factor xmlns=\"urn:opendaylight:netconf-node-topology\">1.5</sleep-factor>"
598             "<connection-timeout-millis xmlns=\"urn:opendaylight:netconf-node-topology\">20000</connection-timeout-millis>"
599             "<max-connection-attempts xmlns=\"urn:opendaylight:netconf-node-topology\">100</max-connection-attempts>"
600             "<between-attempts-timeout-millis xmlns=\"urn:opendaylight:netconf-node-topology\">2000</between-attempts-timeout-millis>"
601             "</node>",
602                         device_name, device_port, getenv("NTS_IP"), device_port, "netconf", "netconf");
603
604         printf("Post data:\n%s\n", post_data_xml);
605
606         curl_easy_setopt(curl_odl, CURLOPT_POSTFIELDS, post_data_xml);
607     curl_easy_setopt(curl_odl, CURLOPT_CUSTOMREQUEST, "PUT");
608     curl_easy_setopt(curl_odl, CURLOPT_USERPWD, credentials);
609
610         res = curl_easy_perform(curl_odl);
611         if (res != CURLE_OK)
612         {
613                 printf("cURL failed to url=%s\n", url_for_curl);
614         }
615
616         long http_response_code = 0;
617         curl_easy_getinfo (curl_odl, CURLINFO_RESPONSE_CODE, &http_response_code);
618         if (http_response_code >= 200 && http_response_code <= 226 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
619         {
620                 printf("cURL succeeded to url=%s\n", url_for_curl);
621         }
622         else
623         {
624             printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
625                 return SR_ERR_OPERATION_FAILED;
626         }
627
628         return SR_ERR_OK;
629 }
630
631 static int send_mount_device_instance_tls(char *url, char *credentials, char *device_name, int device_port)
632 {
633         CURLcode res;
634
635         curl_easy_reset(curl_odl);
636         set_curl_common_info_odl();
637
638         char url_for_curl[200];
639         sprintf(url_for_curl, "%s%s_%d", url, device_name, device_port);
640
641         curl_easy_setopt(curl_odl, CURLOPT_URL, url_for_curl);
642
643         char post_data_xml[1500];
644
645         sprintf(post_data_xml,
646                         "<node xmlns=\"urn:TBD:params:xml:ns:yang:network-topology\">"
647                         "<protocol xmlns=\"urn:opendaylight:netconf-node-topology\">"
648                         "<name>TLS</name>"
649                         "</protocol>"
650                         "<node-id>%s_%d</node-id>"
651                         "<host xmlns=\"urn:opendaylight:netconf-node-topology\">%s</host>"
652                         "<key-based xmlns=\"urn:opendaylight:netconf-node-topology\">"
653                         "<username>%s</username>"
654                         "<key-id>device-key</key-id>"
655                         "</key-based>"
656                         "<port xmlns=\"urn:opendaylight:netconf-node-topology\">%d</port>"
657                         "<tcp-only xmlns=\"urn:opendaylight:netconf-node-topology\">false</tcp-only>"
658                         "<keepalive-delay xmlns=\"urn:opendaylight:netconf-node-topology\">120</keepalive-delay>"
659                         "<reconnect-on-changed-schema xmlns=\"urn:opendaylight:netconf-node-topology\">false</reconnect-on-changed-schema>"
660                         "<sleep-factor xmlns=\"urn:opendaylight:netconf-node-topology\">1.5</sleep-factor>"
661                         "<connection-timeout-millis xmlns=\"urn:opendaylight:netconf-node-topology\">20000</connection-timeout-millis>"
662                         "<max-connection-attempts xmlns=\"urn:opendaylight:netconf-node-topology\">100</max-connection-attempts>"
663                         "<between-attempts-timeout-millis xmlns=\"urn:opendaylight:netconf-node-topology\">2000</between-attempts-timeout-millis>"
664                         "</node>",
665                         device_name, device_port, getenv("NTS_IP"), "netconf", device_port);
666
667         printf("Post data:\n%s\n", post_data_xml);
668
669         curl_easy_setopt(curl_odl, CURLOPT_POSTFIELDS, post_data_xml);
670     curl_easy_setopt(curl_odl, CURLOPT_CUSTOMREQUEST, "PUT");
671     curl_easy_setopt(curl_odl, CURLOPT_USERPWD, credentials);
672
673         res = curl_easy_perform(curl_odl);
674         if (res != CURLE_OK)
675         {
676                 printf("cURL failed to url=%s\n", url_for_curl);
677         }
678
679         long http_response_code = 0;
680         curl_easy_getinfo (curl_odl, CURLINFO_RESPONSE_CODE, &http_response_code);
681         if (http_response_code >= 200 && http_response_code <= 226 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
682         {
683                 printf("cURL succeeded to url=%s\n", url_for_curl);
684         }
685         else
686         {
687             printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
688                 return SR_ERR_OPERATION_FAILED;
689         }
690
691         return SR_ERR_OK;
692 }
693
694 static int send_unmount_device_instance(char *url, char *credentials, char *device_name, int device_port)
695 {
696         CURLcode res;
697
698         curl_easy_reset(curl_odl);
699         set_curl_common_info_odl();
700
701         char url_for_curl[200];
702         sprintf(url_for_curl, "%s%s_%d", url, device_name, device_port);
703
704         curl_easy_setopt(curl_odl, CURLOPT_URL, url_for_curl);
705
706         curl_easy_setopt(curl_odl, CURLOPT_POSTFIELDS, "");
707         curl_easy_setopt(curl_odl, CURLOPT_CUSTOMREQUEST, "DELETE");
708         curl_easy_setopt(curl_odl, CURLOPT_USERPWD, credentials);
709
710         res = curl_easy_perform(curl_odl);
711         if (res != CURLE_OK)
712         {
713                 printf("cURL failed to url=%s\n", url_for_curl);
714         }
715
716         long http_response_code = 0;
717         curl_easy_getinfo (curl_odl, CURLINFO_RESPONSE_CODE, &http_response_code);
718         if (http_response_code == 200 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
719         {
720                 printf("cURL succeeded to url=%s\n", url_for_curl);
721         }
722         else
723         {
724                 printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
725                 return SR_ERR_OPERATION_FAILED;
726         }
727
728
729         return SR_ERR_OK;
730 }
731
732
733 static int send_mount_device(device_t *current_device, controller_t controller_details)
734 {
735         int rc = SR_ERR_OK;
736         bool is_mounted = true;
737     int port = 0;
738
739         //This is where we hardcoded: 7 devices will have SSH connections and 3 devices will have TLS connections
740         for (int i = 0; i < SSH_CONNECTIONS_PER_DEVICE; ++port, ++i)
741         {
742                 rc = send_mount_device_instance_ssh(controller_details.url, controller_details.credentials,
743                                 current_device->device_id, current_device->netconf_port + port);
744                 if (rc != SR_ERR_OK)
745                 {
746                         is_mounted = false;
747                 }
748         }
749         for (int i = 0; i < TLS_CONNECTIONS_PER_DEVICE; ++port, ++i)
750         {
751                 rc = send_mount_device_instance_tls(controller_details.url, controller_details.credentials,
752                                 current_device->device_id, current_device->netconf_port + port);
753                 if (rc != SR_ERR_OK)
754                 {
755                         is_mounted = false;
756                 }
757         }
758
759         current_device->is_mounted = is_mounted;
760
761         return SR_ERR_OK;
762 }
763
764 static int send_unmount_device(device_t *current_device, controller_t controller_details)
765 {
766         int rc = SR_ERR_OK;
767
768         for (int port = 0; port < NETCONF_CONNECTIONS_PER_DEVICE; ++port)
769         {
770                 rc = send_unmount_device_instance(controller_details.url, controller_details.credentials,
771                                 current_device->device_id, current_device->netconf_port + port);
772                 if (rc != SR_ERR_OK)
773                 {
774                         printf("Could not send unmount for ODL with url=\"%s\", for device=\"%s\" and port=%d\n",
775                                         controller_details.url, current_device->device_id, current_device->netconf_port);
776                 }
777         }
778         current_device->is_mounted = false;
779
780         return SR_ERR_OK;
781 }
782
783 device_stack_t *new_device_stack(void)
784 {
785         device_stack_t *stack = malloc(sizeof(*stack));
786
787         if (stack) {
788                 stack->head = NULL;
789                 stack->stack_size = 0;
790         }
791         return stack;
792 }
793
794 void push_device(device_stack_t *theStack, char *dev_id, int port, int dev_num)
795 {
796         device_t *new_dev = malloc(sizeof(*new_dev));
797
798         if (new_dev) {
799                 new_dev->device_id = strdup(dev_id);
800                 new_dev->netconf_port = port;
801         new_dev->device_number = dev_num;
802                 new_dev->is_mounted = false;
803                 new_dev->operational_state = strdup("not-specified");
804
805                 new_dev->next = theStack->head;
806
807                 theStack->head = new_dev;
808                 theStack->stack_size++;
809         }
810 }
811
812 void pop_device(device_stack_t *theStack)
813 {
814         if (theStack && theStack->head) {
815                 device_t *temp = theStack->head;
816                 theStack->head = theStack->head->next;
817
818                 free(temp->device_id);
819                 free(temp->operational_state);
820                 free(temp);
821                 theStack->stack_size--;
822         }
823 }
824
825 int get_netconf_port_next(device_stack_t *theStack)
826 {
827     if (theStack && theStack->stack_size > 0) {
828         return theStack->head->netconf_port + NETCONF_CONNECTIONS_PER_DEVICE;
829     }
830
831     return get_netconf_port_base();
832 }
833
834 int get_netconf_port_base()
835 {
836     int netconf_port_base;
837
838     netconf_port_base = getIntFromString(getenv("NETCONF_BASE"), 50000);
839
840     return netconf_port_base;
841 }
842
843 // we start numbering the containers from 0
844 int get_device_number_next(device_stack_t *theStack)
845 {
846     if (theStack && theStack->stack_size > 0) {
847         return theStack->head->device_number + 1;
848     }
849
850     return 0;
851 }
852
853 char *get_id_last_device(device_stack_t *theStack)
854 {
855     if (theStack && theStack->head) {
856         return theStack->head->device_id;
857     }
858     return NULL;
859 }
860
861 int get_current_number_of_mounted_devices(device_stack_t *theStack)
862 {
863         int mounted_devices = 0;
864
865         if (theStack && theStack->head)
866         {
867                 device_t *current_device = theStack->head;
868
869                 while (current_device != NULL)
870                 {
871                         if (current_device->is_mounted)
872                         {
873                                 mounted_devices++;
874                         }
875                         current_device = current_device->next;
876                 }
877         }
878
879         return mounted_devices;
880 }
881
882 int get_current_number_of_devices(device_stack_t *theStack)
883 {
884     //TODO implement function for k8s deployment
885     if (strcmp(getenv("K8S_DEPLOYMENT"), "true") == 0)
886     {
887         return 0;
888     }
889
890         struct MemoryStruct curl_response_mem;
891
892         curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
893         curl_response_mem.size = 0;    /* no data at this point */
894
895         CURLcode res;
896
897         curl_easy_reset(curl);
898         set_curl_common_info();
899
900         char url[100];
901         sprintf(url, "http:/v%s/containers/json?all=true&filters={\"label\":[\"NTS_Manager=%s\"],\"status\":[\"running\"]}",
902                         getenv("DOCKER_ENGINE_VERSION"), getenv("HOSTNAME"));
903
904         curl_easy_setopt(curl, CURLOPT_URL, url);
905
906         curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
907         curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
908
909         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
910
911         res = curl_easy_perform(curl);
912
913         if (res != CURLE_OK)
914         {
915                 return SR_ERR_OPERATION_FAILED;
916         }
917         else
918         {
919                 cJSON *json_response = cJSON_Parse(curl_response_mem.memory);
920
921                 printf("%lu bytes retrieved\n", (unsigned long)curl_response_mem.size);
922
923                 if (json_response == NULL || !cJSON_IsArray(json_response))
924                 {
925                         printf("Could not parse JSON response for url=\"%s\"\n", url);
926                         return SR_ERR_OPERATION_FAILED;
927                 }
928
929                 int num_of_devices = cJSON_GetArraySize(json_response);
930                 cJSON_Delete(json_response);
931
932                 return num_of_devices;
933         }
934
935         return 0;
936 }
937
938 static int set_operational_state_of_device(device_stack_t *theStack, char *device_id, char *operational_state)
939 {
940         if (theStack && theStack->head)
941         {
942                 device_t *current_device = theStack->head;
943
944                 while (current_device != NULL)
945                 {
946                         if (strcmp(current_device->device_id, device_id) == 0)
947                         {
948                                 free(current_device->operational_state);
949                                 current_device->operational_state = strdup(operational_state);
950
951                                 return SR_ERR_OK;
952                         }
953
954                         current_device = current_device->next;
955                 }
956         }
957
958         printf("Could not find device with uuid=\"%s\"\n", device_id);
959         return SR_ERR_OPERATION_FAILED;
960 }
961
962 char* get_docker_container_operational_state(device_stack_t *theStack, char *container_id)
963 {
964         if (theStack && theStack->head)
965         {
966                 device_t *current_device = theStack->head;
967
968                 while (current_device != NULL)
969                 {
970                         if (strcmp(current_device->device_id, container_id) == 0)
971                         {
972                                 return current_device->operational_state;
973                         }
974
975                         current_device = current_device->next;
976                 }
977         }
978
979         return NULL;
980 }
981
982 int start_device(device_stack_t *theStack)
983 {
984         int rc = SR_ERR_OK;
985         static cJSON *managerBindings = NULL, *networkMode = NULL;
986
987     if (managerBindings == NULL)
988     {
989         managerBindings = get_docker_container_bindings();
990     }
991
992     if (networkMode == NULL)
993         {
994                 networkMode = get_docker_container_network_node();
995         }
996
997         int netconf_base = get_netconf_port_next(theStack);
998     int device_number = get_device_number_next(theStack);
999
1000         char *dev_id = create_docker_container_curl(netconf_base, managerBindings, networkMode);
1001     if (dev_id == NULL)
1002     {
1003         printf("ERROR: Could not create docker container!\n");
1004         return SR_ERR_OPERATION_FAILED;
1005     }
1006
1007         push_device(theStack, dev_id, netconf_base, device_number);
1008
1009         rc = start_docker_container_curl(dev_id);
1010         if (rc != SR_ERR_OK)
1011         {
1012                 printf("Could not start device with device_id=\"%s\"\n", dev_id);
1013         }
1014
1015     rc = rename_docker_container_curl(dev_id, device_number);
1016         if (rc != SR_ERR_OK)
1017         {
1018                 printf("Could not rename device with device_id=\"%s\"\n", dev_id);
1019         }
1020
1021         if (dev_id) {
1022                 free(dev_id);
1023         }
1024
1025         return SR_ERR_OK;
1026 }
1027
1028 int _init_curl()
1029 {
1030         curl = curl_easy_init();
1031
1032         if (curl == NULL) {
1033                 printf("cURL initialization error! Aborting call!\n");
1034                 return SR_ERR_OPERATION_FAILED;
1035         }
1036
1037         return SR_ERR_OK;
1038 }
1039
1040 int cleanup_curl()
1041 {
1042         if (curl != NULL)
1043         {
1044                 curl_easy_cleanup(curl);
1045         }
1046
1047         return SR_ERR_OK;
1048 }
1049
1050 int _init_curl_odl()
1051 {
1052         curl_odl = curl_easy_init();
1053
1054         if (curl_odl == NULL) {
1055                 printf("cURL initialization error! Aborting call!\n");
1056                 return SR_ERR_OPERATION_FAILED;
1057         }
1058
1059         return SR_ERR_OK;
1060 }
1061
1062 int cleanup_curl_odl()
1063 {
1064         if (curl_odl != NULL)
1065         {
1066                 curl_easy_cleanup(curl_odl);
1067         }
1068
1069         return SR_ERR_OK;
1070 }
1071
1072 int _init_curl_k8s()
1073 {
1074     curl_k8s = curl_easy_init();
1075
1076     if (curl_k8s == NULL) {
1077         printf("cURL initialization error! Aborting call!\n");
1078         return SR_ERR_OPERATION_FAILED;
1079     }
1080
1081     return SR_ERR_OK;
1082 }
1083
1084 int cleanup_curl_k8s()
1085 {
1086     if (curl_k8s != NULL)
1087     {
1088         curl_easy_cleanup(curl_k8s);
1089     }
1090
1091     return SR_ERR_OK;
1092 }
1093
1094 int stop_device(device_stack_t *theStack)
1095 {
1096         int rc = SR_ERR_OK;
1097         char *last_id = get_id_last_device(theStack);
1098
1099         rc = kill_and_remove_docker_container_curl(last_id);
1100         if (rc != SR_ERR_OK)
1101         {
1102                 printf("Could not kill and remove docker container with uuid=\"%s\"\n", last_id);
1103         }
1104
1105     rc = removeDeviceEntryFromStatusFile(last_id);
1106     if (rc != SR_ERR_OK)
1107     {
1108         printf("Could not remove entry from status file for uuid=\"%s\"\n", last_id);
1109     }
1110
1111         pop_device(theStack);
1112
1113         return SR_ERR_OK;
1114 }
1115
1116 int mount_device(device_stack_t *theStack, controller_t controller_details)
1117 {
1118         int rc;
1119
1120         if (theStack && theStack->head)
1121         {
1122                 device_t *current_device = theStack->head;
1123                 while (current_device != NULL && current_device->is_mounted == true)
1124                 {
1125                         printf("Device \"%s\" is already mounted, skipping...\n", current_device->device_id);
1126                         current_device = current_device->next;
1127                 }
1128
1129                 if (current_device != NULL)
1130                 {
1131                         printf("Sending mount device for device \"%s\"...\n", current_device->device_id);
1132                         rc = send_mount_device(current_device, controller_details);
1133                         if (rc != SR_ERR_OK)
1134                         {
1135                                 return SR_ERR_OPERATION_FAILED;
1136                         }
1137                 }
1138         }
1139
1140         return SR_ERR_OK;
1141 }
1142
1143 int unmount_device(device_stack_t *theStack, controller_t controller_list)
1144 {
1145         int rc;
1146
1147         if (theStack && theStack->head)
1148         {
1149                 device_t *current_device = theStack->head;
1150                 while (current_device != NULL && current_device->is_mounted == false)
1151                 {
1152                         printf("Device \"%s\" is already unmounted, skipping...\n", current_device->device_id);
1153                         current_device = current_device->next;
1154                 }
1155
1156                 if (current_device != NULL)
1157                 {
1158                         printf("Sending unmount device for device \"%s\"...\n", current_device->device_id);
1159                         rc = send_unmount_device(current_device, controller_list);
1160                         if (rc != SR_ERR_OK)
1161                         {
1162                                 return SR_ERR_OPERATION_FAILED;
1163                         }
1164                 }
1165         }
1166
1167         return SR_ERR_OK;
1168 }
1169
1170 int get_docker_containers_operational_state_curl(device_stack_t *theStack)
1171 {
1172
1173     //TODO implement function for k8s deployment
1174     if (strcmp(getenv("K8S_DEPLOYMENT"), "true") == 0)
1175     {
1176         return SR_ERR_OK;
1177     }
1178
1179         int rc = SR_ERR_OK;
1180         struct MemoryStruct curl_response_mem;
1181
1182         curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
1183         curl_response_mem.size = 0;    /* no data at this point */
1184
1185         CURLcode res;
1186
1187         curl_easy_reset(curl);
1188         set_curl_common_info();
1189
1190         char url[100];
1191         sprintf(url, "http:/v%s/containers/json?all=true&filters={\"label\":[\"NTS_Manager=%s\"]}", 
1192     getenv("DOCKER_ENGINE_VERSION"), getenv("HOSTNAME"));
1193
1194         curl_easy_setopt(curl, CURLOPT_URL, url);
1195
1196     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
1197     curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
1198
1199         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
1200
1201         res = curl_easy_perform(curl);
1202
1203         if (res != CURLE_OK)
1204         {
1205                 return SR_ERR_OPERATION_FAILED;
1206         }
1207         else
1208         {
1209                 cJSON *json_response = cJSON_Parse(curl_response_mem.memory);
1210                 const cJSON *container = NULL;
1211
1212                 printf("%lu bytes retrieved\n", (unsigned long)curl_response_mem.size);
1213
1214                 if (json_response == NULL || !cJSON_IsArray(json_response))
1215                 {
1216                         printf("Could not parse JSON response for url=\"%s\"\n", url);
1217                         return SR_ERR_OPERATION_FAILED;
1218                 }
1219
1220             cJSON_ArrayForEach(container, json_response)
1221             {
1222                 cJSON *container_id_long = cJSON_GetObjectItemCaseSensitive(container, "Id");
1223                 cJSON *state = cJSON_GetObjectItemCaseSensitive(container, "State");
1224
1225                         if (cJSON_IsString(container_id_long) && (container_id_long->valuestring != NULL))
1226                         {
1227                                 char container_id_short[13];
1228
1229                                 memset(container_id_short, '\0', sizeof(container_id_short));
1230                                 strncpy(container_id_short, container_id_long->valuestring, 12);
1231
1232                                 if (cJSON_IsString(state) && (state->valuestring != NULL))
1233                                 {
1234                                         rc = set_operational_state_of_device(theStack, container_id_short, state->valuestring);
1235                                         if (rc != SR_ERR_OK)
1236                                         {
1237                                                 printf("Could not set the operational state for the device with uuid=\"%s\"\n", container_id_short);
1238                                                 return SR_ERR_OPERATION_FAILED;
1239                                         }
1240                                 }
1241                         }
1242             }
1243
1244             cJSON_Delete(json_response);
1245         }
1246
1247         return SR_ERR_OK;
1248 }
1249
1250 char* get_docker_container_resource_stats(device_stack_t *theStack)
1251 {
1252     //TOD need to implement this for k8s deployment
1253     if (strcmp(getenv("K8S_DEPLOYMENT"), "true"))
1254     {
1255         return strdup("CPU=0%;RAM=0MiB");
1256     }
1257
1258         char line[LINE_BUFSIZE];
1259         int linenr;
1260         FILE *pipe;
1261
1262         /* Get a pipe where the output from the scripts comes in */
1263         char script[200];
1264         sprintf(script, "/opt/dev/docker_stats.sh %s", getenv("HOSTNAME"));
1265
1266         pipe = popen(script, "r");
1267         if (pipe == NULL) {  /* check for errors */
1268                 printf("Could not open script.\n");
1269                 return NULL;        /* return with exit code indicating error */
1270         }
1271
1272         /* Read script output from the pipe line by line */
1273         linenr = 1;
1274         while (fgets(line, LINE_BUFSIZE, pipe) != NULL) {
1275                 printf("Script output line %d: %s", linenr, line);
1276                 ++linenr;
1277
1278                 pclose(pipe); /* Close the pipe */
1279                 return strdup(line);
1280         }
1281
1282         /* Once here, out of the loop, the script has ended. */
1283         pclose(pipe); /* Close the pipe */
1284         return NULL;     /* return with exit code indicating success. */
1285 }
1286
1287 int notification_delay_period_changed(sr_val_t *val, size_t count)
1288 {
1289         char *stringConfiguration = readConfigFileInString();
1290
1291         if (stringConfiguration == NULL)
1292         {
1293                 printf("Could not read configuration file!\n");
1294                 return SR_ERR_OPERATION_FAILED;
1295         }
1296
1297         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1298         if (jsonConfig == NULL)
1299         {
1300                 free(stringConfiguration);
1301                 const char *error_ptr = cJSON_GetErrorPtr();
1302                 if (error_ptr != NULL)
1303                 {
1304                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
1305                 }
1306                 return SR_ERR_OPERATION_FAILED;
1307         }
1308         //we don't need the string anymore
1309         free(stringConfiguration);
1310         stringConfiguration = NULL;
1311
1312         cJSON *notifConfig = cJSON_GetObjectItemCaseSensitive(jsonConfig, "notification-config");
1313         if (!cJSON_IsObject(notifConfig))
1314         {
1315                 printf("Configuration JSON is not as expected: notification-config is not an object");
1316                 cJSON_Delete(jsonConfig);
1317                 return SR_ERR_OPERATION_FAILED;
1318         }
1319
1320         cJSON *faultNotifDelay = cJSON_GetObjectItemCaseSensitive(notifConfig, "fault-notification-delay-period");
1321         if (!cJSON_IsArray(faultNotifDelay))
1322         {
1323                 printf("Configuration JSON is not as expected: fault-notification-delay-period is not an array.");
1324                 cJSON_Delete(jsonConfig);
1325                 return SR_ERR_OPERATION_FAILED;
1326         }
1327
1328     cJSON_DeleteItemFromObject(notifConfig, "fault-notification-delay-period");
1329
1330     faultNotifDelay = NULL;
1331
1332     faultNotifDelay = cJSON_CreateArray();
1333     if (faultNotifDelay == NULL) 
1334     {
1335         cJSON_Delete(jsonConfig);
1336                 return SR_ERR_OPERATION_FAILED;
1337     }
1338     cJSON_AddItemToObject(notifConfig, "fault-notification-delay-period", faultNotifDelay);
1339
1340     if (val != NULL && count > 0)
1341     {
1342         cJSON *arrayEntry = NULL;
1343         for (size_t i=0; i<count; ++i)
1344         {
1345             arrayEntry = cJSON_CreateNumber(val[i].data.uint32_val);
1346             if (arrayEntry == NULL) 
1347             {
1348                 cJSON_Delete(jsonConfig);
1349                 return SR_ERR_OPERATION_FAILED;
1350             }
1351             cJSON_AddItemToArray(faultNotifDelay, arrayEntry);
1352         }
1353     }
1354     else
1355     {
1356         cJSON *arrayEntry =  cJSON_CreateNumber(0);
1357         if (arrayEntry == NULL) 
1358         {
1359             cJSON_Delete(jsonConfig);
1360             return SR_ERR_OPERATION_FAILED;
1361         }
1362         cJSON_AddItemToArray(faultNotifDelay, arrayEntry);
1363     }
1364
1365         //writing the new JSON to the configuration file
1366         stringConfiguration = cJSON_Print(jsonConfig);
1367         writeConfigFile(stringConfiguration);
1368
1369     if (stringConfiguration != NULL)
1370     {
1371         free(stringConfiguration);
1372         stringConfiguration = NULL;
1373     }
1374
1375         cJSON_Delete(jsonConfig);
1376
1377         return SR_ERR_OK;
1378 }
1379
1380 int ves_heartbeat_period_changed(int period)
1381 {
1382         char *stringConfiguration = readConfigFileInString();
1383
1384         if (stringConfiguration == NULL)
1385         {
1386                 printf("Could not read configuration file!\n");
1387                 return SR_ERR_OPERATION_FAILED;
1388         }
1389
1390         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1391         if (jsonConfig == NULL)
1392         {
1393                 free(stringConfiguration);
1394                 const char *error_ptr = cJSON_GetErrorPtr();
1395                 if (error_ptr != NULL)
1396                 {
1397                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
1398                 }
1399                 return SR_ERR_OPERATION_FAILED;
1400         }
1401         //we don't need the string anymore
1402         free(stringConfiguration);
1403         stringConfiguration = NULL;
1404
1405         cJSON *notifConfig = cJSON_GetObjectItemCaseSensitive(jsonConfig, "notification-config");
1406         if (!cJSON_IsObject(notifConfig))
1407         {
1408                 printf("Configuration JSON is not as expected: notification-config is not an object");
1409                 cJSON_Delete(jsonConfig);
1410                 return SR_ERR_OPERATION_FAILED;
1411         }
1412
1413         cJSON *vesHeartbeatPeriod = cJSON_GetObjectItemCaseSensitive(notifConfig, "ves-heartbeat-period");
1414         if (!cJSON_IsNumber(vesHeartbeatPeriod))
1415         {
1416                 printf("Configuration JSON is not as expected: ves-heartbeat-period is not an object");
1417                 cJSON_Delete(jsonConfig);
1418                 return SR_ERR_OPERATION_FAILED;
1419         }
1420
1421         //we set the value of the fault-notification-delay-period object
1422         cJSON_SetNumberValue(vesHeartbeatPeriod, period);
1423
1424         //writing the new JSON to the configuration file
1425         stringConfiguration = cJSON_Print(jsonConfig);
1426         writeConfigFile(stringConfiguration);
1427
1428     if (stringConfiguration != NULL)
1429     {
1430         free(stringConfiguration);
1431         stringConfiguration = NULL;
1432     }
1433
1434         cJSON_Delete(jsonConfig);
1435
1436         return SR_ERR_OK;
1437 }
1438
1439 static int add_keystore_entry_odl(char *url, char *credentials)
1440 {
1441         CURLcode res;
1442
1443         curl_easy_reset(curl_odl);
1444         set_curl_common_info_odl();
1445
1446         char url_for_curl[200];
1447         sprintf(url_for_curl, "%s", url);
1448
1449         curl_easy_setopt(curl_odl, CURLOPT_URL, url_for_curl);
1450
1451         char post_data_xml[2000];
1452
1453         sprintf(post_data_xml,
1454                         "<input xmlns=\"urn:opendaylight:netconf:keystore\">"
1455                         "<key-credential>"
1456                         "<key-id>device-key</key-id>"
1457                         "<private-key>MIIEpAIBAAKCAQEAueCQaNQWoNmFK6LKu1p8U8ZWdWg/PvDdLsJyzfzl/Qw4UA68"
1458                         "SfFNaY06zZl8QB9W02nr5kWeeMY0VA3adrPgOlvfx3oWlFbkETnMaN4OT3WTQ0Wt"
1459                         "6jAWZDzVfopwpJPAzRPxACDftIqFGagYcF32hZlVNqqnVdbXh0S0EViweqp/dbG4"
1460                         "VDUHSNVbglc+u4UbEzNIFXMdEFsJZpkynOmSiTsIATqIhb+2srkVgLwhfkC2qkuH"
1461                         "QwAHdubuB07ObM2z01UhyEdDvEYGHwtYAGDBL2TAcsI0oGeVkRyuOkV0QY0UN7UE"
1462                         "FI1yTYw+xZ42HgFx3uGwApCImxhbj69GBYWFqwIDAQABAoIBAQCZN9kR8DGu6V7y"
1463                         "t0Ax68asL8O5B/OKaHWKQ9LqpVrXmikZJOxkbzoGldow/CIFoU+q+Zbwu9aDa65a"
1464                         "0wiP7Hoa4Py3q5XNNUrOQDyU/OYC7cI0I83WS0lJ2zOJGYj8wKae5Z81IeQFKGHK"
1465                         "4lsy1OGPAvPRGh7RjUUgRavA2MCwe07rWRuDb/OJFe4Oh56UMEjwMiNBtMNtncog"
1466                         "j1vr/qgRJdf9tf0zlJmLvUJ9+HSFFV9I/97LJyFhb95gAfHkjdVroLVgT3Cho+4P"
1467                         "WtZaKCIGD0OwfOG2nLV4leXvRUk62/LMlB8NI9+JF7Xm+HCKbaWHNWC7mvWSLV58"
1468                         "Zl4AbUWRAoGBANyJ6SFHFRHSPDY026SsdMzXR0eUxBAK7G70oSBKKhY+O1j0ocLE"
1469                         "jI2krHJBhHbLlnvJVyMUaCUOTS5m0uDw9hgSsAqeSL3hL38kxVZw+KNG9Ouno1Fl"
1470                         "KnE/xXHlPQyeGs/P8nAMzHZxQtEsQdQayJEhK2XXHTsy7Q3MxDisfVJ1AoGBANfD"
1471                         "34gB+OMx6pwj7zk3qWbYXSX8xjCZMR0ciko+h4xeMP2N8B0oyoqC+v1ABMAtJ3wG"
1472                         "sGZd0hV9gwM7OUM3SEwkn6oeg1GemWLcn4rlSmTnZc4aeVwrEWlnSNFX3s4g9l4u"
1473                         "k8Ugu4MVJYqH8HuDQ5Ggl6/QAwPzMSEdCW0O+jOfAoGAIBRbegC5+t6m7Yegz4Ja"
1474                         "dxV1g98K6f58x+MDsQu4tYWV4mmrQgaPH2dtwizvlMwmdpkh+LNWNtWuumowkJHc"
1475                         "akIFo3XExQIFg6wYnGtQb4e5xrGa2xMpKlIJaXjb+YLiCYqJDG2ALFZrTrvuU2kV"
1476                         "9a5qfqTc1qigvNolTM0iaaUCgYApmrZWhnLUdEKV2wP813PNxfioI4afxlpHD8LG"
1477                         "sCn48gymR6E+Lihn7vuwq5B+8fYEH1ISWxLwW+RQUjIneNhy/jjfV8TgjyFqg7or"
1478                         "0Sy4KjpiNI6kLBXOakELRNNMkeSPopGR2E7v5rr3bGD9oAD+aqX1G7oJH/KgPPYd"
1479                         "Vl7+ZwKBgQDcHyWYrimjyUgKaQD2GmoO9wdcJYQ59ke9K+OuGlp4ti5arsi7N1tP"
1480                         "B4f09aeELM2ASIuk8Q/Mx0jQFnm8lzRFXdewgvdPoZW/7VufM9O7dGPOc41cm2Dh"
1481                         "yrTcXx/VmUBb+/fnXVEgCv7gylp/wtdTGHQBQJHR81jFBz0lnLj+gg==</private-key>"
1482                         "<passphrase></passphrase>"
1483                         "</key-credential>"
1484                         "</input>");
1485
1486         printf("Post data:\n%s\n", post_data_xml);
1487
1488         curl_easy_setopt(curl_odl, CURLOPT_POSTFIELDS, post_data_xml);
1489         curl_easy_setopt(curl_odl, CURLOPT_CUSTOMREQUEST, "POST");
1490         curl_easy_setopt(curl_odl, CURLOPT_USERPWD, credentials);
1491
1492         res = curl_easy_perform(curl_odl);
1493         if (res != CURLE_OK)
1494         {
1495                 printf("cURL failed to url=%s\n", url_for_curl);
1496         }
1497
1498         long http_response_code = 0;
1499         curl_easy_getinfo (curl_odl, CURLINFO_RESPONSE_CODE, &http_response_code);
1500         if (http_response_code >= 200 && http_response_code <= 226 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
1501         {
1502                 printf("cURL succeeded to url=%s\n", url_for_curl);
1503         }
1504         else
1505         {
1506                 printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
1507                 return SR_ERR_OPERATION_FAILED;
1508         }
1509
1510         return SR_ERR_OK;
1511 }
1512
1513 static int add_private_key_odl(char *url, char *credentials)
1514 {
1515         CURLcode res;
1516
1517         curl_easy_reset(curl_odl);
1518         set_curl_common_info_odl();
1519
1520         char url_for_curl[200];
1521         sprintf(url_for_curl, "%s", url);
1522
1523         curl_easy_setopt(curl_odl, CURLOPT_URL, url_for_curl);
1524
1525         char post_data_xml[4000];
1526
1527         sprintf(post_data_xml,
1528                         "<input xmlns=\"urn:opendaylight:netconf:keystore\">"
1529                         "<private-key>"
1530                         "<name>device-key</name>"
1531                         "<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>"
1532                         "<certificate-chain>MIIECTCCAvGgAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBjDELMAkGA1UEBhMCQ1oxFjAUBgNVBAgMDVNvdXRoIE1vcmF2aWExDTALBgNVBAcMBEJybm8xDzANBgNVBAoMBkNFU05FVDEMMAoGA1UECwwDVE1DMRMwEQYDVQQDDApleGFtcGxlIENBMSIwIAYJKoZIhvcNAQkBFhNleGFtcGxlY2FAbG9jYWxob3N0MB4XDTE1MDczMDA3MjcxOFoXDTM1MDcyNTA3MjcxOFowgYUxCzAJBgNVBAYTAkNaMRYwFAYDVQQIDA1Tb3V0aCBNb3JhdmlhMQ8wDQYDVQQKDAZDRVNORVQxDDAKBgNVBAsMA1RNQzEXMBUGA1UEAwwOZXhhbXBsZSBjbGllbnQxJjAkBgkqhkiG9w0BCQEWF2V4YW1wbGVjbGllbnRAbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAueCQaNQWoNmFK6LKu1p8U8ZWdWg/PvDdLsJyzfzl/Qw4UA68SfFNaY06zZl8QB9W02nr5kWeeMY0VA3adrPgOlvfx3oWlFbkETnMaN4OT3WTQ0Wt6jAWZDzVfopwpJPAzRPxACDftIqFGagYcF32hZlVNqqnVdbXh0S0EViweqp/dbG4VDUHSNVbglc+u4UbEzNIFXMdEFsJZpkynOmSiTsIATqIhb+2srkVgLwhfkC2qkuHQwAHdubuB07ObM2z01UhyEdDvEYGHwtYAGDBL2TAcsI0oGeVkRyuOkV0QY0UN7UEFI1yTYw+xZ42HgFx3uGwApCImxhbj69GBYWFqwIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUXGpLeLnh2cSDARAVA7KrBxGYpo8wHwYDVR0jBBgwFoAUc1YQIqjZsHVwlea0AB4N+ilNI2gwDQYJKoZIhvcNAQELBQADggEBAJPV3RTXFRtNyOU4rjPpYeBAIAFp2aqGc4t2J1c7oPp/1n+lZvjnwtlJpZHxMM783e2ryDQ6dkvXDf8kpwKlg3U3mkJ3xKkDdWrM4QwghXdCN519aa9qmu0zdFL+jUAaWlQ5tsceOrvbusCcbMqiFGk/QfpHqPv52SVWbYyUx7IX7DE+UjgsLHycfV/tlcx4ZE6soTzl9VdgSL/zmzG3rjsr58J80rXckLgBhvijgBlIAJvWfC7D0vaouvBInSFXymdPVoUDZ30cdGLf+hI/i/TfsEMOinLrXVdkSGNo6FXAHKSvXeB9oFKSzhQ7OPyRyqvEPycUSw/qD6FVr80oDDc=</certificate-chain>"
1533                         "</private-key>"
1534                         "</input>");
1535
1536         printf("Post data:\n%s\n", post_data_xml);
1537
1538         curl_easy_setopt(curl_odl, CURLOPT_POSTFIELDS, post_data_xml);
1539         curl_easy_setopt(curl_odl, CURLOPT_CUSTOMREQUEST, "POST");
1540         curl_easy_setopt(curl_odl, CURLOPT_USERPWD, credentials);
1541
1542         res = curl_easy_perform(curl_odl);
1543         if (res != CURLE_OK)
1544         {
1545                 printf("cURL failed to url=%s\n", url_for_curl);
1546         }
1547
1548         long http_response_code = 0;
1549         curl_easy_getinfo (curl_odl, CURLINFO_RESPONSE_CODE, &http_response_code);
1550         if (http_response_code >= 200 && http_response_code <= 226 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
1551         {
1552                 printf("cURL succeeded to url=%s\n", url_for_curl);
1553         }
1554         else
1555         {
1556                 printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
1557                 return SR_ERR_OPERATION_FAILED;
1558         }
1559
1560         return SR_ERR_OK;
1561 }
1562
1563 static int add_trusted_ca_odl(char *url, char *credentials)
1564 {
1565         CURLcode res;
1566
1567         curl_easy_reset(curl_odl);
1568         set_curl_common_info_odl();
1569
1570         char url_for_curl[200];
1571         sprintf(url_for_curl, "%s", url);
1572
1573         curl_easy_setopt(curl_odl, CURLOPT_URL, url_for_curl);
1574
1575         char post_data_xml[2000];
1576
1577         sprintf(post_data_xml,
1578                         "<input xmlns=\"urn:opendaylight:netconf:keystore\">"
1579                         "<trusted-certificate>"
1580                         "<name>test_trusted_cert</name>"
1581                         "<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>"
1582                         "</trusted-certificate>"
1583                         "</input>");
1584
1585         printf("Post data:\n%s\n", post_data_xml);
1586
1587         curl_easy_setopt(curl_odl, CURLOPT_POSTFIELDS, post_data_xml);
1588         curl_easy_setopt(curl_odl, CURLOPT_CUSTOMREQUEST, "POST");
1589         curl_easy_setopt(curl_odl, CURLOPT_USERPWD, credentials);
1590
1591         res = curl_easy_perform(curl_odl);
1592         if (res != CURLE_OK)
1593         {
1594                 printf("cURL failed to url=%s\n", url_for_curl);
1595         }
1596
1597         long http_response_code = 0;
1598         curl_easy_getinfo (curl_odl, CURLINFO_RESPONSE_CODE, &http_response_code);
1599         if (http_response_code >= 200 && http_response_code <= 226 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
1600         {
1601                 printf("cURL succeeded to url=%s\n", url_for_curl);
1602         }
1603         else
1604         {
1605                 printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
1606                 return SR_ERR_OPERATION_FAILED;
1607         }
1608
1609         return SR_ERR_OK;
1610 }
1611
1612 int add_key_pair_to_odl(controller_t *controller_list, int controller_list_size)
1613 {
1614         int rc = SR_ERR_OK;
1615
1616         rc = add_keystore_entry_odl(controller_list[0].url_for_keystore_add, controller_list[0].credentials);
1617         if (rc != SR_ERR_OK)
1618         {
1619                 printf("Failed to add keystore entry to ODL.\n");
1620         }
1621
1622         rc = add_private_key_odl(controller_list[0].url_for_private_key_add, controller_list[0].credentials);
1623         if (rc != SR_ERR_OK)
1624         {
1625                 printf("Failed to add private key entry to ODL.\n");
1626         }
1627
1628         rc = add_trusted_ca_odl(controller_list[0].url_for_trusted_ca_add, controller_list[0].credentials);
1629         if (rc != SR_ERR_OK)
1630         {
1631                 printf("Failed to add trusted CA entry to ODL.\n");
1632         }
1633
1634         return SR_ERR_OK;
1635 }
1636
1637 int ves_ip_changed(char *new_ip)
1638 {
1639         char *stringConfiguration = readConfigFileInString();
1640
1641         if (stringConfiguration == NULL)
1642         {
1643                 printf("Could not read configuration file!\n");
1644                 return SR_ERR_OPERATION_FAILED;
1645         }
1646
1647         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1648         if (jsonConfig == NULL)
1649         {
1650                 free(stringConfiguration);
1651                 const char *error_ptr = cJSON_GetErrorPtr();
1652                 if (error_ptr != NULL)
1653                 {
1654                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
1655                 }
1656                 return SR_ERR_OPERATION_FAILED;
1657         }
1658         //we don't need the string anymore
1659         free(stringConfiguration);
1660         stringConfiguration = NULL;
1661
1662         cJSON *vesDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "ves-endpoint-details");
1663         if (!cJSON_IsObject(vesDetails))
1664         {
1665                 printf("Configuration JSON is not as expected: ves-endpoint-details is not an object");
1666                 cJSON_Delete(jsonConfig);
1667                 return SR_ERR_OPERATION_FAILED;
1668         }
1669
1670         cJSON *vesIp = cJSON_GetObjectItemCaseSensitive(vesDetails, "ves-endpoint-ip");
1671         if (!cJSON_IsString(vesIp))
1672         {
1673                 printf("Configuration JSON is not as expected: ves-endpoint-ip is not a string");
1674                 cJSON_Delete(jsonConfig);
1675                 return SR_ERR_OPERATION_FAILED;
1676         }
1677
1678         //we set the value of the fault-notification-delay-period object
1679         cJSON_ReplaceItemInObject(vesDetails, "ves-endpoint-ip", cJSON_CreateString(new_ip));
1680
1681         //writing the new JSON to the configuration file
1682         stringConfiguration = cJSON_Print(jsonConfig);
1683         writeConfigFile(stringConfiguration);
1684
1685     if (stringConfiguration != NULL)
1686     {
1687         free(stringConfiguration);
1688         stringConfiguration = NULL;
1689     }
1690
1691         cJSON_Delete(jsonConfig);
1692
1693         return SR_ERR_OK;
1694 }
1695
1696 int ves_port_changed(int new_port)
1697 {
1698         char *stringConfiguration = readConfigFileInString();
1699
1700         if (stringConfiguration == NULL)
1701         {
1702                 printf("Could not read configuration file!\n");
1703                 return SR_ERR_OPERATION_FAILED;
1704         }
1705
1706         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1707         if (jsonConfig == NULL)
1708         {
1709                 free(stringConfiguration);
1710                 const char *error_ptr = cJSON_GetErrorPtr();
1711                 if (error_ptr != NULL)
1712                 {
1713                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
1714                 }
1715                 return SR_ERR_OPERATION_FAILED;
1716         }
1717         //we don't need the string anymore
1718         free(stringConfiguration);
1719         stringConfiguration = NULL;
1720
1721         cJSON *vesDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "ves-endpoint-details");
1722         if (!cJSON_IsObject(vesDetails))
1723         {
1724                 printf("Configuration JSON is not as expected: ves-endpoint-details is not an object");
1725                 cJSON_Delete(jsonConfig);
1726                 return SR_ERR_OPERATION_FAILED;
1727         }
1728
1729         cJSON *vesPort = cJSON_GetObjectItemCaseSensitive(vesDetails, "ves-endpoint-port");
1730         if (!cJSON_IsNumber(vesPort))
1731         {
1732                 printf("Configuration JSON is not as expected: ves-endpoint-port is not a number.");
1733                 cJSON_Delete(jsonConfig);
1734                 return SR_ERR_OPERATION_FAILED;
1735         }
1736
1737         //we set the value of the fault-notification-delay-period object
1738         cJSON_SetNumberValue(vesPort, new_port);
1739
1740         //writing the new JSON to the configuration file
1741         stringConfiguration = cJSON_Print(jsonConfig);
1742         writeConfigFile(stringConfiguration);
1743
1744     if (stringConfiguration != NULL)
1745     {
1746         free(stringConfiguration);
1747         stringConfiguration = NULL;
1748     }
1749
1750         cJSON_Delete(jsonConfig);
1751
1752         return SR_ERR_OK;
1753 }
1754
1755 int ves_registration_changed(cJSON_bool new_bool)
1756 {
1757         char *stringConfiguration = readConfigFileInString();
1758
1759         if (stringConfiguration == NULL)
1760         {
1761                 printf("Could not read configuration file!\n");
1762                 return SR_ERR_OPERATION_FAILED;
1763         }
1764
1765         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1766         if (jsonConfig == NULL)
1767         {
1768                 free(stringConfiguration);
1769                 const char *error_ptr = cJSON_GetErrorPtr();
1770                 if (error_ptr != NULL)
1771                 {
1772                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
1773                 }
1774                 return SR_ERR_OPERATION_FAILED;
1775         }
1776         //we don't need the string anymore
1777         free(stringConfiguration);
1778         stringConfiguration = NULL;
1779
1780         cJSON *vesDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "ves-endpoint-details");
1781         if (!cJSON_IsObject(vesDetails))
1782         {
1783                 printf("Configuration JSON is not as expected: ves-endpoint-details is not an object");
1784                 cJSON_Delete(jsonConfig);
1785                 return SR_ERR_OPERATION_FAILED;
1786         }
1787
1788         cJSON *vesRegistration = cJSON_GetObjectItemCaseSensitive(vesDetails, "ves-registration");
1789         if (!cJSON_IsBool(vesRegistration))
1790         {
1791                 printf("Configuration JSON is not as expected: ves-registration is not a bool.");
1792                 cJSON_Delete(jsonConfig);
1793                 return SR_ERR_OPERATION_FAILED;
1794         }
1795
1796         //we set the value of the ves-registration object
1797         cJSON_ReplaceItemInObject(vesDetails, "ves-registration", cJSON_CreateBool(new_bool));
1798
1799         //writing the new JSON to the configuration file
1800         stringConfiguration = cJSON_Print(jsonConfig);
1801         writeConfigFile(stringConfiguration);
1802
1803     if (stringConfiguration != NULL)
1804     {
1805         free(stringConfiguration);
1806         stringConfiguration = NULL;
1807     }
1808
1809         cJSON_Delete(jsonConfig);
1810
1811         return SR_ERR_OK;
1812 }
1813
1814 int is_netconf_available_changed(cJSON_bool new_bool)
1815 {
1816         char *stringConfiguration = readConfigFileInString();
1817
1818         if (stringConfiguration == NULL)
1819         {
1820                 printf("Could not read configuration file!\n");
1821                 return SR_ERR_OPERATION_FAILED;
1822         }
1823
1824         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1825         if (jsonConfig == NULL)
1826         {
1827                 free(stringConfiguration);
1828                 const char *error_ptr = cJSON_GetErrorPtr();
1829                 if (error_ptr != NULL)
1830                 {
1831                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
1832                 }
1833                 return SR_ERR_OPERATION_FAILED;
1834         }
1835         //we don't need the string anymore
1836         free(stringConfiguration);
1837         stringConfiguration = NULL;
1838
1839         cJSON *notifConfig = cJSON_GetObjectItemCaseSensitive(jsonConfig, "notification-config");
1840         if (!cJSON_IsObject(notifConfig))
1841         {
1842                 printf("Configuration JSON is not as expected: notification-config is not an object");
1843                 cJSON_Delete(jsonConfig);
1844                 return SR_ERR_OPERATION_FAILED;
1845         }
1846
1847         cJSON *isNetconfAvailable = cJSON_GetObjectItemCaseSensitive(notifConfig, "is-netconf-available");
1848         if (!cJSON_IsBool(isNetconfAvailable))
1849         {
1850                 printf("Configuration JSON is not as expected: is-netconf-available is not a bool.");
1851                 cJSON_Delete(jsonConfig);
1852                 return SR_ERR_OPERATION_FAILED;
1853         }
1854
1855         //we set the value of the ves-registration object
1856         cJSON_ReplaceItemInObject(notifConfig, "is-netconf-available", cJSON_CreateBool(new_bool));
1857
1858         //writing the new JSON to the configuration file
1859         stringConfiguration = cJSON_Print(jsonConfig);
1860         writeConfigFile(stringConfiguration);
1861
1862     if (stringConfiguration != NULL)
1863     {
1864         free(stringConfiguration);
1865         stringConfiguration = NULL;
1866     }
1867
1868         cJSON_Delete(jsonConfig);
1869
1870         return SR_ERR_OK;
1871 }
1872
1873 int is_ves_available_changed(cJSON_bool new_bool)
1874 {
1875         char *stringConfiguration = readConfigFileInString();
1876
1877         if (stringConfiguration == NULL)
1878         {
1879                 printf("Could not read configuration file!\n");
1880                 return SR_ERR_OPERATION_FAILED;
1881         }
1882
1883         cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1884         if (jsonConfig == NULL)
1885         {
1886                 free(stringConfiguration);
1887                 const char *error_ptr = cJSON_GetErrorPtr();
1888                 if (error_ptr != NULL)
1889                 {
1890                         fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
1891                 }
1892                 return SR_ERR_OPERATION_FAILED;
1893         }
1894         //we don't need the string anymore
1895         free(stringConfiguration);
1896         stringConfiguration = NULL;
1897
1898         cJSON *notifConfig = cJSON_GetObjectItemCaseSensitive(jsonConfig, "notification-config");
1899         if (!cJSON_IsObject(notifConfig))
1900         {
1901                 printf("Configuration JSON is not as expected: notification-config is not an object");
1902                 cJSON_Delete(jsonConfig);
1903                 return SR_ERR_OPERATION_FAILED;
1904         }
1905
1906         cJSON *isVesAvailable = cJSON_GetObjectItemCaseSensitive(notifConfig, "is-ves-available");
1907         if (!cJSON_IsBool(isVesAvailable))
1908         {
1909                 printf("Configuration JSON is not as expected: is-ves-available is not a bool.");
1910                 cJSON_Delete(jsonConfig);
1911                 return SR_ERR_OPERATION_FAILED;
1912         }
1913
1914         //we set the value of the ves-registration object
1915         cJSON_ReplaceItemInObject(notifConfig, "is-ves-available", cJSON_CreateBool(new_bool));
1916
1917         //writing the new JSON to the configuration file
1918         stringConfiguration = cJSON_Print(jsonConfig);
1919         writeConfigFile(stringConfiguration);
1920
1921     if (stringConfiguration != NULL)
1922     {
1923         free(stringConfiguration);
1924         stringConfiguration = NULL;
1925     }
1926
1927         cJSON_Delete(jsonConfig);
1928
1929         return SR_ERR_OK;
1930 }
1931
1932     int ssh_connections_changed(int number)
1933     {
1934     char *stringConfiguration = readConfigFileInString();
1935
1936     if (stringConfiguration == NULL)
1937     {
1938         printf("Could not read configuration file!\n");
1939         return SR_ERR_OPERATION_FAILED;
1940     }
1941
1942     cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1943     if (jsonConfig == NULL)
1944     {
1945         free(stringConfiguration);
1946         const char *error_ptr = cJSON_GetErrorPtr();
1947         if (error_ptr != NULL)
1948         {
1949             fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
1950         }
1951         return SR_ERR_OPERATION_FAILED;
1952     }
1953     //we don't need the string anymore
1954     free(stringConfiguration);
1955     stringConfiguration = NULL;
1956
1957     cJSON *sshConnections = cJSON_GetObjectItemCaseSensitive(jsonConfig, "ssh-connections");
1958     if (!cJSON_IsNumber(sshConnections))
1959     {
1960         printf("Configuration JSON is not as expected: ssh-connections is not an object");
1961         cJSON_Delete(jsonConfig);
1962         return SR_ERR_OPERATION_FAILED;
1963     }
1964
1965     //we set the value of the ssh-connections object
1966     cJSON_SetNumberValue(sshConnections, number);
1967
1968     //writing the new JSON to the configuration file
1969     stringConfiguration = cJSON_Print(jsonConfig);
1970     writeConfigFile(stringConfiguration);
1971
1972     if (stringConfiguration != NULL)
1973     {
1974         free(stringConfiguration);
1975         stringConfiguration = NULL;
1976     }
1977
1978     cJSON_Delete(jsonConfig);
1979
1980     return SR_ERR_OK;
1981 }
1982
1983 int tls_connections_changed(int number)
1984     {
1985     char *stringConfiguration = readConfigFileInString();
1986
1987     if (stringConfiguration == NULL)
1988     {
1989         printf("Could not read configuration file!\n");
1990         return SR_ERR_OPERATION_FAILED;
1991     }
1992
1993     cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
1994     if (jsonConfig == NULL)
1995     {
1996         free(stringConfiguration);
1997         const char *error_ptr = cJSON_GetErrorPtr();
1998         if (error_ptr != NULL)
1999         {
2000             fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
2001         }
2002         return SR_ERR_OPERATION_FAILED;
2003     }
2004     //we don't need the string anymore
2005     free(stringConfiguration);
2006     stringConfiguration = NULL;
2007
2008     cJSON *tlsConnections = cJSON_GetObjectItemCaseSensitive(jsonConfig, "tls-connections");
2009     if (!cJSON_IsNumber(tlsConnections))
2010     {
2011         printf("Configuration JSON is not as expected: tls-connections is not an object");
2012         cJSON_Delete(jsonConfig);
2013         return SR_ERR_OPERATION_FAILED;
2014     }
2015
2016     //we set the value of the tls-connections object
2017     cJSON_SetNumberValue(tlsConnections, number);
2018
2019     //writing the new JSON to the configuration file
2020     stringConfiguration = cJSON_Print(jsonConfig);
2021     writeConfigFile(stringConfiguration);
2022
2023     if (stringConfiguration != NULL)
2024     {
2025         free(stringConfiguration);
2026         stringConfiguration = NULL;
2027     }
2028
2029     cJSON_Delete(jsonConfig);
2030
2031     return SR_ERR_OK;
2032 }
2033
2034 /*
2035 curl -X POST -H 'Content-Type: application/json' -i http://localhost:5000/extend-ports --data '{"number-of-ports":12}'
2036 */
2037 int send_k8s_extend_port(void)
2038 {
2039     int num_of_ports = getSshConnectionsFromConfigJson() + getTlsConnectionsFromConfigJson();
2040
2041     CURLcode res;
2042
2043     curl_easy_reset(curl_k8s);
2044     set_curl_common_info_k8s();
2045
2046     char url_for_curl[100];
2047     sprintf(url_for_curl, "http://localhost:5000/extend-ports");
2048
2049     curl_easy_setopt(curl_k8s, CURLOPT_URL, url_for_curl);
2050
2051     char post_data_json[1500];
2052
2053     sprintf(post_data_json,
2054             "{\"number-of-ports\":%d}",
2055             num_of_ports);
2056
2057     printf("Post data:\n%s\n", post_data_json);
2058
2059     curl_easy_setopt(curl_k8s, CURLOPT_POSTFIELDS, post_data_json);
2060     curl_easy_setopt(curl_k8s, CURLOPT_CUSTOMREQUEST, "POST");
2061
2062     res = curl_easy_perform(curl_k8s);
2063     if (res != CURLE_OK)
2064     {
2065         printf("cURL failed to url=%s\n", url_for_curl);
2066     }
2067
2068     long http_response_code = 0;
2069     curl_easy_getinfo (curl_k8s, CURLINFO_RESPONSE_CODE, &http_response_code);
2070     if (http_response_code >= 200 && http_response_code <= 226 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
2071     {
2072         printf("cURL succeeded to url=%s\n", url_for_curl);
2073     }
2074     else
2075     {
2076         printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
2077         return SR_ERR_OPERATION_FAILED;
2078     }
2079
2080     return SR_ERR_OK;
2081 }
2082
2083 /*
2084 curl -X POST -H 'Content-Type: application/json' -i http://localhost:5000/scale --data '{"simulatedDevices":2}'
2085 */
2086 int send_k8s_scale(int number_of_devices)
2087 {
2088     CURLcode res;
2089
2090     curl_easy_reset(curl_k8s);
2091     set_curl_common_info_k8s();
2092
2093     char url_for_curl[100];
2094     sprintf(url_for_curl, "http://localhost:5000/scale");
2095
2096     curl_easy_setopt(curl_k8s, CURLOPT_URL, url_for_curl);
2097
2098     char post_data_json[1500];
2099
2100     sprintf(post_data_json,
2101             "{\"simulatedDevices\":%d}",
2102             number_of_devices);
2103
2104     printf("Post data:\n%s\n", post_data_json);
2105
2106     curl_easy_setopt(curl_k8s, CURLOPT_POSTFIELDS, post_data_json);
2107     curl_easy_setopt(curl_k8s, CURLOPT_CUSTOMREQUEST, "POST");
2108
2109     res = curl_easy_perform(curl_k8s);
2110     if (res != CURLE_OK)
2111     {
2112         printf("cURL failed to url=%s\n", url_for_curl);
2113     }
2114
2115     long http_response_code = 0;
2116     curl_easy_getinfo (curl_k8s, CURLINFO_RESPONSE_CODE, &http_response_code);
2117     if (http_response_code >= 200 && http_response_code <= 226 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
2118     {
2119         printf("cURL succeeded to url=%s\n", url_for_curl);
2120     }
2121     else
2122     {
2123         printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
2124         return SR_ERR_OPERATION_FAILED;
2125     }
2126
2127     return SR_ERR_OK;
2128 }