7e8588d5f3d715df539fba04f97e06e669008bec
[sim/o1-interface.git] / ntsimulator / ntsim-ng / core / docker.c
1 /*************************************************************************
2 *
3 * Copyright 2020 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 #define _GNU_SOURCE
19
20 #include "docker.h"
21 #include "utils/log_utils.h"
22 #include "utils/sys_utils.h"
23 #include "utils/http_client.h"
24 #include "core/framework.h"
25 #include "core/session.h"
26 #include "core/context.h"
27 #include <sysrepo.h>
28 #include <dirent.h>
29 #include <assert.h>
30 #include <sys/sysinfo.h>
31
32 #include <cjson/cJSON.h>
33
34 #define DOCKER_SOCK_FNAME       "/var/run/docker.sock"
35
36 static cJSON *docker_network_info = 0;
37
38 struct installable_module {
39     char *name;
40     char *fullpath;
41     bool installed;
42     bool submodule;
43 };
44
45 typedef struct {
46     char *name;
47     char *value;
48 } environment_var_t;
49
50 static environment_var_t *docker_environment_var;
51 static int docker_environment_var_count = 0;
52
53 static int get_installable_modules(struct installable_module **modules);    //list available modules for install
54 static void list_yangs(const char *path, struct installable_module **modules, int *total);
55
56 static char *docker_parse_json_message(const char *json_string);
57
58 static int docker_container_create(const char *image, manager_network_function_instance_t *instance);
59 static int docker_container_start(manager_network_function_instance_t *instance);
60 static int docker_container_inspect(manager_network_function_instance_t *instance);
61
62
63 bool docker_container_init(void) {
64     int rc;
65
66     sr_log_stderr(SR_LL_NONE);
67     log_message(1, "Entering container-init mode...\n");
68
69     // connect to sysrepo
70     rc = sr_connect(0, &session_connection);
71     if(SR_ERR_OK != rc) {
72         log_error("sr_connect failed");
73         return false;
74     }
75
76     /* get context */
77     session_context = (struct ly_ctx *)sr_get_context(session_connection);
78     if(session_context == 0) {
79         log_error("sr_get_context failed");
80         return false;
81     }
82
83     /* install yang files */
84     log_message(1, "Installing yang files...\n");
85     struct installable_module *modules;
86     int total_modules = get_installable_modules(&modules);
87     log_message(1, "Found total modules: %d\n", total_modules);
88
89     int old_failed_installations = 1;
90     int failed_installations = 0;
91     int install_round = 0;
92     while(failed_installations != old_failed_installations) {
93         old_failed_installations = failed_installations;
94         failed_installations = 0;
95         install_round++;
96         for(int i = 0; i < total_modules; i++) {
97             if(!modules[i].installed) {
98                 modules[i].submodule = context_yang_is_module(modules[i].fullpath);
99                 if(!modules[i].submodule) {
100                     if(!framework_is_docker_excluded_module(modules[i].name)) {
101                         log_message(1, "[round %d] trying to install module %s from %s... ", install_round, modules[i].name, modules[i].fullpath);
102                         if(!context_module_install(modules[i].name, modules[i].fullpath)) {
103                             failed_installations++;
104                             log_message(1, LOG_COLOR_BOLD_YELLOW"failed"LOG_COLOR_RESET"\n");
105                         }
106                         else {
107                             log_message(1, LOG_COLOR_BOLD_GREEN"done"LOG_COLOR_RESET"\n");
108                             modules[i].installed = true;
109                         }
110                     }
111                     else {
112                         log_message(1, "[round %d] not installing module %s as it's excluded in config.\n", install_round, modules[i].name);
113                         modules[i].installed = true;
114                     }
115                 }
116                 else {
117                     log_message(1, "[round %d] %s is a submodule... "LOG_COLOR_BOLD_YELLOW"skipping"LOG_COLOR_RESET"\n", install_round, modules[i].name);
118                     modules[i].installed = true;
119                 }
120             }
121         }
122     }
123
124     if(failed_installations != 0) {
125         log_error("Failed to install all modules in %d rounds...", install_round);
126         return false;
127     }
128     else {
129         log_message(1, LOG_COLOR_BOLD_GREEN"successfully"LOG_COLOR_RESET" installed "LOG_COLOR_BOLD_GREEN"ALL"LOG_COLOR_RESET" modules in "LOG_COLOR_BOLD_YELLOW"%d"LOG_COLOR_RESET" rounds\n", (install_round - 1));
130     }
131
132     //set access for all installed modules
133     log_message(1, "Setting access configuration for installed modules... ");
134     for(int i = 0; i < total_modules; i++) {
135         if((!framework_is_docker_excluded_module(modules[i].name)) && (!modules[i].submodule)) {
136             if(!context_module_set_access(modules[i].name)) {
137                 log_error("Failed to set access to module %s...", modules[i].name);
138                 return false;
139             }
140         }
141     }
142     log_message(1, LOG_COLOR_BOLD_GREEN"done"LOG_COLOR_RESET"\n");
143
144     //cleanup module-install used memory
145     for(int i = 0; i < total_modules; i++) {
146         free(modules[i].name);
147         free(modules[i].fullpath);
148     }
149     free(modules);
150
151     //get context
152     session_context = (struct ly_ctx *)sr_get_context(session_connection);
153     if(session_context == 0) {
154         log_error("sr_get_context failed");
155         return false;
156     }
157
158     //init context so we can see all the available modules, features, etc
159     rc = context_init(session_context);
160     if(rc != 0) {
161         log_error("context_init() failed");
162         return false;
163     }
164
165     /* enable features */
166     log_message(1, "Enabling yang features...\n");
167     char **available_features;
168     int total_available_features;
169     total_available_features = context_get_features(&available_features);
170     log_message(1, "Found total features: %d\n", total_available_features);
171     for(int i = 0; i < total_available_features; i++) {
172         log_message(1, "feature %s: ", available_features[i]);
173
174         if(!context_get_feature_enabled(available_features[i])) {
175             if(!framework_is_docker_excluded_feature(available_features[i])) {
176                 if(context_feature_enable(available_features[i])) {
177                     log_message(1, "enabling... "LOG_COLOR_BOLD_GREEN"done"LOG_COLOR_RESET"\n");
178                 }
179                 else {
180                     log_error("enabling... failed\n");
181                 }
182             }
183             else {
184                 log_message(1, "excluded in config, skipping\n");
185             }
186         }
187         else {
188             log_message(1, "already "LOG_COLOR_BOLD_GREEN"enabled"LOG_COLOR_RESET", skipping.\n");
189         }
190     }
191     for(int i = 0; i < total_available_features; i++) {
192         free(available_features[i]);
193     }
194     free(available_features);
195
196     sr_disconnect(session_connection);
197     context_free();
198
199     log_message(1, LOG_COLOR_BOLD_GREEN"ntsim successfully initialized Docker container"LOG_COLOR_RESET"\n");
200     return true;
201 }
202
203 static int get_installable_modules(struct installable_module **modules) {
204     int total = 0;
205     *modules = 0;
206     list_yangs("/opt/dev/deploy/yang", modules, &total);
207     return total;
208 }
209
210 static void list_yangs(const char *path, struct installable_module **modules, int *total) {
211     DIR *d;
212     struct dirent *dir;
213     d = opendir(path);
214     if(d) {
215         while((dir = readdir(d)) != NULL) {
216             if(dir->d_type == DT_DIR) {
217                 if(strcmp(dir->d_name, ".") != 0 && strcmp(dir->d_name, "..") != 0)
218                 {
219                     char new_path[1024];
220                     snprintf(new_path, sizeof(new_path), "%s/%s", path, dir->d_name);
221                     list_yangs(new_path, modules, total);
222                 }
223             } else {
224                 if(strstr(dir->d_name, ".yang") != 0) {
225                     *modules = (struct installable_module *)realloc(*modules, sizeof(struct installable_module) * (*total + 1));
226                     if(!*modules) {
227                         log_error("could not realloc");
228                         return;
229                     }
230
231                     (*modules)[*total].name = (char*)malloc(sizeof(char) * (strlen(dir->d_name) + 1));
232                     if(!(*modules)[*total].name) {
233                         log_error("could not alloc");
234                         return;
235                     }
236                     strcpy((*modules)[*total].name, dir->d_name);
237                     (*modules)[*total].name[strlen(dir->d_name) - 5] = 0;   //extract ".yang"
238                     char *rev = strstr((*modules)[*total].name, "@");
239                     if(rev) { //extract revision, if exists
240                         *rev = 0;
241                     }
242
243                     (*modules)[*total].fullpath = (char*)malloc(sizeof(char) * (strlen(path) + 1 + strlen(dir->d_name) + 1));
244                     if(!(*modules)[*total].fullpath) {
245                         log_error("could not alloc");
246                         return;
247                     }
248                     sprintf((*modules)[*total].fullpath, "%s/%s", path, dir->d_name);
249
250                     (*modules)[*total].installed = false;
251                     (*modules)[*total].submodule = false;
252
253                     (*total)++;
254                 }
255             }
256         }
257         closedir(d);
258     }
259 }
260
261 int docker_device_init(void) {
262     char *response = 0;
263     char url[512];
264     sprintf(url, "http://v%s/containers/%s/json", framework_environment.docker_engine_version, framework_environment.hostname);
265
266     int rc = http_socket_request(url, DOCKER_SOCK_FNAME, "GET", 0, 0, &response);
267     if(rc != NTS_ERR_OK) {
268         log_error("http_socket_request failed");
269         return NTS_ERR_FAILED;
270     }
271
272     cJSON *json_response = cJSON_Parse(response);
273     free(response);
274
275     if(json_response == 0) {
276         log_error("could not parse JSON response for url=\"%s\"", url);
277         return NTS_ERR_FAILED;
278     }
279
280     cJSON *hostConfig = cJSON_GetObjectItemCaseSensitive(json_response, "HostConfig");
281     if(hostConfig == 0) {
282         log_error("could not get HostConfig object");
283         cJSON_Delete(json_response);
284         return NTS_ERR_FAILED;
285     }
286
287     cJSON *networkMode = cJSON_GetObjectItemCaseSensitive(hostConfig, "NetworkMode");
288     if(networkMode == 0) {
289         log_error("could not get NetworkMode object");
290         cJSON_Delete(json_response);
291         return NTS_ERR_FAILED;
292     }
293
294     docker_network_info = cJSON_Duplicate(networkMode, 1);
295     cJSON_Delete(json_response);
296
297     log_message(2, "finished parsing docker inspect...\n");
298
299
300     docker_environment_var_count = 5;
301     docker_environment_var = (environment_var_t *)malloc(sizeof(environment_var_t) * docker_environment_var_count);
302     if(docker_environment_var == 0) {
303         log_error("malloc failed");
304         cJSON_Delete(networkMode);
305         return NTS_ERR_FAILED;
306     }
307     
308     //set env variables for network functions
309     docker_environment_var[0].name = ENV_VAR_SSH_CONNECTIONS;
310     asprintf(&docker_environment_var[0].value, "%d", framework_environment.ssh_connections);
311     docker_environment_var[1].name = ENV_VAR_TLS_CONNECTIONS;
312     asprintf(&docker_environment_var[1].value, "%d", framework_environment.tls_connections);
313     docker_environment_var[2].name = ENV_VAR_IPV6ENABLED;
314     docker_environment_var[2].value = framework_environment.ip_v6_enabled ? "true" : "false";
315     docker_environment_var[3].name = ENV_VAR_HOST_IP;
316     docker_environment_var[3].value = framework_environment.host_ip;
317     docker_environment_var[4].name = ENV_VAR_HOST_BASE_PORT;
318     // docker_environment_var[4].value = will be updated by docker_create...
319
320     return NTS_ERR_OK;
321 }
322
323 int docker_device_start(const manager_network_function_type *function_type, manager_network_function_instance_t *instance) {
324     assert(function_type);
325     assert(instance);
326     assert(docker_network_info);
327
328     char image[512];
329     if(function_type->docker_version_tag && (function_type->docker_version_tag[0] != 0)) {
330         if(function_type->docker_repository && (function_type->docker_repository[0] != 0) && (strcmp(function_type->docker_repository, "local") != 0)) {
331             sprintf(image, "%s/%s:%s", function_type->docker_repository, function_type->docker_image_name, function_type->docker_version_tag);    
332         }
333         else {
334             sprintf(image, "%s:%s", function_type->docker_image_name, function_type->docker_version_tag);
335         }
336     }
337     else {
338         if(function_type->docker_repository && (function_type->docker_repository[0] != 0) && (strcmp(function_type->docker_repository, "local") != 0)) {
339             sprintf(image, "%s/%s:latest", function_type->docker_repository, function_type->docker_image_name);    
340         }
341         else {
342             sprintf(image, "%s:latest", function_type->docker_image_name);
343         }
344     }
345
346     int rc = docker_container_create(image, instance);
347     if(rc != NTS_ERR_OK) {
348         log_error("docker_container_create failed");
349         return NTS_ERR_FAILED;
350     }
351
352     rc = docker_container_start(instance);
353     if(rc != NTS_ERR_OK) {
354         log_error("docker_container_start failed");
355         docker_device_stop(instance);
356         return NTS_ERR_FAILED;
357     }
358
359     rc = docker_container_inspect(instance);
360     if(rc != NTS_ERR_OK) {
361         log_error("docker_container_inspect failed");
362         docker_device_stop(instance);
363         return NTS_ERR_FAILED;
364     }
365
366     log_message(2, "docker_device_start: docker_id: %s | name: %s | docker_ip: %s | host_port: %d\n", instance->docker_id, instance->name, instance->docker_ip, instance->host_port);
367
368     return NTS_ERR_OK;
369 }
370
371 int docker_device_stop(manager_network_function_instance_t *instance) {
372     assert(instance);
373
374     char url[512];
375     sprintf(url, "http://v%s/containers/%s?force=true", framework_environment.docker_engine_version, instance->docker_id);
376
377     int rc = http_socket_request(url, DOCKER_SOCK_FNAME, "DELETE", "", 0, 0);
378     if(rc != NTS_ERR_OK) {
379         log_error("http_socket_request failed");
380         return NTS_ERR_FAILED;
381     }
382
383     return NTS_ERR_OK;
384 }
385
386 docker_usage_t docker_usage_get(const manager_network_function_type *function_type, int function_type_count) {
387     docker_usage_t ret;
388     ret.cpu = 0;
389     ret.mem = 0;
390
391     char buffer[1024];
392     char full_text[1024 * 1024];
393     FILE* pipe = popen("docker stats --no-stream --format \"table {{.ID}}|{{.CPUPerc}}|{{.MemUsage}}|\"", "r");
394     if (!pipe) {
395         log_error("popen() failed");
396         return ret;
397     }
398
399     int n = 1;
400     int k = 0;
401     while(n != 0) {
402         n = fread(buffer, 1, sizeof(buffer), pipe);
403         for(int i = 0; i < n; i++) {
404             full_text[k++] = buffer[i];
405         }
406     }
407     pclose(pipe);
408     full_text[k] = 0;
409
410     char *c = full_text;
411     
412     c = strstr(c, "\n");
413     while(c) {
414         char line[1024];
415         line[0] = 0;
416
417         char *d = strstr(c + 1, "\n");
418         if(d) {
419             for(char *i = c + 1; i < d; i++) {
420                 line[i - c - 1] = *i;
421                 line[i - c] = 0;
422             }
423
424             char container_name[1024];
425             char buff[1024];
426             float cpu = 0.0;
427             float mem = 0.0;
428
429             char *x = strstr(line, "|");
430             for(char *i = line; i < x; i++) {
431                 container_name[i - line] = *i;
432                 container_name[i - line + 1] = 0;
433             }
434
435             char *start = x + 1;
436             x = strstr(start, "|");
437             for(char *i = start; i < x; i++) {
438                 if(((*i >= '0') && (*i <= '9')) || (*i == '.')) {
439                     buff[i - start] = *i;
440                 }
441                 else {
442                     buff[i - start] = 0;
443                     break;
444                 }
445             }
446
447             cpu = strtof(buff, 0);
448
449             int mul = 1;
450             start = x + 1;
451             x = strstr(start, "|");
452             for(char *i = start; i < x; i++) {
453                 if(((*i >= '0') && (*i <= '9')) || (*i == '.')) {
454                     buff[i - start] = *i;
455                 }
456                 else {
457                     if(*i == 'G') {
458                         mul = 1024;
459                     }
460                     buff[i - start] = 0;
461                     break;
462                 }
463             }
464
465             mem = strtof(buff, 0) * mul;
466             
467             
468             if(strcmp(container_name, framework_environment.hostname) == 0) {
469                 ret.cpu += cpu;
470                 ret.mem += mem;
471             }
472             else {
473                 for(int i = 0; i < function_type_count; i++) {
474                     for(int j = 0; j < function_type[i].started_instances; j++) {
475                         
476                         if(strcmp(container_name, function_type[i].instance[j].docker_id) == 0) {
477                             ret.cpu += cpu;
478                             ret.mem += mem;
479                             break;
480                         }
481                     }
482                 }
483             }
484         }
485         
486         c = d;
487     }
488
489
490     ret.cpu /= get_nprocs();
491
492     return ret;
493 }
494
495 static char *docker_parse_json_message(const char *json_string) {
496     assert(json_string);
497
498     cJSON *json_response = cJSON_Parse(json_string);
499     if(json_response == 0) {
500         log_error("cJSON_Parse failed");
501         return 0;
502     }
503
504     cJSON *message;
505     message = cJSON_GetObjectItem(json_response, "message");
506     if(message == 0) {
507         log_error("json parsing failed");
508         cJSON_Delete(json_response);
509         return 0;
510     }
511
512     char *ret = strdup(message->valuestring);
513     cJSON_Delete(json_response);
514     return ret;
515 }
516
517 static int docker_container_create(const char *image, manager_network_function_instance_t *instance) {
518     assert(image);
519     assert(instance);
520
521     cJSON *postDataJson = cJSON_CreateObject();
522     if(cJSON_AddStringToObject(postDataJson, "Image", image) == 0) {
523         log_error("could not create JSON object: Image");
524         return NTS_ERR_FAILED;
525     }
526
527     if(cJSON_AddStringToObject(postDataJson, "Hostname", instance->name) == 0) {
528         log_error("could not create JSON object: Hostname");
529         cJSON_Delete(postDataJson);
530         return NTS_ERR_FAILED;
531     }    
532
533     cJSON *hostConfig = cJSON_CreateObject();
534     if(hostConfig == 0) {
535         log_error("could not create JSON object: HostConfig");
536         cJSON_Delete(postDataJson);
537         return NTS_ERR_FAILED;
538     }
539     if(cJSON_AddItemToObject(postDataJson, "HostConfig", hostConfig) == 0) {
540         log_error("cJSON_AddItemToObject failed");
541         cJSON_Delete(postDataJson);
542         return NTS_ERR_FAILED;
543     }
544
545     cJSON *portBindings = cJSON_CreateObject();
546     if(portBindings == 0) {
547         printf("could not create JSON object: PortBindings");
548         cJSON_Delete(postDataJson);
549         return NTS_ERR_FAILED;
550     }
551     if(cJSON_AddItemToObject(hostConfig, "PortBindings", portBindings) == 0) {
552         log_error("cJSON_AddItemToObject failed");
553         cJSON_Delete(postDataJson);
554         return NTS_ERR_FAILED;
555     }
556     
557     for(int i = 0; i < (framework_environment.ssh_connections + framework_environment.tls_connections + framework_environment.ftp_connections + framework_environment.sftp_connections); ++i) {
558         cJSON *port = cJSON_CreateArray();
559         if(port == 0) {
560             log_error("could not create JSON object: port");
561             cJSON_Delete(postDataJson);
562             return NTS_ERR_FAILED;
563         }
564
565         char dockerContainerPort[20];
566         if(i < framework_environment.ssh_connections + framework_environment.tls_connections) {
567             sprintf(dockerContainerPort, "%d/tcp", STANDARD_NETCONF_PORT + i);
568         }
569         else if(i < (framework_environment.ssh_connections + framework_environment.tls_connections + framework_environment.ftp_connections)) {
570             sprintf(dockerContainerPort, "%d/tcp", STANDARD_FTP_PORT);
571         }
572         else if(i < (framework_environment.ssh_connections + framework_environment.tls_connections + framework_environment.ftp_connections + framework_environment.sftp_connections)) {
573             sprintf(dockerContainerPort, "%d/tcp", STANDARD_SFTP_PORT);
574         }
575         if(cJSON_AddItemToObject(portBindings, dockerContainerPort, port) == 0) {
576             log_error("cJSON_AddItemToObject failed");
577             cJSON_Delete(postDataJson);
578             return NTS_ERR_FAILED;
579         }
580
581         cJSON *hostPort = cJSON_CreateObject();
582         if(hostPort == 0) {
583             log_error("could not create JSON object: HostPort");
584             cJSON_Delete(postDataJson);
585             return NTS_ERR_FAILED;
586         }
587
588         char dockerHostPort[20];
589         sprintf(dockerHostPort, "%d", instance->host_port + i);
590         if(cJSON_AddStringToObject(hostPort, "HostPort", dockerHostPort) == 0) {
591             log_error("could not create JSON object: HostPortString");
592             cJSON_Delete(postDataJson);
593             return NTS_ERR_FAILED;
594         }
595
596         if(cJSON_AddStringToObject(hostPort, "HostIp", "0.0.0.0") == 0) {   //instance->host_ip
597             log_error("could not create JSON object: HostIpString");
598             cJSON_Delete(postDataJson);
599             return NTS_ERR_FAILED;
600         }
601
602         if(cJSON_AddItemToArray(port, hostPort) == 0) {
603             log_error("cJSON_AddItemToArray failed");
604             cJSON_Delete(postDataJson);
605             return NTS_ERR_FAILED;
606         }
607     }
608
609     
610     //environment vars start
611     asprintf(&docker_environment_var[4].value, "%d", instance->host_port);
612
613     cJSON *env_variables_array = cJSON_CreateArray();
614     if(env_variables_array == 0) {
615         log_error("Could not create JSON object: Env array");
616         return NTS_ERR_FAILED;
617     }
618     cJSON_AddItemToObject(postDataJson, "Env", env_variables_array);
619
620     for(int i = 0; i < docker_environment_var_count; i++) {
621         if(docker_environment_var[i].value) {
622             char *environment_var = 0;
623             asprintf(&environment_var, "%s=%s", docker_environment_var[i].name, docker_environment_var[i].value);
624
625             cJSON *env_var_obj = cJSON_CreateString(environment_var);
626             if(env_var_obj == 0) {
627                 log_error("could not create JSON object");
628                 return NTS_ERR_FAILED;
629             }
630             cJSON_AddItemToArray(env_variables_array, env_var_obj);
631
632             free(environment_var);
633         }
634     }
635
636     free(docker_environment_var[4].value);
637     //environment vars finished
638
639
640     cJSON *netMode = cJSON_Duplicate(docker_network_info, 1);
641     cJSON_AddItemToObject(hostConfig, "NetworkMode", netMode);
642
643     char *post_data_string = 0;
644     post_data_string = cJSON_PrintUnformatted(postDataJson);
645     cJSON_Delete(postDataJson);
646
647     char url[512];
648     sprintf(url, "http:/v%s/containers/create?name=%s", framework_environment.docker_engine_version, instance->name);
649
650     char *response = 0;
651     int response_code = 0;
652     int rc = http_socket_request(url, DOCKER_SOCK_FNAME, "POST", post_data_string, &response_code, &response);
653     free(post_data_string);
654     if(rc != NTS_ERR_OK) {
655         log_error("http_socket_request failed");
656         return NTS_ERR_FAILED;
657     }
658
659     if(response_code != 201) {
660         char *message = docker_parse_json_message(response);
661         log_error("docker_container_create failed (%d): %s", response_code, message);
662         free(message);
663         free(response);
664         return NTS_ERR_FAILED;
665     }
666     else {
667         cJSON *json_response = cJSON_Parse(response);
668         free(response);
669         const cJSON *container_id = 0;
670
671         container_id = cJSON_GetObjectItemCaseSensitive(json_response, "Id");
672
673         if(cJSON_IsString(container_id) && (container_id->valuestring != 0)) {
674             char container_id_short[13];
675             memset(container_id_short, '\0', sizeof(container_id_short));
676             strncpy(container_id_short, container_id->valuestring, 12);
677
678             instance->docker_id = strdup(container_id_short);
679
680             cJSON_Delete(json_response);
681             return NTS_ERR_OK;
682         }
683         else {
684             cJSON_Delete(json_response);
685             return NTS_ERR_FAILED;
686         }
687     }
688 }
689
690 static int docker_container_start(manager_network_function_instance_t *instance) {
691     assert(instance);
692
693     char url[512];
694     sprintf(url, "http://v%s/containers/%s/start", framework_environment.docker_engine_version, instance->docker_id);
695
696     char *response = 0;
697     int response_code = 0;
698     int rc = http_socket_request(url, DOCKER_SOCK_FNAME, "POST", "", &response_code, &response);
699     if(rc != NTS_ERR_OK) {
700         log_error("http_socket_request failed");
701         return NTS_ERR_FAILED;
702     }
703     else {
704         if(response_code == 304) {
705             log_error("docker_container_start failed (%d): container already started\n", response_code);
706             free(response);
707             return NTS_ERR_FAILED;
708         }
709         else if(response_code != 204) {
710             char *message = docker_parse_json_message(response);
711             log_error("docker_container_start failed (%d): %s", response_code, message);
712             free(message);
713             free(response);
714             return NTS_ERR_FAILED;
715         }
716         
717     }
718
719     return NTS_ERR_OK;
720 }
721
722 static int docker_container_inspect(manager_network_function_instance_t *instance) {
723     assert(instance);
724
725     char url[512];
726     sprintf(url, "http://v%s/containers/%s/json", framework_environment.docker_engine_version, instance->docker_id);
727
728     char *response = 0;    
729     int rc = http_socket_request(url, DOCKER_SOCK_FNAME, "GET", "", 0, &response);
730     if(rc != NTS_ERR_OK) {
731         log_error("http_socket_request failed");
732         return NTS_ERR_FAILED;
733     }
734
735     cJSON *json_response = cJSON_Parse(response);
736     free(response);
737     if(json_response == 0) {
738         log_error("cJSON_Parse failed");
739         return NTS_ERR_FAILED;
740     }
741
742
743     cJSON *main_node = cJSON_GetObjectItem(json_response, "NetworkSettings");
744     if(main_node == 0) {
745         log_error("json parsing failed");
746         cJSON_Delete(json_response);
747         return NTS_ERR_FAILED;
748     }
749
750     cJSON *node = cJSON_GetObjectItem(main_node, "Networks");
751     if(node == 0) {
752         log_error("json parsing failed");
753         cJSON_Delete(json_response);
754         return NTS_ERR_FAILED;
755     }
756         
757     node = node->child;   //get info from the first in array
758     if(node == 0) {
759         log_error("json parsing failed");
760         cJSON_Delete(json_response);
761         return NTS_ERR_FAILED;
762     }
763
764     cJSON *element;
765     if(framework_environment.ip_v6_enabled) {
766         element = cJSON_GetObjectItem(node, "GlobalIPv6Address");
767     }
768     else {
769         element = cJSON_GetObjectItem(node, "IPAddress");
770     } 
771
772     if(element == 0) {
773         log_error("json parsing failed");
774         cJSON_Delete(json_response);
775         return NTS_ERR_FAILED;
776     }
777
778     instance->docker_ip = strdup(element->valuestring);
779
780     cJSON_Delete(json_response);
781     return NTS_ERR_OK;
782 }