Rewrite NTS Framework.
[sim/o1-interface.git] / ntsimulator / ntsim-ng / core / docker.c
diff --git a/ntsimulator/ntsim-ng/core/docker.c b/ntsimulator/ntsim-ng/core/docker.c
new file mode 100644 (file)
index 0000000..40f2bff
--- /dev/null
@@ -0,0 +1,756 @@
+/*************************************************************************
+*
+* Copyright 2020 highstreet technologies GmbH and others
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+***************************************************************************/
+
+#define _GNU_SOURCE
+
+#include "docker.h"
+#include "utils/log_utils.h"
+#include "utils/sys_utils.h"
+#include "utils/http_client.h"
+#include "core/framework.h"
+#include "core/session.h"
+#include "core/context.h"
+#include <sysrepo.h>
+#include <dirent.h>
+#include <assert.h>
+#include <sys/sysinfo.h>
+
+#include <cjson/cJSON.h>
+
+#define DOCKER_SOCK_FNAME       "/var/run/docker.sock"
+
+static cJSON *docker_network_info = 0;
+
+struct installable_module {
+    char *name;
+    char *fullpath;
+    bool installed;
+    bool submodule;
+};
+
+typedef struct {
+    char *name;
+    char *value;
+} environment_var_t;
+
+static environment_var_t *docker_environment_var;
+static int docker_environment_var_count = 0;
+
+static int get_installable_modules(struct installable_module **modules);    //list available modules for install
+static void list_yangs(const char *path, struct installable_module **modules, int *total);
+
+static char *docker_parse_json_message(const char *json_string);
+
+static int docker_container_create(const char *image, manager_network_function_instance_t *instance);
+static int docker_container_start(manager_network_function_instance_t *instance);
+static int docker_container_inspect(manager_network_function_instance_t *instance);
+
+
+bool docker_container_init(void) {
+    int rc;
+
+    sr_log_stderr(SR_LL_NONE);
+    log_message(1, "Entering container-init mode...\n");
+
+    // connect to sysrepo
+    rc = sr_connect(0, &session_connection);
+    if(SR_ERR_OK != rc) {
+        log_error("sr_connect failed");
+        return false;
+    }
+
+    /* get context */
+    session_context = (struct ly_ctx *)sr_get_context(session_connection);
+    if(session_context == 0) {
+        log_error("sr_get_context failed");
+        return false;
+    }
+
+    /* install yang files */
+    log_message(1, "Installing yang files...\n");
+    struct installable_module *modules;
+    int total_modules = get_installable_modules(&modules);
+    log_message(1, "Found total modules: %d\n", total_modules);
+
+    int old_failed_installations = 1;
+    int failed_installations = 0;
+    int install_round = 0;
+    while(failed_installations != old_failed_installations) {
+        old_failed_installations = failed_installations;
+        failed_installations = 0;
+        install_round++;
+        for(int i = 0; i < total_modules; i++) {
+            if(!modules[i].installed) {
+                modules[i].submodule = context_yang_is_module(modules[i].fullpath);
+                if(!modules[i].submodule) {
+                    if(!framework_is_docker_excluded_module(modules[i].name)) {
+                        log_message(1, "[round %d] trying to install module %s from %s... ", install_round, modules[i].name, modules[i].fullpath);
+                        if(!context_module_install(modules[i].name, modules[i].fullpath)) {
+                            failed_installations++;
+                            log_message(1, LOG_COLOR_BOLD_YELLOW"failed"LOG_COLOR_RESET"\n");
+                        }
+                        else {
+                            log_message(1, LOG_COLOR_BOLD_GREEN"done"LOG_COLOR_RESET"\n");
+                            modules[i].installed = true;
+                        }
+                    }
+                    else {
+                        log_message(1, "[round %d] not installing module %s as it's excluded in config.\n", install_round, modules[i].name);
+                        modules[i].installed = true;
+                    }
+                }
+                else {
+                    log_message(1, "[round %d] %s is a submodule... "LOG_COLOR_BOLD_YELLOW"skipping"LOG_COLOR_RESET"\n", install_round, modules[i].name);
+                    modules[i].installed = true;
+                }
+            }
+        }
+    }
+
+    if(failed_installations != 0) {
+        log_error("Failed to install all modules in %d rounds...", install_round);
+        return false;
+    }
+    else {
+        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));
+    }
+
+    //set access for all installed modules
+    log_message(1, "Setting access configuration for installed modules... ");
+    for(int i = 0; i < total_modules; i++) {
+        if((!framework_is_docker_excluded_module(modules[i].name)) && (!modules[i].submodule)) {
+            if(!context_module_set_access(modules[i].name)) {
+                log_error("Failed to set access to module %s...", modules[i].name);
+                return false;
+            }
+        }
+    }
+    log_message(1, LOG_COLOR_BOLD_GREEN"done"LOG_COLOR_RESET"\n");
+
+    //cleanup module-install used memory
+    for(int i = 0; i < total_modules; i++) {
+        free(modules[i].name);
+        free(modules[i].fullpath);
+    }
+    free(modules);
+
+    //get context
+    session_context = (struct ly_ctx *)sr_get_context(session_connection);
+    if(session_context == 0) {
+        log_error("sr_get_context failed");
+        return false;
+    }
+
+    //init context so we can see all the available modules, features, etc
+    rc = context_init(session_context);
+    if(rc != 0) {
+        log_error("context_init() failed");
+        return false;
+    }
+
+    /* enable features */
+    log_message(1, "Enabling yang features...\n");
+    char **available_features;
+    int total_available_features;
+    total_available_features = context_get_features(&available_features);
+    log_message(1, "Found total features: %d\n", total_available_features);
+    for(int i = 0; i < total_available_features; i++) {
+        log_message(1, "feature %s: ", available_features[i]);
+
+        if(!context_get_feature_enabled(available_features[i])) {
+            if(!framework_is_docker_excluded_feature(available_features[i])) {
+                if(context_feature_enable(available_features[i])) {
+                    log_message(1, "enabling... "LOG_COLOR_BOLD_GREEN"done"LOG_COLOR_RESET"\n");
+                }
+                else {
+                    log_error("enabling... failed\n");
+                }
+            }
+            else {
+                log_message(1, "excluded in config, skipping\n");
+            }
+        }
+        else {
+            log_message(1, "already "LOG_COLOR_BOLD_GREEN"enabled"LOG_COLOR_RESET", skipping.\n");
+        }
+    }
+    for(int i = 0; i < total_available_features; i++) {
+        free(available_features[i]);
+    }
+    free(available_features);
+
+    sr_disconnect(session_connection);
+    context_free();
+
+    log_message(1, LOG_COLOR_BOLD_GREEN"ntsim successfully initialized Docker container"LOG_COLOR_RESET"\n");
+    return true;
+}
+
+static int get_installable_modules(struct installable_module **modules) {
+    int total = 0;
+    *modules = 0;
+    list_yangs("/opt/dev/deploy/yang", modules, &total);
+    return total;
+}
+
+static void list_yangs(const char *path, struct installable_module **modules, int *total) {
+    DIR *d;
+    struct dirent *dir;
+    d = opendir(path);
+    if(d) {
+        while((dir = readdir(d)) != NULL) {
+            if(dir->d_type == DT_DIR) {
+                if(strcmp(dir->d_name, ".") != 0 && strcmp(dir->d_name, "..") != 0)
+                {
+                    char new_path[1024];
+                    snprintf(new_path, sizeof(new_path), "%s/%s", path, dir->d_name);
+                    list_yangs(new_path, modules, total);
+                }
+            } else {
+                if(strstr(dir->d_name, ".yang") != 0) {
+                    *modules = (struct installable_module *)realloc(*modules, sizeof(struct installable_module) * (*total + 1));
+                    if(!*modules) {
+                        log_error("could not realloc");
+                        return;
+                    }
+
+                    (*modules)[*total].name = (char*)malloc(sizeof(char) * (strlen(dir->d_name) + 1));
+                    if(!(*modules)[*total].name) {
+                        log_error("could not alloc");
+                        return;
+                    }
+                    strcpy((*modules)[*total].name, dir->d_name);
+                    (*modules)[*total].name[strlen(dir->d_name) - 5] = 0;   //extract ".yang"
+                    char *rev = strstr((*modules)[*total].name, "@");
+                    if(rev) { //extract revision, if exists
+                        *rev = 0;
+                    }
+
+                    (*modules)[*total].fullpath = (char*)malloc(sizeof(char) * (strlen(path) + 1 + strlen(dir->d_name) + 1));
+                    if(!(*modules)[*total].fullpath) {
+                        log_error("could not alloc");
+                        return;
+                    }
+                    sprintf((*modules)[*total].fullpath, "%s/%s", path, dir->d_name);
+
+                    (*modules)[*total].installed = false;
+                    (*modules)[*total].submodule = false;
+
+                    (*total)++;
+                }
+            }
+        }
+        closedir(d);
+    }
+}
+
+int docker_device_init(void) {
+    char *response = 0;
+    char *url = 0;
+    asprintf(&url, "http://v%s/containers/%s/json", framework_environment.docker_engine_version, framework_environment.hostname);
+
+    int rc = http_socket_request(url, DOCKER_SOCK_FNAME, "GET", 0, 0, &response);
+    if(rc != NTS_ERR_OK) {
+        log_error("http_socket_request failed");
+        return NTS_ERR_FAILED;
+    }
+
+    cJSON *json_response = cJSON_Parse(response);
+    free(response);
+
+    if(json_response == 0) {
+        log_error("could not parse JSON response for url=\"%s\"", url);
+        return NTS_ERR_FAILED;
+    }
+
+    cJSON *hostConfig = cJSON_GetObjectItemCaseSensitive(json_response, "HostConfig");
+    if(hostConfig == 0) {
+        log_error("could not get HostConfig object");
+        return NTS_ERR_FAILED;
+    }
+
+    cJSON *networkMode = cJSON_GetObjectItemCaseSensitive(hostConfig, "NetworkMode");
+    if(networkMode == 0) {
+        log_error("could not get NetworkMode object");
+        return NTS_ERR_FAILED;
+    }
+
+    docker_network_info = cJSON_Duplicate(networkMode, 1);
+    cJSON_Delete(json_response);
+
+    log_message(2, "finished parsing docker inspect...\n");
+
+
+    docker_environment_var_count = 5;
+    docker_environment_var = (environment_var_t *)malloc(sizeof(environment_var_t) * docker_environment_var_count);
+    if(docker_environment_var == 0) {
+        log_error("malloc failed");
+        return NTS_ERR_FAILED;
+    }
+    
+    //set env variables for network functions
+    docker_environment_var[0].name = ENV_VAR_SSH_CONNECTIONS;
+    asprintf(&docker_environment_var[0].value, "%d", framework_environment.ssh_connections);
+    docker_environment_var[1].name = ENV_VAR_TLS_CONNECTIONS;
+    asprintf(&docker_environment_var[1].value, "%d", framework_environment.tls_connections);
+    docker_environment_var[2].name = ENV_VAR_IPV6ENABLED;
+    docker_environment_var[2].value = framework_environment.ip_v6_enabled ? "true" : "false";
+    docker_environment_var[3].name = ENV_VAR_HOST_IP;
+    docker_environment_var[3].value = framework_environment.host_ip;
+    docker_environment_var[4].name = ENV_VAR_HOST_BASE_PORT;
+    // docker_environment_var[4].value = will be updated by docker_create...
+
+    return NTS_ERR_OK;
+}
+
+int docker_device_start(const manager_network_function_type *function_type, manager_network_function_instance_t *instance) {
+    assert(function_type);
+    assert(instance);
+    assert(docker_network_info);
+
+    char *image = 0;
+    if(function_type->docker_version_tag && (function_type->docker_version_tag[0] != 0)) {
+        if(function_type->docker_repository && (function_type->docker_repository[0] != 0)) {
+            asprintf(&image, "%s/%s:%s", function_type->docker_repository, function_type->docker_image_name, function_type->docker_version_tag);    
+        }
+        else {
+            asprintf(&image, "%s:%s", function_type->docker_image_name, function_type->docker_version_tag);
+        }
+    }
+    else {
+        if(function_type->docker_repository && (function_type->docker_repository[0] != 0)) {
+            asprintf(&image, "%s/%s:latest", function_type->docker_repository, function_type->docker_image_name);    
+        }
+        else {
+            asprintf(&image, "%s:latest", function_type->docker_image_name);
+        }
+    }
+
+    int rc = docker_container_create(image, instance);
+    if(rc != NTS_ERR_OK) {
+        log_error("docker_container_create failed");
+        return NTS_ERR_FAILED;
+    }
+    free(image);
+
+    rc = docker_container_start(instance);
+    if(rc != NTS_ERR_OK) {
+        log_error("docker_container_start failed");
+        return NTS_ERR_FAILED;
+    }
+
+    rc = docker_container_inspect(instance);
+    if(rc != NTS_ERR_OK) {
+        log_error("docker_container_inspect failed");
+        return NTS_ERR_FAILED;
+    }
+
+    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);
+
+    return NTS_ERR_OK;
+}
+
+int docker_device_stop(manager_network_function_instance_t *instance) {
+    assert(instance);
+
+    char *url = 0;
+    asprintf(&url, "http://v%s/containers/%s?force=true", framework_environment.docker_engine_version, instance->docker_id);
+
+    int rc = http_socket_request(url, DOCKER_SOCK_FNAME, "DELETE", "", 0, 0);
+    free(url);
+    if(rc != NTS_ERR_OK) {
+        log_error("http_socket_request failed");
+        return NTS_ERR_FAILED;
+    }
+
+    return NTS_ERR_OK;
+}
+
+docker_usage_t docker_usage_get(const manager_network_function_type *function_type, int function_type_count) {
+    docker_usage_t ret;
+    ret.cpu = 0;
+    ret.mem = 0;
+
+    char buffer[1024];
+    char full_text[1024 * 1024];
+    FILE* pipe = popen("docker stats --no-stream --format \"table {{.ID}}|{{.CPUPerc}}|{{.MemUsage}}|\"", "r");
+    if (!pipe) {
+        log_error("popen() failed");
+        return ret;
+    }
+
+    int n = 1;
+    int k = 0;
+    while(n != 0) {
+        n = fread(buffer, 1, sizeof(buffer), pipe);
+        for(int i = 0; i < n; i++) {
+            full_text[k++] = buffer[i];
+        }
+    }
+    pclose(pipe);
+    full_text[k] = 0;
+
+    char *c = full_text;
+    
+    c = strstr(c, "\n");
+    while(c) {
+        char line[1024];
+        line[0] = 0;
+
+        char *d = strstr(c + 1, "\n");
+        if(d) {
+            for(char *i = c + 1; i < d; i++) {
+                line[i - c - 1] = *i;
+                line[i - c] = 0;
+            }
+
+            char container_name[1024];
+            char buff[1024];
+            float cpu = 0.0;
+            float mem = 0.0;
+
+            char *x = strstr(line, "|");
+            for(char *i = line; i < x; i++) {
+                container_name[i - line] = *i;
+                container_name[i - line + 1] = 0;
+            }
+
+            char *start = x + 1;
+            x = strstr(start, "|");
+            for(char *i = start; i < x; i++) {
+                if(((*i >= '0') && (*i <= '9')) || (*i == '.')) {
+                    buff[i - start] = *i;
+                }
+                else {
+                    buff[i - start] = 0;
+                    break;
+                }
+            }
+
+            cpu = strtof(buff, 0);
+
+            int mul = 1;
+            start = x + 1;
+            x = strstr(start, "|");
+            for(char *i = start; i < x; i++) {
+                if(((*i >= '0') && (*i <= '9')) || (*i == '.')) {
+                    buff[i - start] = *i;
+                }
+                else {
+                    if(*i == 'G') {
+                        mul = 1024;
+                    }
+                    buff[i - start] = 0;
+                    break;
+                }
+            }
+
+            mem = strtof(buff, 0) * mul;
+            
+            
+            if(strcmp(container_name, framework_environment.hostname) == 0) {
+                ret.cpu += cpu;
+                ret.mem += mem;
+            }
+            else {
+                for(int i = 0; i < function_type_count; i++) {
+                    for(int j = 0; j < function_type[i].started_instances; j++) {
+                        
+                        if(strcmp(container_name, function_type[i].instance[j].docker_id) == 0) {
+                            ret.cpu += cpu;
+                            ret.mem += mem;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        
+        c = d;
+    }
+
+
+    ret.cpu /= get_nprocs();
+
+    return ret;
+}
+
+static char *docker_parse_json_message(const char *json_string) {
+    assert(json_string);
+
+    cJSON *json_response = cJSON_Parse(json_string);
+    if(json_response == 0) {
+        log_error("cJSON_Parse failed");
+        return 0;
+    }
+
+    cJSON *message;
+    message = cJSON_GetObjectItem(json_response, "message");
+    if(message == 0) {
+        log_error("json parsing failed");
+        return 0;
+    }
+
+    char *ret = strdup(message->valuestring);
+    cJSON_Delete(json_response);
+    return ret;
+}
+
+static int docker_container_create(const char *image, manager_network_function_instance_t *instance) {
+    assert(image);
+    assert(instance);
+
+    cJSON *postDataJson = cJSON_CreateObject();
+    if(cJSON_AddStringToObject(postDataJson, "Image", image) == 0) {
+        log_error("could not create JSON object: Image");
+        return NTS_ERR_FAILED;
+    }
+
+    if(cJSON_AddStringToObject(postDataJson, "Hostname", instance->name) == 0) {
+        log_error("could not create JSON object: Hostname");
+        return NTS_ERR_FAILED;
+    }    
+
+    cJSON *hostConfig = cJSON_CreateObject();
+    if(hostConfig == 0) {
+        log_error("could not create JSON object: HostConfig");
+        return NTS_ERR_FAILED;
+    }
+    cJSON_AddItemToObject(postDataJson, "HostConfig", hostConfig);
+
+    cJSON *portBindings = cJSON_CreateObject();
+    if(portBindings == 0) {
+        printf("could not create JSON object: PortBindings");
+        return NTS_ERR_FAILED;
+    }
+    cJSON_AddItemToObject(hostConfig, "PortBindings", portBindings);
+    
+    for(int i = 0; i < (framework_environment.ssh_connections + framework_environment.tls_connections + framework_environment.ftp_connections + framework_environment.sftp_connections); ++i) {
+        cJSON *port = cJSON_CreateArray();
+        if(port == 0) {
+            log_error("could not create JSON object: port");
+            return NTS_ERR_FAILED;
+        }
+
+        char dockerContainerPort[20];
+        if(i < framework_environment.ssh_connections + framework_environment.tls_connections) {
+            sprintf(dockerContainerPort, "%d/tcp", STANDARD_NETCONF_PORT + i);
+        }
+        else if(i < (framework_environment.ssh_connections + framework_environment.tls_connections + framework_environment.ftp_connections)) {
+            sprintf(dockerContainerPort, "%d/tcp", STANDARD_FTP_PORT);
+        }
+        else if(i < (framework_environment.ssh_connections + framework_environment.tls_connections + framework_environment.ftp_connections + framework_environment.sftp_connections)) {
+            sprintf(dockerContainerPort, "%d/tcp", STANDARD_SFTP_PORT);
+        }
+        cJSON_AddItemToObject(portBindings, dockerContainerPort, port);
+
+        cJSON *hostPort = cJSON_CreateObject();
+        if(hostPort == 0) {
+            log_error("could not create JSON object: HostPort");
+            return NTS_ERR_FAILED;
+        }
+
+        char dockerHostPort[20];
+        sprintf(dockerHostPort, "%d", instance->host_port + i);
+        if(cJSON_AddStringToObject(hostPort, "HostPort", dockerHostPort) == 0) {
+            log_error("could not create JSON object: HostPortString");
+            return NTS_ERR_FAILED;
+        }
+
+        if(cJSON_AddStringToObject(hostPort, "HostIp", "0.0.0.0") == 0) {   //instance->host_ip
+            log_error("could not create JSON object: HostIpString");
+            return NTS_ERR_FAILED;
+        }
+
+        cJSON_AddItemToArray(port, hostPort);
+    }
+
+    
+    //environment vars start
+    asprintf(&docker_environment_var[4].value, "%d", instance->host_port);
+
+    cJSON *env_variables_array = cJSON_CreateArray();
+    if (env_variables_array == 0) {
+        log_error("Could not create JSON object: Env array");
+        return NTS_ERR_FAILED;
+    }
+    cJSON_AddItemToObject(postDataJson, "Env", env_variables_array);
+
+    for(int i = 0; i < docker_environment_var_count; i++) {
+        char *environment_var = 0;
+        asprintf(&environment_var, "%s=%s", docker_environment_var[i].name, docker_environment_var[i].value);
+
+        cJSON *env_var_obj = cJSON_CreateString(environment_var);
+        if(env_var_obj == 0) {
+            log_error("could not create JSON object");
+            return NTS_ERR_FAILED;
+        }
+        cJSON_AddItemToArray(env_variables_array, env_var_obj);
+
+        free(environment_var);
+    }
+
+    free(docker_environment_var[4].value);
+    //environment vars finished
+
+
+    cJSON *netMode = cJSON_Duplicate(docker_network_info, 1);
+    cJSON_AddItemToObject(hostConfig, "NetworkMode", netMode);
+
+    char *post_data_string = 0;
+    post_data_string = cJSON_PrintUnformatted(postDataJson);
+    cJSON_Delete(postDataJson);
+
+    char *url = 0;
+    asprintf(&url, "http:/v%s/containers/create?name=%s", framework_environment.docker_engine_version, instance->name);
+
+    char *response = 0;
+    int response_code = 0;
+    int rc = http_socket_request(url, DOCKER_SOCK_FNAME, "POST", post_data_string, &response_code, &response);
+    if(rc != NTS_ERR_OK) {
+        log_error("http_socket_request failed");
+        return NTS_ERR_FAILED;
+    }
+    free(url);
+
+    if(response_code != 201) {
+        char *message = docker_parse_json_message(response);
+        log_error("docker_container_create failed (%d): %s", response_code, message);
+        free(message);
+        free(response);
+        return NTS_ERR_FAILED;
+    }
+    else {
+        cJSON *json_response = cJSON_Parse(response);
+        free(response);
+        const cJSON *container_id = 0;
+
+        container_id = cJSON_GetObjectItemCaseSensitive(json_response, "Id");
+
+        if(cJSON_IsString(container_id) && (container_id->valuestring != 0)) {
+            char container_id_short[13];
+            memset(container_id_short, '\0', sizeof(container_id_short));
+            strncpy(container_id_short, container_id->valuestring, 12);
+
+            instance->docker_id = strdup(container_id_short);
+
+            cJSON_Delete(json_response);
+            return NTS_ERR_OK;
+        }
+        else {
+            cJSON_Delete(json_response);
+            return NTS_ERR_FAILED;
+        }
+    }
+}
+
+static int docker_container_start(manager_network_function_instance_t *instance) {
+    assert(instance);
+
+    char *url = 0;
+    asprintf(&url, "http://v%s/containers/%s/start", framework_environment.docker_engine_version, instance->docker_id);
+
+    char *response = 0;
+    int response_code = 0;
+    int rc = http_socket_request(url, DOCKER_SOCK_FNAME, "POST", "", &response_code, &response);
+    free(url);
+    if(rc != NTS_ERR_OK) {
+        log_error("http_socket_request failed");
+        return NTS_ERR_FAILED;
+    }
+    else {
+        if(response_code == 304) {
+            log_error("docker_container_start failed (%d): container already started\n", response_code);
+            free(response);
+            return NTS_ERR_FAILED;
+        }
+        else if(response_code != 204) {
+            char *message = docker_parse_json_message(response);
+            log_error("docker_container_start failed (%d): %s", response_code, message);
+            free(message);
+            free(response);
+            return NTS_ERR_FAILED;
+        }
+        
+    }
+
+    return NTS_ERR_OK;
+}
+
+static int docker_container_inspect(manager_network_function_instance_t *instance) {
+    assert(instance);
+
+    char *url = 0;
+    asprintf(&url, "http://v%s/containers/%s/json", framework_environment.docker_engine_version, instance->docker_id);
+
+    char *response = 0;    
+    int rc = http_socket_request(url, DOCKER_SOCK_FNAME, "GET", "", 0, &response);
+    free(url);
+    if(rc != NTS_ERR_OK) {
+        log_error("http_socket_request failed");
+        return NTS_ERR_FAILED;
+    }
+
+    cJSON *json_response = cJSON_Parse(response);
+    free(response);
+    if(json_response == 0) {
+        log_error("cJSON_Parse failed");
+        return NTS_ERR_FAILED;
+    }
+
+
+    cJSON *main_node = cJSON_GetObjectItem(json_response, "NetworkSettings");
+    if(main_node == 0) {
+        log_error("json parsing failed");
+        return NTS_ERR_FAILED;
+    }
+
+    cJSON *node = cJSON_GetObjectItem(main_node, "Networks");
+    if(node == 0) {
+        log_error("json parsing failed");
+        return NTS_ERR_FAILED;
+    }
+        
+    node = node->child;   //get info from the first in array
+    if(node == 0) {
+        log_error("json parsing failed");
+        return NTS_ERR_FAILED;
+    }
+
+    char *ipv6_env_var = getenv("IPv6_ENABLED");
+    if(ipv6_env_var == 0) {
+        log_error("could not get the IPv6 Enabled env variable");
+        return NTS_ERR_FAILED;
+    }
+
+    cJSON *element = cJSON_GetObjectItem(node, "IPAddress");
+    if(strcmp(ipv6_env_var, "true") == 0) {
+        element = cJSON_GetObjectItem(node, "GlobalIPv6Address");
+    }
+    else {
+        element = cJSON_GetObjectItem(node, "IPAddress");
+    } 
+
+    if(element == 0) {
+        log_error("json parsing failed");
+        return NTS_ERR_FAILED;
+    }
+    instance->docker_ip = strdup(element->valuestring);
+
+    cJSON_Delete(json_response);
+    return NTS_ERR_OK;
+}