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