Add network emulation feature.
[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/nts_utils.h"
24 #include "utils/http_client.h"
25 #include "core/framework.h"
26 #include "core/session.h"
27 #include "core/context.h"
28 #include <sysrepo.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 typedef struct {
39     char *name;
40     char *value;
41 } environment_var_t;
42
43 static environment_var_t *docker_environment_var;
44 static int docker_environment_var_count = 0;
45
46 static char *docker_parse_json_message(const char *json_string);
47 static int docker_add_port(cJSON *portBindings, uint16_t docker_port, uint16_t host_port);
48
49 static int docker_populate_images(docker_context_t *context, int count, const char *min_version);
50 static int docker_container_create(const char *image, docker_container_t *container);
51 static int docker_container_start(docker_container_t *container);
52 static int docker_container_inspect(docker_container_t *container);
53
54 int docker_init(const char **filter, int filter_count, const char *min_version, docker_context_t **context) {
55     assert(filter);
56     assert(filter_count);
57     assert(context);
58
59     char *response = 0;
60     char url[512];
61     sprintf(url, "http://v%s/containers/%s/json", framework_environment.settings.docker_engine_version, framework_environment.settings.hostname);
62
63     int rc = http_socket_request(url, DOCKER_SOCK_FNAME, "GET", 0, 0, &response);
64     if(rc != NTS_ERR_OK) {
65         log_error("http_socket_request failed\n");
66         return NTS_ERR_FAILED;
67     }
68
69     cJSON *json_response = cJSON_Parse(response);
70     free(response);
71
72     if(json_response == 0) {
73         log_error("could not parse JSON response for url=\"%s\"\n", url);
74         return NTS_ERR_FAILED;
75     }
76
77     cJSON *hostConfig = cJSON_GetObjectItemCaseSensitive(json_response, "HostConfig");
78     if(hostConfig == 0) {
79         log_error("could not get HostConfig object\n");
80         cJSON_Delete(json_response);
81         return NTS_ERR_FAILED;
82     }
83
84     cJSON *networkMode = cJSON_GetObjectItemCaseSensitive(hostConfig, "NetworkMode");
85     if(networkMode == 0) {
86         log_error("could not get NetworkMode object\n");
87         cJSON_Delete(json_response);
88         return NTS_ERR_FAILED;
89     }
90
91     docker_network_info = cJSON_Duplicate(networkMode, 1);
92     cJSON_Delete(json_response);
93
94     log_add_verbose(2, "finished parsing docker inspect...\n");
95
96     docker_environment_var_count = 9;
97     docker_environment_var = (environment_var_t *)malloc(sizeof(environment_var_t) * docker_environment_var_count);
98     if(docker_environment_var == 0) {
99         log_error("malloc failed\n");
100         cJSON_Delete(networkMode);
101         return NTS_ERR_FAILED;
102     }
103     
104     //set env variables for network functions
105     docker_environment_var[0].name = ENV_VAR_SSH_CONNECTIONS;
106     asprintf(&docker_environment_var[0].value, "%d", framework_environment.settings.ssh_connections);
107     docker_environment_var[1].name = ENV_VAR_TLS_CONNECTIONS;
108     asprintf(&docker_environment_var[1].value, "%d", framework_environment.settings.tls_connections);
109     docker_environment_var[2].name = ENV_VAR_IPV6ENABLED;
110     docker_environment_var[2].value = framework_environment.settings.ip_v6_enabled ? "true" : "false";
111     docker_environment_var[3].name = ENV_VAR_HOST_IP;
112     docker_environment_var[3].value = framework_environment.host.ip;
113
114     docker_environment_var[4].name = ENV_VAR_HOST_NETCONF_SSH_BASE_PORT;
115     // docker_environment_var[4].value = will be updated by docker_create...
116     docker_environment_var[5].name = ENV_VAR_HOST_NETCONF_TLS_BASE_PORT;
117     // docker_environment_var[5].value = will be updated by docker_create...
118     docker_environment_var[6].name = ENV_VAR_HOST_TRANSFER_FTP_BASE_PORT;
119     // docker_environment_var[6].value = will be updated by docker_create...
120     docker_environment_var[7].name = ENV_VAR_HOST_TRANSFER_SFTP_BASE_PORT;
121     // docker_environment_var[7].value = will be updated by docker_create...
122
123     docker_environment_var[8].name = ENV_VAR_VES_COMMON_HEADER_VERSION;
124     docker_environment_var[8].value = framework_environment.ves_endpoint.common_header_version;
125
126
127
128     //docker context build
129     *context = (docker_context_t *)malloc(sizeof(docker_context_t) * filter_count);
130     if(*context == 0) {
131         log_error("bad malloc\n");
132         free(docker_environment_var[0].value);
133         free(docker_environment_var[1].value);
134         free(docker_environment_var);
135         return NTS_ERR_FAILED;
136     }
137
138     docker_context_t *ctx = *context;
139     for(int i = 0; i < filter_count; i++) {
140         ctx[i].image = strdup(filter[i]);
141         ctx[i].available_images = 0;
142         ctx[i].available_images_count = 0;
143     }
144
145     docker_populate_images(ctx, filter_count, min_version);
146
147     return NTS_ERR_OK;
148 }
149
150 void docker_free(docker_context_t *context, int count) {
151     free(docker_environment_var[0].value);
152     free(docker_environment_var[1].value);
153     free(docker_environment_var);
154
155     for(int i = 0; i < count; i++) {
156         free(context[i].image);
157         for(int j = 0; j < context[i].available_images_count; j++) {
158             free(context[i].available_images[j].repo);
159             free(context[i].available_images[j].tag);
160         }
161         free(context[i].available_images);
162     }
163 }
164
165 int docker_start(const char *container_name, const char *tag, const char *image, const char *repo, uint16_t host_netconf_ssh_port, uint16_t host_netconf_tls_port, uint16_t host_ftp_port, uint16_t host_sftp_port, docker_container_t *container) {
166     assert(container_name);
167     assert(image);
168     assert(container);
169     assert(docker_network_info);
170
171     char image_full[512];
172     if(tag && (tag[0] != 0)) {
173         if(repo && (repo[0] != 0) && (strcmp(repo, "local") != 0)) {
174             sprintf(image_full, "%s/%s:%s", repo, image, tag);    
175         }
176         else {
177             sprintf(image_full, "%s:%s", image, tag);
178         }
179     }
180     else {
181         if(repo && (repo[0] != 0) && (strcmp(repo, "local") != 0)) {
182             sprintf(image_full, "%s/%s:latest", repo, image);    
183         }
184         else {
185             sprintf(image_full, "%s:latest", image);
186         }
187     }
188
189     container->name = strdup(container_name);
190     container->id = 0;
191     container->docker_ip = 0;
192     container->docker_netconf_ssh_port = STANDARD_NETCONF_PORT;
193     container->docker_netconf_tls_port = container->docker_netconf_ssh_port + framework_environment.settings.ssh_connections;
194     if(framework_environment.settings.ssh_connections == 0) {
195         container->docker_netconf_ssh_port = 0;
196     }
197     if(framework_environment.settings.tls_connections == 0) {
198         container->docker_netconf_tls_port = 0;
199     }
200     container->docker_ftp_port= STANDARD_FTP_PORT;
201     container->docker_sftp_port= STANDARD_SFTP_PORT;
202
203     container->host_ip = strdup(framework_environment.host.ip);
204     container->host_netconf_ssh_port = host_netconf_ssh_port;
205     container->host_netconf_tls_port = host_netconf_tls_port;
206     container->host_ftp_port = host_ftp_port;
207     container->host_sftp_port = host_sftp_port;
208
209     int rc = docker_container_create(image_full, container);
210     if(rc != NTS_ERR_OK) {
211         log_error("docker_container_create failed\n");
212         return NTS_ERR_FAILED;
213     }
214
215     rc = docker_container_start(container);
216     if(rc != NTS_ERR_OK) {
217         log_error("docker_container_start failed\n");
218         docker_stop(container);
219         return NTS_ERR_FAILED;
220     }
221
222     rc = docker_container_inspect(container);
223     if(rc != NTS_ERR_OK) {
224         log_error("docker_container_inspect failed\n");
225         docker_stop(container);
226         return NTS_ERR_FAILED;
227     }
228
229     log_add_verbose(2, "docker_start: name: %s | id: %s | docker_ip: %s | netconf_ssh_port: (%d:%d) | netconf_tls_port: (%d:%d) | ftp_port: (%d:%d) | sftp_port: (%d:%d)\n", container->name, container->id, container->docker_ip, container->docker_netconf_ssh_port, container->host_netconf_ssh_port, container->docker_netconf_tls_port, container->host_netconf_tls_port, container->docker_ftp_port, container->host_ftp_port, container->docker_sftp_port, container->host_sftp_port);
230
231     return NTS_ERR_OK;
232 }
233
234 int docker_stop(docker_container_t *container) {
235     assert(container);
236
237     char url[512];
238     sprintf(url, "http://v%s/containers/%s?force=true", framework_environment.settings.docker_engine_version, container->id);
239     
240     free(container->name);
241     free(container->id);
242     free(container->docker_ip);
243     free(container->host_ip);
244
245     int rc = http_socket_request(url, DOCKER_SOCK_FNAME, "DELETE", "", 0, 0);
246     if(rc != NTS_ERR_OK) {
247         log_error("http_socket_request failed\n");
248         return NTS_ERR_FAILED;
249     }
250
251     return NTS_ERR_OK;
252 }
253
254 int docker_usage_get(const char **instances_id, int count, docker_usage_t *usage) {
255     assert(instances_id);
256     assert(usage);
257
258     usage->cpu = 0;
259     usage->mem = 0;
260
261     char buffer[1024];
262     char full_text[1024 * 1024];
263     FILE* pipe = popen("docker stats --no-stream --format \"table {{.ID}}|{{.CPUPerc}}|{{.MemUsage}}|\"", "r");
264     if (!pipe) {
265         log_error("popen() failed\n");
266         return NTS_ERR_FAILED;
267     }
268
269     int n = 1;
270     int k = 0;
271     while(n != 0) {
272         n = fread(buffer, 1, sizeof(buffer), pipe);
273         for(int i = 0; i < n; i++) {
274             full_text[k++] = buffer[i];
275         }
276     }
277     pclose(pipe);
278     full_text[k] = 0;
279
280     char *c = full_text;
281     
282     c = strstr(c, "\n");
283     while(c) {
284         char line[1024];
285         line[0] = 0;
286
287         char *d = strstr(c + 1, "\n");
288         if(d) {
289             for(char *i = c + 1; i < d; i++) {
290                 line[i - c - 1] = *i;
291                 line[i - c] = 0;
292             }
293
294             char container_name[1024];
295             char buff[1024];
296             float cpu = 0.0;
297             float mem = 0.0;
298
299             char *x = strstr(line, "|");
300             for(char *i = line; i < x; i++) {
301                 container_name[i - line] = *i;
302                 container_name[i - line + 1] = 0;
303             }
304
305             char *start = x + 1;
306             x = strstr(start, "|");
307             for(char *i = start; i < x; i++) {
308                 if(((*i >= '0') && (*i <= '9')) || (*i == '.')) {
309                     buff[i - start] = *i;
310                 }
311                 else {
312                     buff[i - start] = 0;
313                     break;
314                 }
315             }
316
317             cpu = strtof(buff, 0);
318
319             int mul = 1;
320             start = x + 1;
321             x = strstr(start, "|");
322             for(char *i = start; i < x; i++) {
323                 if(((*i >= '0') && (*i <= '9')) || (*i == '.')) {
324                     buff[i - start] = *i;
325                 }
326                 else {
327                     if(*i == 'G') {
328                         mul = 1024;
329                     }
330                     buff[i - start] = 0;
331                     break;
332                 }
333             }
334
335             mem = strtof(buff, 0) * mul;
336             
337             
338             if(strcmp(container_name, framework_environment.settings.hostname) == 0) {
339                 usage->cpu += cpu;
340                 usage->mem += mem;
341             }
342             else {
343                 for(int i = 0; i < count; i++) {   
344                     if(strcmp(container_name, instances_id[i]) == 0) {
345                         usage->cpu += cpu;
346                         usage->mem += mem;
347                         break;
348                     }
349                 }
350             }
351         }
352         
353         c = d;
354     }
355
356     usage->cpu /= get_nprocs();
357
358     return NTS_ERR_OK;
359 }
360
361 int docker_pull(const char *repo, const char *image, const char *tag) {
362     assert(repo);
363     assert(image);
364     assert(tag);
365
366     char image_full[256];
367     if(tag && (tag[0] != 0)) {
368         sprintf(image_full, "%s/%s:%s", repo, image, tag);
369     }
370     else {
371         sprintf(image_full, "%s/%s:latest", repo, image);    
372     }
373
374     char url[512];
375     sprintf(url, "http:/v%s/images/create?fromImage=%s", framework_environment.settings.docker_engine_version, image_full);
376
377     char *response = 0;
378     int response_code = 0;
379     int rc = http_socket_request(url, DOCKER_SOCK_FNAME, "POST", 0, &response_code, &response);
380
381     if(rc != NTS_ERR_OK) {
382         log_error("http_socket_request failed\n");
383         return NTS_ERR_FAILED;
384     }
385
386     if(response_code != 200) {
387         char *message = docker_parse_json_message(response);
388         log_error("docker_pull failed (%d): %s\n", response_code, message);
389         free(message);
390         free(response);
391         return NTS_ERR_FAILED;
392     }
393     
394     return NTS_ERR_OK;
395 }
396
397 static char *docker_parse_json_message(const char *json_string) {
398     assert(json_string);
399
400     cJSON *json_response = cJSON_Parse(json_string);
401     if(json_response == 0) {
402         log_error("cJSON_Parse failed\n");
403         return 0;
404     }
405
406     cJSON *message = cJSON_GetObjectItem(json_response, "message");
407     if(message == 0) {
408         log_error("json parsing failed\n");
409         cJSON_Delete(json_response);
410         return 0;
411     }
412
413     char *ret = strdup(message->valuestring);
414     cJSON_Delete(json_response);
415     return ret;
416 }
417
418 static int docker_add_port(cJSON *portBindings, uint16_t docker_port, uint16_t host_port) {
419     assert(portBindings);
420
421     cJSON *port = cJSON_CreateArray();
422     if(port == 0) {
423         log_error("could not create JSON object: port\n");
424         return NTS_ERR_FAILED;
425     }
426
427     char dockerContainerPort[20];
428     sprintf(dockerContainerPort, "%d/tcp", docker_port);
429
430     if(cJSON_AddItemToObject(portBindings, dockerContainerPort, port) == 0) {
431         log_error("cJSON_AddItemToObject failed\n");
432         return NTS_ERR_FAILED;
433     }
434
435     cJSON *hostPort = cJSON_CreateObject();
436     if(hostPort == 0) {
437         log_error("could not create JSON object: HostPort\n");
438         return NTS_ERR_FAILED;
439     }
440
441     char dockerHostPort[20];
442     sprintf(dockerHostPort, "%d", host_port);
443     if(cJSON_AddStringToObject(hostPort, "HostPort", dockerHostPort) == 0) {
444         log_error("could not create JSON object: HostPortString\n");
445         cJSON_Delete(hostPort);
446         return NTS_ERR_FAILED;
447     }
448
449     if(cJSON_AddItemToArray(port, hostPort) == 0) {
450         log_error("cJSON_AddItemToArray failed\n");
451         cJSON_Delete(hostPort);
452         return NTS_ERR_FAILED;
453     }
454
455     return NTS_ERR_OK;
456 }
457
458 static int docker_populate_images(docker_context_t *context, int count, const char *min_version) {
459     assert(context);
460     assert(count);
461     assert(min_version);
462
463     char url[512];
464     sprintf(url, "http://v%s/images/json", framework_environment.settings.docker_engine_version);
465
466     char *response = 0;    
467     int rc = http_socket_request(url, DOCKER_SOCK_FNAME, "GET", "", 0, &response);
468     if(rc != NTS_ERR_OK) {
469         log_error("http_socket_request failed\n");
470         return NTS_ERR_FAILED;
471     }
472
473     cJSON *json_response = cJSON_Parse(response);
474     free(response);
475     if(json_response == 0) {
476         log_error("cJSON_Parse failed\n");
477         return NTS_ERR_FAILED;
478     }
479     
480     cJSON *element;
481     cJSON_ArrayForEach(element, json_response) {
482         cJSON *tag = cJSON_GetObjectItem(element, "RepoTags");
483         if(tag) {
484             cJSON *ctag;
485             cJSON_ArrayForEach(ctag, tag) {
486                 char *tag_name = ctag->valuestring; //contains repo/image:tag
487                 for(int i = 0; i < count; i++) {
488                     char *s = strstr(tag_name, context[i].image);
489                     if(s != 0) {
490                         char *tag = s + strlen(context[i].image);
491                         if(*tag == ':') {
492                             tag = strdup(s + strlen(context[i].image) + 1);
493                         }
494                         else if(*tag == 0) {
495                             tag = strdup("");
496                         }
497                         else {
498                             continue;
499                         }
500
501                         if(nts_vercmp(tag, min_version) >= 0) {
502                             char *repo = 0;
503                             if(s != tag_name) {
504                                 repo = strdup(tag_name);
505                                 *(strstr(repo, context[i].image) - 1) = 0;
506                             }
507                             else {
508                                 repo = strdup("");
509                             }
510
511                             context[i].available_images = (docker_available_images_t *)realloc(context[i].available_images, (sizeof(docker_available_images_t) * (context[i].available_images_count + 1)));
512                             context[i].available_images[context[i].available_images_count].repo = repo;
513                             context[i].available_images[context[i].available_images_count].tag = tag;
514                             context[i].available_images_count++;
515                         }
516                         else {
517                             free(tag);
518                         }
519                     }
520                 }
521             }
522         }
523     }
524
525     cJSON_Delete(json_response);
526
527     return NTS_ERR_OK;
528 }
529
530 static int docker_container_create(const char *image, docker_container_t *container) {
531     assert(image);
532     assert(container);
533
534     cJSON *postDataJson = cJSON_CreateObject();
535     if(cJSON_AddStringToObject(postDataJson, "Image", image) == 0) {
536         log_error("could not create JSON object: Image\n");
537         return NTS_ERR_FAILED;
538     }
539
540     if(cJSON_AddStringToObject(postDataJson, "Hostname", container->name) == 0) {
541         log_error("could not create JSON object: Hostname\n");
542         cJSON_Delete(postDataJson);
543         return NTS_ERR_FAILED;
544     }    
545
546     cJSON *hostConfig = cJSON_CreateObject();
547     if(hostConfig == 0) {
548         log_error("could not create JSON object: HostConfig\n");
549         cJSON_Delete(postDataJson);
550         return NTS_ERR_FAILED;
551     }
552     if(cJSON_AddItemToObject(postDataJson, "HostConfig", hostConfig) == 0) {
553         log_error("cJSON_AddItemToObject failed\n");
554         cJSON_Delete(postDataJson);
555         return NTS_ERR_FAILED;
556     }
557
558     cJSON *capAdd = cJSON_CreateArray();
559     if(capAdd == 0) {
560         log_error("could not create JSON array: CapAdd\n");
561         cJSON_Delete(postDataJson);
562         return NTS_ERR_FAILED;
563     }
564     if(cJSON_AddItemToObject(hostConfig, "CapAdd", capAdd) == 0) {
565         log_error("cJSON_AddItemToObject failed\n");
566         cJSON_Delete(postDataJson);
567         return NTS_ERR_FAILED;
568     }
569     cJSON *net_admin = cJSON_CreateString("NET_ADMIN");
570     if(net_admin == 0) {
571         log_error("could not create JSON string\n");
572         cJSON_Delete(postDataJson);
573         return NTS_ERR_FAILED;
574     }
575     if(cJSON_AddItemToArray(capAdd, net_admin) == 0) {
576         log_error("cJSON_AddItemToArray failed\n");
577         cJSON_Delete(postDataJson);
578         return NTS_ERR_FAILED;
579     }
580     
581
582     cJSON *portBindings = cJSON_CreateObject();
583     if(portBindings == 0) {
584         log_error("could not create JSON object: PortBindings\n");
585         cJSON_Delete(postDataJson);
586         return NTS_ERR_FAILED;
587     }
588     if(cJSON_AddItemToObject(hostConfig, "PortBindings", portBindings) == 0) {
589         log_error("cJSON_AddItemToObject failed\n");
590         cJSON_Delete(postDataJson);
591         return NTS_ERR_FAILED;
592     }
593     
594     for(int i = 0; i < framework_environment.settings.ssh_connections; i++) {
595         if(docker_add_port(portBindings, container->docker_netconf_ssh_port + i, container->host_netconf_ssh_port + i) != NTS_ERR_OK) {
596             log_error("docker_add_port() failed\n");
597             cJSON_Delete(postDataJson);
598             return NTS_ERR_FAILED;
599         }
600     }
601
602     for(int i = 0; i < framework_environment.settings.tls_connections; i++) {
603         if(docker_add_port(portBindings, container->docker_netconf_tls_port + i, container->host_netconf_tls_port + i) != NTS_ERR_OK) {
604             log_error("docker_add_port() failed\n");
605             cJSON_Delete(postDataJson);
606             return NTS_ERR_FAILED;
607         }
608     }
609
610     for(int i = 0; i < framework_environment.settings.ftp_connections; i++) {
611         if(docker_add_port(portBindings, container->docker_ftp_port + i, container->host_ftp_port + i) != NTS_ERR_OK) {
612             log_error("docker_add_port() failed\n");
613             cJSON_Delete(postDataJson);
614             return NTS_ERR_FAILED;
615         }
616     }
617
618     for(int i = 0; i < framework_environment.settings.sftp_connections; i++) {
619         if(docker_add_port(portBindings, container->docker_sftp_port + i, container->host_sftp_port + i) != NTS_ERR_OK) {
620             log_error("docker_add_port() failed\n");
621             cJSON_Delete(postDataJson);
622             return NTS_ERR_FAILED;
623         }
624     }
625     
626     //environment vars start
627     asprintf(&docker_environment_var[4].value, "%d", container->host_netconf_ssh_port);
628     asprintf(&docker_environment_var[5].value, "%d", container->host_netconf_tls_port);
629     asprintf(&docker_environment_var[6].value, "%d", container->host_ftp_port);
630     asprintf(&docker_environment_var[7].value, "%d", container->host_sftp_port);
631
632     cJSON *env_variables_array = cJSON_CreateArray();
633     if(env_variables_array == 0) {
634         log_error("Could not create JSON object: Env array\n");
635         cJSON_Delete(postDataJson);
636         free(docker_environment_var[4].value);
637         free(docker_environment_var[5].value);
638         free(docker_environment_var[6].value);
639         free(docker_environment_var[7].value);
640         return NTS_ERR_FAILED;
641     }
642     cJSON_AddItemToObject(postDataJson, "Env", env_variables_array);
643
644     for(int i = 0; i < docker_environment_var_count; i++) {
645         if(docker_environment_var[i].value) {
646             char *environment_var = 0;
647             asprintf(&environment_var, "%s=%s", docker_environment_var[i].name, docker_environment_var[i].value);
648
649             cJSON *env_var_obj = cJSON_CreateString(environment_var);
650             if(env_var_obj == 0) {
651                 log_error("could not create JSON object\n");
652                 cJSON_Delete(postDataJson);
653                 free(docker_environment_var[4].value);
654                 free(docker_environment_var[5].value);
655                 free(docker_environment_var[6].value);
656                 free(docker_environment_var[7].value);
657                 free(environment_var);
658                 return NTS_ERR_FAILED;
659             }
660             cJSON_AddItemToArray(env_variables_array, env_var_obj);
661
662             free(environment_var);
663         }
664     }
665
666     free(docker_environment_var[4].value);
667     free(docker_environment_var[5].value);
668     free(docker_environment_var[6].value);
669     free(docker_environment_var[7].value);
670     //environment vars finished
671
672     cJSON *netMode = cJSON_Duplicate(docker_network_info, 1);
673     cJSON_AddItemToObject(hostConfig, "NetworkMode", netMode);
674
675     char *post_data_string = 0;
676     post_data_string = cJSON_PrintUnformatted(postDataJson);
677     cJSON_Delete(postDataJson);
678
679     char url[512];
680     sprintf(url, "http:/v%s/containers/create?name=%s", framework_environment.settings.docker_engine_version, container->name);
681
682     char *response = 0;
683     int response_code = 0;
684     int rc = http_socket_request(url, DOCKER_SOCK_FNAME, "POST", post_data_string, &response_code, &response);
685     free(post_data_string);
686     if(rc != NTS_ERR_OK) {
687         log_error("http_socket_request failed\n");
688         return NTS_ERR_FAILED;
689     }
690
691     if(response_code != 201) {
692         char *message = docker_parse_json_message(response);
693         log_error("docker_container_create failed (%d): %s\n", response_code, message);
694         free(message);
695         free(response);
696         return NTS_ERR_FAILED;
697     }
698     else {
699         cJSON *json_response = cJSON_Parse(response);
700         free(response);
701         const cJSON *container_id = 0;
702
703         container_id = cJSON_GetObjectItemCaseSensitive(json_response, "Id");
704
705         if(cJSON_IsString(container_id) && (container_id->valuestring != 0)) {
706             char container_id_short[13];
707             memset(container_id_short, '\0', sizeof(container_id_short));
708             strncpy(container_id_short, container_id->valuestring, 12);
709
710             container->id = strdup(container_id_short);
711
712             cJSON_Delete(json_response);
713             return NTS_ERR_OK;
714         }
715         else {
716             cJSON_Delete(json_response);
717             return NTS_ERR_FAILED;
718         }
719     }
720 }
721
722 static int docker_container_start(docker_container_t *container) {
723     assert(container);
724
725     char url[512];
726     sprintf(url, "http://v%s/containers/%s/start", framework_environment.settings.docker_engine_version, container->id);
727
728     char *response = 0;
729     int response_code = 0;
730     int rc = http_socket_request(url, DOCKER_SOCK_FNAME, "POST", "", &response_code, &response);
731     if(rc != NTS_ERR_OK) {
732         log_error("http_socket_request failed\n");
733         return NTS_ERR_FAILED;
734     }
735     else {
736         if(response_code == 304) {
737             log_error("docker_container_start failed (%d): container already started\n", response_code);
738             free(response);
739             return NTS_ERR_FAILED;
740         }
741         else if(response_code != 204) {
742             char *message = docker_parse_json_message(response);
743             log_error("docker_container_start failed (%d): %s\n", response_code, message);
744             free(message);
745             free(response);
746             return NTS_ERR_FAILED;
747         }
748         
749     }
750
751     return NTS_ERR_OK;
752 }
753
754 static int docker_container_inspect(docker_container_t *container) {
755     assert(container);
756
757     char url[512];
758     sprintf(url, "http://v%s/containers/%s/json", framework_environment.settings.docker_engine_version, container->id);
759
760     char *response = 0;    
761     int rc = http_socket_request(url, DOCKER_SOCK_FNAME, "GET", "", 0, &response);
762     if(rc != NTS_ERR_OK) {
763         log_error("http_socket_request failed\n");
764         free(response);
765         return NTS_ERR_FAILED;
766     }
767
768     cJSON *json_response = cJSON_Parse(response);
769     free(response);
770     if(json_response == 0) {
771         log_error("cJSON_Parse failed\n");
772         return NTS_ERR_FAILED;
773     }
774
775
776     cJSON *main_node = cJSON_GetObjectItem(json_response, "NetworkSettings");
777     if(main_node == 0) {
778         log_error("json parsing failed\n");
779         cJSON_Delete(json_response);
780         return NTS_ERR_FAILED;
781     }
782
783     cJSON *node = cJSON_GetObjectItem(main_node, "Networks");
784     if(node == 0) {
785         log_error("json parsing failed\n");
786         cJSON_Delete(json_response);
787         return NTS_ERR_FAILED;
788     }
789         
790     node = node->child;   //get info from the first in array
791     if(node == 0) {
792         log_error("json parsing failed\n");
793         cJSON_Delete(json_response);
794         return NTS_ERR_FAILED;
795     }
796
797     cJSON *element;
798     if(framework_environment.settings.ip_v6_enabled) {
799         element = cJSON_GetObjectItem(node, "GlobalIPv6Address");
800     }
801     else {
802         element = cJSON_GetObjectItem(node, "IPAddress");
803     } 
804
805     if(element == 0) {
806         log_error("json parsing failed\n");
807         cJSON_Delete(json_response);
808         return NTS_ERR_FAILED;
809     }
810
811     container->docker_ip = strdup(element->valuestring);
812
813     cJSON_Delete(json_response);
814     return NTS_ERR_OK;
815 }