Bug fix.
[sim/o1-interface.git] / ntsimulator / src / ntsimulator-manager / simulator-operations.c
index f734307..87b1d68 100644 (file)
@@ -21,6 +21,7 @@
 #include <string.h>
 #include <math.h>
 #include <linux/limits.h>
+#include <unistd.h>
 
 #include "utils.h"
 
 
 static         CURL *curl; //share the same curl connection for communicating with the Docker Engine API
 static         CURL *curl_odl; //share the same curl connection for mounting servers in ODL
+static         CURL *curl_k8s; //share the same curl connection for communicating with the K8S cluster
+
+/*
+curl -X POST -H 'Content-Type: application/json' -i http://localhost:5000/scale --data '{"simulatedDevices":2}'
+*/
 
 static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
 {
@@ -51,35 +57,49 @@ static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, voi
 
 static void set_curl_common_info()
 {
-       struct curl_slist *chunk = NULL;
-       chunk = curl_slist_append(chunk, "Content-Type: application/json");
-       chunk = curl_slist_append(chunk, "Accept: application/json");
+    struct curl_slist *chunk = NULL;
+    chunk = curl_slist_append(chunk, "Content-Type: application/json");
+    chunk = curl_slist_append(chunk, "Accept: application/json");
 
     curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
 
-       curl_easy_setopt(curl, CURLOPT_UNIX_SOCKET_PATH, "/var/run/docker.sock");
+    curl_easy_setopt(curl, CURLOPT_UNIX_SOCKET_PATH, "/var/run/docker.sock");
 
-       curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
-    curl_easy_setopt(curl_odl, CURLOPT_CONNECTTIMEOUT, 2L); // seconds timeout for a connection
-    curl_easy_setopt(curl_odl, CURLOPT_TIMEOUT, 5L); //seconds timeout for an operation
+    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
+    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 2L); // seconds timeout for a connection
+    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L); //seconds timeout for an operation
 
     curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
 }
 
 static void set_curl_common_info_odl()
 {
-       struct curl_slist *chunk = NULL;
-       chunk = curl_slist_append(chunk, "Content-Type: application/xml");
-       chunk = curl_slist_append(chunk, "Accept: application/xml");
+    struct curl_slist *chunk = NULL;
+    chunk = curl_slist_append(chunk, "Content-Type: application/xml");
+    chunk = curl_slist_append(chunk, "Accept: application/xml");
 
     curl_easy_setopt(curl_odl, CURLOPT_HTTPHEADER, chunk);
 
     curl_easy_setopt(curl_odl, CURLOPT_CONNECTTIMEOUT, 2L); // seconds timeout for a connection
-    curl_easy_setopt(curl_odl, CURLOPT_TIMEOUT, 5L); //seconds timeout for an operation
+    curl_easy_setopt(curl_odl, CURLOPT_TIMEOUT, 10L); //seconds timeout for an operation
 
     curl_easy_setopt(curl_odl, CURLOPT_VERBOSE, 1L);
 }
 
+static void set_curl_common_info_k8s()
+{
+    struct curl_slist *chunk = NULL;
+    chunk = curl_slist_append(chunk, "Content-Type: application/json");
+    chunk = curl_slist_append(chunk, "Accept: application/json");
+
+    curl_easy_setopt(curl_k8s, CURLOPT_HTTPHEADER, chunk);
+
+    curl_easy_setopt(curl_k8s, CURLOPT_CONNECTTIMEOUT, 2L); // seconds timeout for a connection
+    curl_easy_setopt(curl_k8s, CURLOPT_TIMEOUT, 10L); //seconds timeout for an operation
+
+    curl_easy_setopt(curl_k8s, CURLOPT_VERBOSE, 1L);
+}
+
 static cJSON* get_docker_container_bindings(void)
 {
        struct MemoryStruct curl_response_mem;
@@ -146,14 +166,87 @@ static cJSON* get_docker_container_bindings(void)
        return NULL;
 }
 
-static char* create_docker_container_curl(int base_netconf_port, cJSON* managerBinds)
+static cJSON* get_docker_container_network_node(void)
+{
+    struct MemoryStruct curl_response_mem;
+
+    curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
+    curl_response_mem.size = 0;    /* no data at this point */
+
+    CURLcode res;
+
+    curl_easy_reset(curl);
+    set_curl_common_info();
+
+    char url[200];
+    sprintf(url, "http:/v%s/containers/%s/json", getenv("DOCKER_ENGINE_VERSION"), getenv("HOSTNAME"));
+
+    curl_easy_setopt(curl, CURLOPT_URL, url);
+
+    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
+    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
+
+    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
+
+    res = curl_easy_perform(curl);
+
+    if (res != CURLE_OK)
+    {
+        return NULL;
+    }
+    else
+    {
+        cJSON *json_response = cJSON_Parse(curl_response_mem.memory);
+
+        printf("%lu bytes retrieved\n", (unsigned long)curl_response_mem.size);
+
+        if (json_response == NULL)
+        {
+            printf("Could not parse JSON response for url=\"%s\"\n", url);
+            return NULL;
+        }
+
+        cJSON *hostConfig = cJSON_GetObjectItemCaseSensitive(json_response, "HostConfig");
+
+        if (hostConfig == NULL)
+        {
+            printf("Could not get HostConfig object\n");
+            return NULL;
+        }
+
+        cJSON *networkMode = cJSON_GetObjectItemCaseSensitive(hostConfig, "NetworkMode");
+
+        if (networkMode == NULL)
+        {
+            printf("Could not get NetworkMode object\n");
+            return NULL;
+        }
+
+        cJSON *networkCopy = cJSON_Duplicate(networkMode, 1);
+
+        cJSON_Delete(json_response);
+
+        return networkCopy;
+    }
+
+    return NULL;
+}
+
+static char* create_docker_container_curl(int base_netconf_port, cJSON* managerBinds, cJSON* networkMode, int device_number)
 {
-       if (managerBinds == NULL)
+    if (managerBinds == NULL)
+    {
+        printf("Could not retrieve JSON object: Binds\n");
+        return NULL;
+    }
+    cJSON *binds = cJSON_Duplicate(managerBinds, 1);
+
+    if (networkMode == NULL)
        {
-               printf("Could not retrieve JSON object: Binds\n");
+               printf("Could not retrieve JSON object: NetworkMode\n");
                return NULL;
        }
-       cJSON *binds = cJSON_Duplicate(managerBinds, 1);
+       cJSON *netMode = cJSON_Duplicate(networkMode, 1);
 
        struct MemoryStruct curl_response_mem;
 
@@ -178,26 +271,35 @@ static char* create_docker_container_curl(int base_netconf_port, cJSON* managerB
     cJSON *postDataJson = cJSON_CreateObject();
 
     if (cJSON_AddStringToObject(postDataJson, "Image", models_var) == NULL)
-       {
-       printf("Could not create JSON object: Image\n");
-               return NULL;
-       }
+    {
+        printf("Could not create JSON object: Image\n");
+        return NULL;
+    }
+
+    char device_name[100];
+    sprintf(device_name, "%s-%d", getenv("CONTAINER_NAME"), device_number);
+
+    if (cJSON_AddStringToObject(postDataJson, "Hostname", device_name) == NULL)
+    {
+        printf("Could not create JSON object: Hostname\n");
+        return NULL;
+    }    
 
     cJSON *hostConfig = cJSON_CreateObject();
     if (hostConfig == NULL)
-       {
-       printf("Could not create JSON object: HostConfig\n");
-               return NULL;
-       }
+    {
+        printf("Could not create JSON object: HostConfig\n");
+        return NULL;
+    }
 
     cJSON_AddItemToObject(postDataJson, "HostConfig", hostConfig);
 
     cJSON *portBindings = cJSON_CreateObject();
     if (portBindings == NULL)
-       {
-       printf("Could not create JSON object: PortBindings\n");
-               return NULL;
-       }
+    {
+        printf("Could not create JSON object: PortBindings\n");
+        return NULL;
+    }
 
     cJSON_AddItemToObject(hostConfig, "PortBindings", portBindings);
 
@@ -268,7 +370,7 @@ static char* create_docker_container_curl(int base_netconf_port, cJSON* managerB
 
     cJSON_AddItemToObject(postDataJson, "Env", env_variables_array);
 
-    char environment_var[50];
+    char environment_var[100];
     sprintf(environment_var, "NTS_IP=%s", getenv("NTS_IP"));
 
     cJSON *env_var_obj = cJSON_CreateString(environment_var);
@@ -279,6 +381,24 @@ static char* create_docker_container_curl(int base_netconf_port, cJSON* managerB
        }
     cJSON_AddItemToArray(env_variables_array, env_var_obj);
 
+    char *external_nts_ip = getenv("EXTERNAL_NTS_IP");
+    if (external_nts_ip == NULL)
+    {
+        sprintf(environment_var, "EXTERNAL_NTS_IP=%s", getenv("NTS_IP"));
+    }
+    else
+    {
+        sprintf(environment_var, "EXTERNAL_NTS_IP=%s", external_nts_ip);
+    }
+
+    cJSON *env_var_obj_0 = cJSON_CreateString(environment_var);
+    if (env_var_obj_0 == NULL)
+       {
+        printf("Could not create JSON object: Env array object EXTERNAL_NTS_IP\n");
+               return NULL;
+       }
+    cJSON_AddItemToArray(env_variables_array, env_var_obj_0);
+
     sprintf(environment_var, "NETCONF_BASE=%d", base_netconf_port);
     cJSON *env_var_obj_2 = cJSON_CreateString(environment_var);
     if (env_var_obj_2 == NULL)
@@ -288,18 +408,40 @@ static char* create_docker_container_curl(int base_netconf_port, cJSON* managerB
        }
     cJSON_AddItemToArray(env_variables_array, env_var_obj_2);
 
-       char scripts_dir[200];
-       sprintf(scripts_dir, "SCRIPTS_DIR=%s", getenv("SCRIPTS_DIR"));
-       cJSON *env_var_obj_3 = cJSON_CreateString(scripts_dir);
-       if (env_var_obj_3 == NULL)
-       {
-               printf("Could not create JSON object: Env array object SCRIPTS_DIR\n");
-               return NULL;
-       }
-       cJSON_AddItemToArray(env_variables_array, env_var_obj_3);
+    char scripts_dir[200];
+    sprintf(scripts_dir, "SCRIPTS_DIR=%s", getenv("SCRIPTS_DIR"));
+    cJSON *env_var_obj_3 = cJSON_CreateString(scripts_dir);
+    if (env_var_obj_3 == NULL)
+    {
+        printf("Could not create JSON object: Env array object SCRIPTS_DIR\n");
+        return NULL;
+    }
+    cJSON_AddItemToArray(env_variables_array, env_var_obj_3);
+
+    char k8s_deployment[50];
+    sprintf(k8s_deployment, "K8S_DEPLOYMENT=%s", getenv("K8S_DEPLOYMENT"));
+    cJSON *env_var_obj_4 = cJSON_CreateString(k8s_deployment);
+    if (env_var_obj_4 == NULL)
+    {
+        printf("Could not create JSON object: Env array object K8S_DEPLOYMENT\n");
+        return NULL;
+    }
+    cJSON_AddItemToArray(env_variables_array, env_var_obj_4);
+
+    char ipv6_enabled[50];
+    sprintf(ipv6_enabled, "IPv6Enabled=%s", getenv("IPv6Enabled"));
+    cJSON *env_var_obj_5 = cJSON_CreateString(ipv6_enabled);
+    if (env_var_obj_5 == NULL)
+    {
+        printf("Could not create JSON object: Env array object IPv6Enabled\n");
+        return NULL;
+    }
+    cJSON_AddItemToArray(env_variables_array, env_var_obj_5);
 
     cJSON_AddItemToObject(hostConfig, "Binds", binds);
 
+    cJSON_AddItemToObject(hostConfig, "NetworkMode", netMode);
+
     char *post_data_string = NULL;
 
     post_data_string = cJSON_PrintUnformatted(postDataJson);
@@ -317,6 +459,11 @@ static char* create_docker_container_curl(int base_netconf_port, cJSON* managerB
 
        res = curl_easy_perform(curl);
 
+    if (post_data_string != NULL)
+    {
+        free(post_data_string);
+    }
+
        if (res != CURLE_OK)
        {
                return NULL;
@@ -353,37 +500,76 @@ static char* create_docker_container_curl(int base_netconf_port, cJSON* managerB
 
 static int start_docker_container_curl(char *container_id)
 {
-       struct MemoryStruct curl_response_mem;
+    struct MemoryStruct curl_response_mem;
 
-       curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
-       curl_response_mem.size = 0;    /* no data at this point */
+    curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
+    curl_response_mem.size = 0;    /* no data at this point */
 
-       CURLcode res;
+    CURLcode res;
 
-       curl_easy_reset(curl);
-       set_curl_common_info();
+    curl_easy_reset(curl);
+    set_curl_common_info();
 
-       char url[100];
-       sprintf(url, "http:/v%s/containers/%s/start", getenv("DOCKER_ENGINE_VERSION"), container_id);
+    char url[100];
+    sprintf(url, "http:/v%s/containers/%s/start", getenv("DOCKER_ENGINE_VERSION"), container_id);
 
-       curl_easy_setopt(curl, CURLOPT_URL, url);
+    curl_easy_setopt(curl, CURLOPT_URL, url);
 
     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
 
-       curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
+    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
 
-       res = curl_easy_perform(curl);
+    res = curl_easy_perform(curl);
 
-       if (res != CURLE_OK)
-       {
-               return SR_ERR_OPERATION_FAILED;
-       }
-       else
-       {
-               printf("Container %s started successfully!\n", container_id);
-       }
+    if (res != CURLE_OK)
+    {
+        return SR_ERR_OPERATION_FAILED;
+    }
+    else
+    {
+        printf("Container %s started successfully!\n", container_id);
+    }
 
-       return SR_ERR_OK;
+    return SR_ERR_OK;
+}
+
+static int rename_docker_container_curl(char *container_id, int device_number)
+{
+    struct MemoryStruct curl_response_mem;
+
+    curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
+    curl_response_mem.size = 0;    /* no data at this point */
+
+    CURLcode res;
+
+    curl_easy_reset(curl);
+    set_curl_common_info();
+
+    char device_name[100];
+    sprintf(device_name, "%s-%d", getenv("CONTAINER_NAME"), device_number);
+
+    char url[100];
+    sprintf(url, "http:/v%s/containers/%s/rename?name=%s", getenv("DOCKER_ENGINE_VERSION"), container_id,
+                device_name);
+
+    curl_easy_setopt(curl, CURLOPT_URL, url);
+
+    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
+
+    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
+
+    res = curl_easy_perform(curl);
+
+    if (res != CURLE_OK)
+    {
+        return SR_ERR_OPERATION_FAILED;
+    }
+    else
+    {
+        printf("Container %s renamed successfully to %s!\n", container_id, device_name);
+    }
+
+    return SR_ERR_OK;
 }
 
 static int kill_and_remove_docker_container_curl(char *container_id)
@@ -437,21 +623,22 @@ static int send_mount_device_instance_ssh(char *url, char *credentials, char *de
        char post_data_xml[1500];
 
        sprintf(post_data_xml,
-                       "<node xmlns=\"urn:TBD:params:xml:ns:yang:network-topology\">"
-                       "<node-id>%s_%d</node-id>"
-                       "<host xmlns=\"urn:opendaylight:netconf-node-topology\">%s</host>"
-                       "<port xmlns=\"urn:opendaylight:netconf-node-topology\">%d</port>"
-                       "<username xmlns=\"urn:opendaylight:netconf-node-topology\">%s</username>"
-                       "<password xmlns=\"urn:opendaylight:netconf-node-topology\">%s</password>"
-                       "<tcp-only xmlns=\"urn:opendaylight:netconf-node-topology\">false</tcp-only>"
-                       "<keepalive-delay xmlns=\"urn:opendaylight:netconf-node-topology\">120</keepalive-delay>"
-                       "<reconnect-on-changed-schema xmlns=\"urn:opendaylight:netconf-node-topology\">false</reconnect-on-changed-schema>"
-                       "<sleep-factor xmlns=\"urn:opendaylight:netconf-node-topology\">1.5</sleep-factor>"
-                       "<connection-timeout-millis xmlns=\"urn:opendaylight:netconf-node-topology\">20000</connection-timeout-millis>"
-                       "<max-connection-attempts xmlns=\"urn:opendaylight:netconf-node-topology\">100</max-connection-attempts>"
-                       "<between-attempts-timeout-millis xmlns=\"urn:opendaylight:netconf-node-topology\">2000</between-attempts-timeout-millis>"
-                       "</node>",
-                       device_name, device_port, getenv("NTS_IP"), device_port, "netconf", "netconf");
+            "<node xmlns=\"urn:TBD:params:xml:ns:yang:network-topology\">"
+            "<node-id>%s_%d</node-id>"
+            "<host xmlns=\"urn:opendaylight:netconf-node-topology\">%s</host>"
+            "<port xmlns=\"urn:opendaylight:netconf-node-topology\">%d</port>"
+            "<username xmlns=\"urn:opendaylight:netconf-node-topology\">%s</username>"
+            "<password xmlns=\"urn:opendaylight:netconf-node-topology\">%s</password>"
+            "<tcp-only xmlns=\"urn:opendaylight:netconf-node-topology\">false</tcp-only>"
+            "<keepalive-delay xmlns=\"urn:opendaylight:netconf-node-topology\">120</keepalive-delay>"
+            "<reconnect-on-changed-schema xmlns=\"urn:opendaylight:netconf-node-topology\">false</reconnect-on-changed-schema>"
+            "<sleep-factor xmlns=\"urn:opendaylight:netconf-node-topology\">1.5</sleep-factor>"
+            "<connection-timeout-millis xmlns=\"urn:opendaylight:netconf-node-topology\">20000</connection-timeout-millis>"
+            "<max-connection-attempts xmlns=\"urn:opendaylight:netconf-node-topology\">100</max-connection-attempts>"
+            "<between-attempts-timeout-millis xmlns=\"urn:opendaylight:netconf-node-topology\">2000</between-attempts-timeout-millis>"
+            "</node>",
+                       device_name, device_port, (getenv("EXTERNAL_NTS_IP") == NULL) ? getenv("NTS_IP") : getenv("EXTERNAL_NTS_IP"),
+            device_port, "netconf", "netconf");
 
        printf("Post data:\n%s\n", post_data_xml);
 
@@ -514,7 +701,7 @@ static int send_mount_device_instance_tls(char *url, char *credentials, char *de
                        "<max-connection-attempts xmlns=\"urn:opendaylight:netconf-node-topology\">100</max-connection-attempts>"
                        "<between-attempts-timeout-millis xmlns=\"urn:opendaylight:netconf-node-topology\">2000</between-attempts-timeout-millis>"
                        "</node>",
-                       device_name, device_port, getenv("NTS_IP"), "netconf", device_port);
+                       device_name, device_port, (getenv("EXTERNAL_NTS_IP") == NULL) ? getenv("NTS_IP") : getenv("EXTERNAL_NTS_IP"), "netconf", device_port);
 
        printf("Post data:\n%s\n", post_data_xml);
 
@@ -577,7 +764,6 @@ static int send_unmount_device_instance(char *url, char *credentials, char *devi
                return SR_ERR_OPERATION_FAILED;
        }
 
-
        return SR_ERR_OK;
 }
 
@@ -586,21 +772,27 @@ static int send_mount_device(device_t *current_device, controller_t controller_d
 {
        int rc = SR_ERR_OK;
        bool is_mounted = true;
+    int port = 0;
+
+    char device_name[200];
+    sprintf(device_name, "%s-%d", getenv("CONTAINER_NAME"), current_device->device_number);
 
        //This is where we hardcoded: 7 devices will have SSH connections and 3 devices will have TLS connections
-       for (int port = 0; port < NETCONF_CONNECTIONS_PER_DEVICE - 3; ++port)
+       for (int i = 0; i < SSH_CONNECTIONS_PER_DEVICE; ++port, ++i)
        {
+        
+
                rc = send_mount_device_instance_ssh(controller_details.url, controller_details.credentials,
-                               current_device->device_id, current_device->netconf_port + port);
+                               device_name, current_device->netconf_port + port);
                if (rc != SR_ERR_OK)
                {
                        is_mounted = false;
                }
        }
-       for (int port = NETCONF_CONNECTIONS_PER_DEVICE - 3; port < NETCONF_CONNECTIONS_PER_DEVICE; ++port)
+       for (int i = 0; i < TLS_CONNECTIONS_PER_DEVICE; ++port, ++i)
        {
                rc = send_mount_device_instance_tls(controller_details.url, controller_details.credentials,
-                               current_device->device_id, current_device->netconf_port + port);
+                               device_name, current_device->netconf_port + port);
                if (rc != SR_ERR_OK)
                {
                        is_mounted = false;
@@ -615,15 +807,17 @@ static int send_mount_device(device_t *current_device, controller_t controller_d
 static int send_unmount_device(device_t *current_device, controller_t controller_details)
 {
        int rc = SR_ERR_OK;
+    char device_name[100];
+    sprintf(device_name, "%s-%d", getenv("CONTAINER_NAME"), current_device->device_number);
 
        for (int port = 0; port < NETCONF_CONNECTIONS_PER_DEVICE; ++port)
        {
                rc = send_unmount_device_instance(controller_details.url, controller_details.credentials,
-                               current_device->device_id, current_device->netconf_port + port);
+                               device_name, current_device->netconf_port + port);
                if (rc != SR_ERR_OK)
                {
                        printf("Could not send unmount for ODL with url=\"%s\", for device=\"%s\" and port=%d\n",
-                                       controller_details.url, current_device->device_id, current_device->netconf_port);
+                                       controller_details.url, device_name, current_device->netconf_port);
                }
        }
        current_device->is_mounted = false;
@@ -642,13 +836,14 @@ device_stack_t *new_device_stack(void)
        return stack;
 }
 
-void push_device(device_stack_t *theStack, char *dev_id, int port)
+void push_device(device_stack_t *theStack, char *dev_id, int port, int dev_num)
 {
        device_t *new_dev = malloc(sizeof(*new_dev));
 
        if (new_dev) {
                new_dev->device_id = strdup(dev_id);
                new_dev->netconf_port = port;
+        new_dev->device_number = dev_num;
                new_dev->is_mounted = false;
                new_dev->operational_state = strdup("not-specified");
 
@@ -674,39 +869,38 @@ void pop_device(device_stack_t *theStack)
 
 int get_netconf_port_next(device_stack_t *theStack)
 {
-       if (theStack && theStack->stack_size > 0) {
-               return theStack->head->netconf_port + NETCONF_CONNECTIONS_PER_DEVICE;
-       }
+    if (theStack && theStack->stack_size > 0) {
+        return theStack->head->netconf_port + NETCONF_CONNECTIONS_PER_DEVICE;
+    }
 
-       return get_netconf_port_base();
+    return get_netconf_port_base();
 }
 
 int get_netconf_port_base()
 {
-       int netconf_port_base = 0, rc;
-
-       char *netconf_base_string = getenv("NETCONF_BASE");
+    int netconf_port_base;
 
-       if (netconf_base_string != NULL)
-       {
-               rc = sscanf(netconf_base_string, "%d", &netconf_port_base);
-               if (rc != 1)
-               {
-                       printf("Could not get the NETCONF_BASE port! Using the default 30.000...\n");
-                       netconf_port_base = 30000;
-               }
-       }
+    netconf_port_base = getIntFromString(getenv("NETCONF_BASE"), 50000);
 
-       return netconf_port_base;
+    return netconf_port_base;
 }
 
+// we start numbering the containers from 0
+int get_device_number_next(device_stack_t *theStack)
+{
+    if (theStack && theStack->stack_size > 0) {
+        return theStack->head->device_number + 1;
+    }
+
+    return 0;
+}
 
 char *get_id_last_device(device_stack_t *theStack)
 {
-       if (theStack && theStack->head) {
-               return theStack->head->device_id;
-       }
-       return NULL;
+    if (theStack && theStack->head) {
+        return theStack->head->device_id;
+    }
+    return NULL;
 }
 
 int get_current_number_of_mounted_devices(device_stack_t *theStack)
@@ -732,6 +926,12 @@ int get_current_number_of_mounted_devices(device_stack_t *theStack)
 
 int get_current_number_of_devices(device_stack_t *theStack)
 {
+    //TODO implement function for k8s deployment
+    if (strcmp(getenv("K8S_DEPLOYMENT"), "true") == 0)
+    {
+        return 0;
+    }
+
        struct MemoryStruct curl_response_mem;
 
        curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
@@ -743,8 +943,8 @@ int get_current_number_of_devices(device_stack_t *theStack)
        set_curl_common_info();
 
        char url[100];
-       sprintf(url, "http:/v%s/containers/json?all=true&filters={\"label\":[\"NTS\"],\"status\":[\"running\"]}",
-                       getenv("DOCKER_ENGINE_VERSION"));
+       sprintf(url, "http:/v%s/containers/json?all=true&filters={\"label\":[\"NTS_Manager=%s\"],\"status\":[\"running\"]}",
+                       getenv("DOCKER_ENGINE_VERSION"), getenv("HOSTNAME"));
 
        curl_easy_setopt(curl, CURLOPT_URL, url);
 
@@ -827,18 +1027,29 @@ char* get_docker_container_operational_state(device_stack_t *theStack, char *con
 int start_device(device_stack_t *theStack)
 {
        int rc = SR_ERR_OK;
-       static cJSON* managerBindings = NULL;
+       static cJSON *managerBindings = NULL, *networkMode = NULL;
+
+    if (managerBindings == NULL)
+    {
+        managerBindings = get_docker_container_bindings();
+    }
 
-       if (managerBindings == NULL)
+    if (networkMode == NULL)
        {
-               managerBindings = get_docker_container_bindings();
+               networkMode = get_docker_container_network_node();
        }
 
        int netconf_base = get_netconf_port_next(theStack);
+    int device_number = get_device_number_next(theStack);
 
-       char *dev_id = create_docker_container_curl(netconf_base, managerBindings);
+       char *dev_id = create_docker_container_curl(netconf_base, managerBindings, networkMode, device_number);
+    if (dev_id == NULL)
+    {
+        printf("ERROR: Could not create docker container!\n");
+        return SR_ERR_OPERATION_FAILED;
+    }
 
-       push_device(theStack, dev_id, netconf_base);
+       push_device(theStack, dev_id, netconf_base, device_number);
 
        rc = start_docker_container_curl(dev_id);
        if (rc != SR_ERR_OK)
@@ -846,6 +1057,12 @@ int start_device(device_stack_t *theStack)
                printf("Could not start device with device_id=\"%s\"\n", dev_id);
        }
 
+    rc = rename_docker_container_curl(dev_id, device_number);
+       if (rc != SR_ERR_OK)
+       {
+               printf("Could not rename device with device_id=\"%s\"\n", dev_id);
+       }
+
        if (dev_id) {
                free(dev_id);
        }
@@ -897,6 +1114,28 @@ int cleanup_curl_odl()
        return SR_ERR_OK;
 }
 
+int _init_curl_k8s()
+{
+    curl_k8s = curl_easy_init();
+
+    if (curl_k8s == NULL) {
+        printf("cURL initialization error! Aborting call!\n");
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    return SR_ERR_OK;
+}
+
+int cleanup_curl_k8s()
+{
+    if (curl_k8s != NULL)
+    {
+        curl_easy_cleanup(curl_k8s);
+    }
+
+    return SR_ERR_OK;
+}
+
 int stop_device(device_stack_t *theStack)
 {
        int rc = SR_ERR_OK;
@@ -975,6 +1214,13 @@ int unmount_device(device_stack_t *theStack, controller_t controller_list)
 
 int get_docker_containers_operational_state_curl(device_stack_t *theStack)
 {
+
+    //TODO implement function for k8s deployment
+    if (strcmp(getenv("K8S_DEPLOYMENT"), "true") == 0)
+    {
+        return SR_ERR_OK;
+    }
+
        int rc = SR_ERR_OK;
        struct MemoryStruct curl_response_mem;
 
@@ -987,7 +1233,8 @@ int get_docker_containers_operational_state_curl(device_stack_t *theStack)
        set_curl_common_info();
 
        char url[100];
-       sprintf(url, "http:/v%s/containers/json?all=true&filters={\"label\":[\"NTS\"]}", getenv("DOCKER_ENGINE_VERSION"));
+       sprintf(url, "http:/v%s/containers/json?all=true&filters={\"label\":[\"NTS_Manager=%s\"]}", 
+    getenv("DOCKER_ENGINE_VERSION"), getenv("HOSTNAME"));
 
        curl_easy_setopt(curl, CURLOPT_URL, url);
 
@@ -1047,13 +1294,19 @@ int get_docker_containers_operational_state_curl(device_stack_t *theStack)
 
 char* get_docker_container_resource_stats(device_stack_t *theStack)
 {
+    //TOD need to implement this for k8s deployment
+    if (strcmp(getenv("K8S_DEPLOYMENT"), "true"))
+    {
+        return strdup("CPU=0%;RAM=0MiB");
+    }
+
        char line[LINE_BUFSIZE];
        int linenr;
        FILE *pipe;
 
        /* Get a pipe where the output from the scripts comes in */
        char script[200];
-       sprintf(script, "%s/docker_stats.sh", getenv("SCRIPTS_DIR"));
+       sprintf(script, "/opt/dev/docker_stats.sh %s", getenv("HOSTNAME"));
 
        pipe = popen(script, "r");
        if (pipe == NULL) {  /* check for errors */
@@ -1158,6 +1411,12 @@ int notification_delay_period_changed(sr_val_t *val, size_t count)
        stringConfiguration = cJSON_Print(jsonConfig);
        writeConfigFile(stringConfiguration);
 
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
        cJSON_Delete(jsonConfig);
 
        return SR_ERR_OK;
@@ -1211,6 +1470,12 @@ int ves_heartbeat_period_changed(int period)
        stringConfiguration = cJSON_Print(jsonConfig);
        writeConfigFile(stringConfiguration);
 
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
        cJSON_Delete(jsonConfig);
 
        return SR_ERR_OK;
@@ -1416,55 +1681,61 @@ int add_key_pair_to_odl(controller_t *controller_list, int controller_list_size)
 
 int ves_ip_changed(char *new_ip)
 {
-       char *stringConfiguration = readConfigFileInString();
+    char *stringConfiguration = readConfigFileInString();
 
-       if (stringConfiguration == NULL)
-       {
-               printf("Could not read configuration file!\n");
-               return SR_ERR_OPERATION_FAILED;
-       }
+    if (stringConfiguration == NULL)
+    {
+        printf("Could not read configuration file!\n");
+        return SR_ERR_OPERATION_FAILED;
+    }
 
-       cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
-       if (jsonConfig == NULL)
-       {
-               free(stringConfiguration);
-               const char *error_ptr = cJSON_GetErrorPtr();
-               if (error_ptr != NULL)
-               {
-                       fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
-               }
-               return SR_ERR_OPERATION_FAILED;
-       }
-       //we don't need the string anymore
-       free(stringConfiguration);
-       stringConfiguration = NULL;
+    cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
+    if (jsonConfig == NULL)
+    {
+        free(stringConfiguration);
+        const char *error_ptr = cJSON_GetErrorPtr();
+        if (error_ptr != NULL)
+        {
+            fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
+        }
+        return SR_ERR_OPERATION_FAILED;
+    }
+    //we don't need the string anymore
+    free(stringConfiguration);
+    stringConfiguration = NULL;
 
-       cJSON *vesDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "ves-endpoint-details");
-       if (!cJSON_IsObject(vesDetails))
-       {
-               printf("Configuration JSON is not as expected: ves-endpoint-details is not an object");
-               cJSON_Delete(jsonConfig);
-               return SR_ERR_OPERATION_FAILED;
-       }
+    cJSON *vesDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "ves-endpoint-details");
+    if (!cJSON_IsObject(vesDetails))
+    {
+        printf("Configuration JSON is not as expected: ves-endpoint-details is not an object");
+        cJSON_Delete(jsonConfig);
+        return SR_ERR_OPERATION_FAILED;
+    }
 
-       cJSON *vesIp = cJSON_GetObjectItemCaseSensitive(vesDetails, "ves-endpoint-ip");
-       if (!cJSON_IsString(vesIp))
-       {
-               printf("Configuration JSON is not as expected: ves-endpoint-ip is not a string");
-               cJSON_Delete(jsonConfig);
-               return SR_ERR_OPERATION_FAILED;
-       }
+    cJSON *vesIp = cJSON_GetObjectItemCaseSensitive(vesDetails, "ves-endpoint-ip");
+    if (!cJSON_IsString(vesIp))
+    {
+        printf("Configuration JSON is not as expected: ves-endpoint-ip is not a string");
+        cJSON_Delete(jsonConfig);
+        return SR_ERR_OPERATION_FAILED;
+    }
 
-       //we set the value of the fault-notification-delay-period object
-       cJSON_ReplaceItemInObject(vesDetails, "ves-endpoint-ip", cJSON_CreateString(new_ip));
+    //we set the value of the fault-notification-delay-period object
+    cJSON_ReplaceItemInObject(vesDetails, "ves-endpoint-ip", cJSON_CreateString(new_ip));
 
-       //writing the new JSON to the configuration file
-       stringConfiguration = cJSON_Print(jsonConfig);
-       writeConfigFile(stringConfiguration);
+    //writing the new JSON to the configuration file
+    stringConfiguration = cJSON_Print(jsonConfig);
+    writeConfigFile(stringConfiguration);
 
-       cJSON_Delete(jsonConfig);
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
 
-       return SR_ERR_OK;
+    cJSON_Delete(jsonConfig);
+
+    return SR_ERR_OK;
 }
 
 int ves_port_changed(int new_port)
@@ -1515,12 +1786,195 @@ int ves_port_changed(int new_port)
        stringConfiguration = cJSON_Print(jsonConfig);
        writeConfigFile(stringConfiguration);
 
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
        cJSON_Delete(jsonConfig);
 
        return SR_ERR_OK;
 }
 
-int ves_registration_changed(cJSON_bool new_bool)
+int ves_username_changed(char *new_username)
+{
+    char *stringConfiguration = readConfigFileInString();
+
+    if (stringConfiguration == NULL)
+    {
+        printf("Could not read configuration file!\n");
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
+    if (jsonConfig == NULL)
+    {
+        free(stringConfiguration);
+        const char *error_ptr = cJSON_GetErrorPtr();
+        if (error_ptr != NULL)
+        {
+            fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
+        }
+        return SR_ERR_OPERATION_FAILED;
+    }
+    //we don't need the string anymore
+    free(stringConfiguration);
+    stringConfiguration = NULL;
+
+    cJSON *vesDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "ves-endpoint-details");
+    if (!cJSON_IsObject(vesDetails))
+    {
+        printf("Configuration JSON is not as expected: ves-endpoint-details is not an object");
+        cJSON_Delete(jsonConfig);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    cJSON *vesUsername = cJSON_GetObjectItemCaseSensitive(vesDetails, "ves-endpoint-username");
+    if (!cJSON_IsString(vesUsername))
+    {
+        printf("Configuration JSON is not as expected: ves-endpoint-username is not a string");
+        cJSON_Delete(jsonConfig);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    //we set the value of the fault-notification-delay-period object
+    cJSON_ReplaceItemInObject(vesDetails, "ves-endpoint-username", cJSON_CreateString(new_username));
+
+    //writing the new JSON to the configuration file
+    stringConfiguration = cJSON_Print(jsonConfig);
+    writeConfigFile(stringConfiguration);
+
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
+    cJSON_Delete(jsonConfig);
+
+    return SR_ERR_OK;
+}
+
+int ves_password_changed(char *new_password)
+{
+    char *stringConfiguration = readConfigFileInString();
+
+    if (stringConfiguration == NULL)
+    {
+        printf("Could not read configuration file!\n");
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
+    if (jsonConfig == NULL)
+    {
+        free(stringConfiguration);
+        const char *error_ptr = cJSON_GetErrorPtr();
+        if (error_ptr != NULL)
+        {
+            fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
+        }
+        return SR_ERR_OPERATION_FAILED;
+    }
+    //we don't need the string anymore
+    free(stringConfiguration);
+    stringConfiguration = NULL;
+
+    cJSON *vesDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "ves-endpoint-details");
+    if (!cJSON_IsObject(vesDetails))
+    {
+        printf("Configuration JSON is not as expected: ves-endpoint-details is not an object");
+        cJSON_Delete(jsonConfig);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    cJSON *vesPassword = cJSON_GetObjectItemCaseSensitive(vesDetails, "ves-endpoint-password");
+    if (!cJSON_IsString(vesPassword))
+    {
+        printf("Configuration JSON is not as expected: ves-endpoint-password is not a string");
+        cJSON_Delete(jsonConfig);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    //we set the value of the fault-notification-delay-period object
+    cJSON_ReplaceItemInObject(vesDetails, "ves-endpoint-password", cJSON_CreateString(new_password));
+
+    //writing the new JSON to the configuration file
+    stringConfiguration = cJSON_Print(jsonConfig);
+    writeConfigFile(stringConfiguration);
+
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
+    cJSON_Delete(jsonConfig);
+
+    return SR_ERR_OK;
+}
+
+int ves_auth_method_changed(char *new_auth_method)
+{
+    char *stringConfiguration = readConfigFileInString();
+
+    if (stringConfiguration == NULL)
+    {
+        printf("Could not read configuration file!\n");
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
+    if (jsonConfig == NULL)
+    {
+        free(stringConfiguration);
+        const char *error_ptr = cJSON_GetErrorPtr();
+        if (error_ptr != NULL)
+        {
+            fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
+        }
+        return SR_ERR_OPERATION_FAILED;
+    }
+    //we don't need the string anymore
+    free(stringConfiguration);
+    stringConfiguration = NULL;
+
+    cJSON *vesDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "ves-endpoint-details");
+    if (!cJSON_IsObject(vesDetails))
+    {
+        printf("Configuration JSON is not as expected: ves-endpoint-details is not an object");
+        cJSON_Delete(jsonConfig);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    cJSON *vesAuthMethod = cJSON_GetObjectItemCaseSensitive(vesDetails, "ves-endpoint-auth-method");
+    if (!cJSON_IsString(vesAuthMethod))
+    {
+        printf("Configuration JSON is not as expected: ves-endpoint-auth-method is not a string");
+        cJSON_Delete(jsonConfig);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    //we set the value of the fault-notification-delay-period object
+    cJSON_ReplaceItemInObject(vesDetails, "ves-endpoint-auth-method", cJSON_CreateString(new_auth_method));
+
+    //writing the new JSON to the configuration file
+    stringConfiguration = cJSON_Print(jsonConfig);
+    writeConfigFile(stringConfiguration);
+
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
+    cJSON_Delete(jsonConfig);
+
+    return SR_ERR_OK;
+}
+
+int ves_registration_changed(cJSON_bool new_bool)
 {
        char *stringConfiguration = readConfigFileInString();
 
@@ -1568,6 +2022,12 @@ int ves_registration_changed(cJSON_bool new_bool)
        stringConfiguration = cJSON_Print(jsonConfig);
        writeConfigFile(stringConfiguration);
 
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
        cJSON_Delete(jsonConfig);
 
        return SR_ERR_OK;
@@ -1621,6 +2081,12 @@ int is_netconf_available_changed(cJSON_bool new_bool)
        stringConfiguration = cJSON_Print(jsonConfig);
        writeConfigFile(stringConfiguration);
 
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
        cJSON_Delete(jsonConfig);
 
        return SR_ERR_OK;
@@ -1674,7 +2140,870 @@ int is_ves_available_changed(cJSON_bool new_bool)
        stringConfiguration = cJSON_Print(jsonConfig);
        writeConfigFile(stringConfiguration);
 
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
+       cJSON_Delete(jsonConfig);
+
+       return SR_ERR_OK;
+}
+
+    int ssh_connections_changed(int number)
+    {
+    char *stringConfiguration = readConfigFileInString();
+
+    if (stringConfiguration == NULL)
+    {
+        printf("Could not read configuration file!\n");
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
+    if (jsonConfig == NULL)
+    {
+        free(stringConfiguration);
+        const char *error_ptr = cJSON_GetErrorPtr();
+        if (error_ptr != NULL)
+        {
+            fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
+        }
+        return SR_ERR_OPERATION_FAILED;
+    }
+    //we don't need the string anymore
+    free(stringConfiguration);
+    stringConfiguration = NULL;
+
+    cJSON *sshConnections = cJSON_GetObjectItemCaseSensitive(jsonConfig, "ssh-connections");
+    if (!cJSON_IsNumber(sshConnections))
+    {
+        printf("Configuration JSON is not as expected: ssh-connections is not an object");
+        cJSON_Delete(jsonConfig);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    //we set the value of the ssh-connections object
+    cJSON_SetNumberValue(sshConnections, number);
+
+    //writing the new JSON to the configuration file
+    stringConfiguration = cJSON_Print(jsonConfig);
+    writeConfigFile(stringConfiguration);
+
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
+    cJSON_Delete(jsonConfig);
+
+    return SR_ERR_OK;
+}
+
+int tls_connections_changed(int number)
+    {
+    char *stringConfiguration = readConfigFileInString();
+
+    if (stringConfiguration == NULL)
+    {
+        printf("Could not read configuration file!\n");
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
+    if (jsonConfig == NULL)
+    {
+        free(stringConfiguration);
+        const char *error_ptr = cJSON_GetErrorPtr();
+        if (error_ptr != NULL)
+        {
+            fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
+        }
+        return SR_ERR_OPERATION_FAILED;
+    }
+    //we don't need the string anymore
+    free(stringConfiguration);
+    stringConfiguration = NULL;
+
+    cJSON *tlsConnections = cJSON_GetObjectItemCaseSensitive(jsonConfig, "tls-connections");
+    if (!cJSON_IsNumber(tlsConnections))
+    {
+        printf("Configuration JSON is not as expected: tls-connections is not an object");
+        cJSON_Delete(jsonConfig);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    //we set the value of the tls-connections object
+    cJSON_SetNumberValue(tlsConnections, number);
+
+    //writing the new JSON to the configuration file
+    stringConfiguration = cJSON_Print(jsonConfig);
+    writeConfigFile(stringConfiguration);
+
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
+    cJSON_Delete(jsonConfig);
+
+    return SR_ERR_OK;
+}
+
+/*
+curl -X POST -H 'Content-Type: application/json' -i http://localhost:5000/extend-ports --data '{"number-of-ports":12}'
+*/
+int send_k8s_extend_port(void)
+{
+    int num_of_ports = getSshConnectionsFromConfigJson() + getTlsConnectionsFromConfigJson();
+
+    CURLcode res;
+
+    curl_easy_reset(curl_k8s);
+    set_curl_common_info_k8s();
+
+    char url_for_curl[100];
+    sprintf(url_for_curl, "http://localhost:5000/extend-ports");
+
+    curl_easy_setopt(curl_k8s, CURLOPT_URL, url_for_curl);
+
+    char post_data_json[1500];
+
+    sprintf(post_data_json,
+            "{\"number-of-ports\":%d}",
+            num_of_ports);
+
+    printf("Post data:\n%s\n", post_data_json);
+
+    curl_easy_setopt(curl_k8s, CURLOPT_POSTFIELDS, post_data_json);
+    curl_easy_setopt(curl_k8s, CURLOPT_CUSTOMREQUEST, "POST");
+
+    res = curl_easy_perform(curl_k8s);
+    if (res != CURLE_OK)
+    {
+        printf("cURL failed to url=%s\n", url_for_curl);
+    }
+
+    long http_response_code = 0;
+    curl_easy_getinfo (curl_k8s, CURLINFO_RESPONSE_CODE, &http_response_code);
+    if (http_response_code >= 200 && http_response_code <= 226 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
+    {
+        printf("cURL succeeded to url=%s\n", url_for_curl);
+    }
+    else
+    {
+        printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    return SR_ERR_OK;
+}
+
+/*
+curl -X POST -H 'Content-Type: application/json' -i http://localhost:5000/scale --data '{"simulatedDevices":2}'
+*/
+int send_k8s_scale(int number_of_devices)
+{
+    CURLcode res;
+
+    curl_easy_reset(curl_k8s);
+    set_curl_common_info_k8s();
+
+    char url_for_curl[100];
+    sprintf(url_for_curl, "http://localhost:5000/scale");
+
+    curl_easy_setopt(curl_k8s, CURLOPT_URL, url_for_curl);
+
+    char post_data_json[1500];
+
+    sprintf(post_data_json,
+            "{\"simulatedDevices\":%d}",
+            number_of_devices);
+
+    printf("Post data:\n%s\n", post_data_json);
+
+    curl_easy_setopt(curl_k8s, CURLOPT_POSTFIELDS, post_data_json);
+    curl_easy_setopt(curl_k8s, CURLOPT_CUSTOMREQUEST, "POST");
+
+    res = curl_easy_perform(curl_k8s);
+    if (res != CURLE_OK)
+    {
+        printf("cURL failed to url=%s\n", url_for_curl);
+    }
+
+    long http_response_code = 0;
+    curl_easy_getinfo (curl_k8s, CURLINFO_RESPONSE_CODE, &http_response_code);
+    if (http_response_code >= 200 && http_response_code <= 226 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
+    {
+        printf("cURL succeeded to url=%s\n", url_for_curl);
+    }
+    else
+    {
+        printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    return SR_ERR_OK;
+}
+
+int controller_ip_changed(char *new_ip)
+{
+       char *stringConfiguration = readConfigFileInString();
+
+       if (stringConfiguration == NULL)
+       {
+               printf("Could not read configuration file!\n");
+               return SR_ERR_OPERATION_FAILED;
+       }
+
+       cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
+       if (jsonConfig == NULL)
+       {
+               free(stringConfiguration);
+               const char *error_ptr = cJSON_GetErrorPtr();
+               if (error_ptr != NULL)
+               {
+                       fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
+               }
+               return SR_ERR_OPERATION_FAILED;
+       }
+       //we don't need the string anymore
+       free(stringConfiguration);
+       stringConfiguration = NULL;
+
+       cJSON *controllerDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "controller-details");
+       if (!cJSON_IsObject(controllerDetails))
+       {
+               printf("Configuration JSON is not as expected: controller-details is not an object");
+               cJSON_Delete(jsonConfig);
+               return SR_ERR_OPERATION_FAILED;
+       }
+
+       cJSON *controllerIp = cJSON_GetObjectItemCaseSensitive(controllerDetails, "controller-ip");
+       if (!cJSON_IsString(controllerIp))
+       {
+               printf("Configuration JSON is not as expected: controller-ip is not a string");
+               cJSON_Delete(jsonConfig);
+               return SR_ERR_OPERATION_FAILED;
+       }
+
+       //we set the value of the fault-notification-delay-period object
+       cJSON_ReplaceItemInObject(controllerDetails, "controller-ip", cJSON_CreateString(new_ip));
+
+       //writing the new JSON to the configuration file
+       stringConfiguration = cJSON_Print(jsonConfig);
+       writeConfigFile(stringConfiguration);
+
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
        cJSON_Delete(jsonConfig);
 
        return SR_ERR_OK;
 }
+
+int controller_port_changed(int new_port)
+{
+       char *stringConfiguration = readConfigFileInString();
+
+       if (stringConfiguration == NULL)
+       {
+               printf("Could not read configuration file!\n");
+               return SR_ERR_OPERATION_FAILED;
+       }
+
+       cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
+       if (jsonConfig == NULL)
+       {
+               free(stringConfiguration);
+               const char *error_ptr = cJSON_GetErrorPtr();
+               if (error_ptr != NULL)
+               {
+                       fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
+               }
+               return SR_ERR_OPERATION_FAILED;
+       }
+       //we don't need the string anymore
+       free(stringConfiguration);
+       stringConfiguration = NULL;
+
+       cJSON *controllerDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "controller-details");
+       if (!cJSON_IsObject(controllerDetails))
+       {
+               printf("Configuration JSON is not as expected: controller-details is not an object");
+               cJSON_Delete(jsonConfig);
+               return SR_ERR_OPERATION_FAILED;
+       }
+
+       cJSON *controllerPort = cJSON_GetObjectItemCaseSensitive(controllerDetails, "controller-port");
+       if (!cJSON_IsNumber(controllerPort))
+       {
+               printf("Configuration JSON is not as expected: controller-port is not a number.");
+               cJSON_Delete(jsonConfig);
+               return SR_ERR_OPERATION_FAILED;
+       }
+
+       //we set the value of the fault-notification-delay-period object
+       cJSON_SetNumberValue(controllerPort, new_port);
+
+       //writing the new JSON to the configuration file
+       stringConfiguration = cJSON_Print(jsonConfig);
+       writeConfigFile(stringConfiguration);
+
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
+       cJSON_Delete(jsonConfig);
+
+       return SR_ERR_OK;
+}
+
+int controller_netconf_call_home_port_changed(int new_port)
+{
+       char *stringConfiguration = readConfigFileInString();
+
+       if (stringConfiguration == NULL)
+       {
+               printf("Could not read configuration file!\n");
+               return SR_ERR_OPERATION_FAILED;
+       }
+
+       cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
+       if (jsonConfig == NULL)
+       {
+               free(stringConfiguration);
+               const char *error_ptr = cJSON_GetErrorPtr();
+               if (error_ptr != NULL)
+               {
+                       fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
+               }
+               return SR_ERR_OPERATION_FAILED;
+       }
+       //we don't need the string anymore
+       free(stringConfiguration);
+       stringConfiguration = NULL;
+
+       cJSON *controllerDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "controller-details");
+       if (!cJSON_IsObject(controllerDetails))
+       {
+               printf("Configuration JSON is not as expected: controller-details is not an object");
+               cJSON_Delete(jsonConfig);
+               return SR_ERR_OPERATION_FAILED;
+       }
+
+       cJSON *netconfCallHomePort = cJSON_GetObjectItemCaseSensitive(controllerDetails, "netconf-call-home-port");
+       if (!cJSON_IsNumber(netconfCallHomePort))
+       {
+               printf("Configuration JSON is not as expected: netconf-call-home-port is not a number.");
+               cJSON_Delete(jsonConfig);
+               return SR_ERR_OPERATION_FAILED;
+       }
+
+       //we set the value of the fault-notification-delay-period object
+       cJSON_SetNumberValue(netconfCallHomePort, new_port);
+
+       //writing the new JSON to the configuration file
+       stringConfiguration = cJSON_Print(jsonConfig);
+       writeConfigFile(stringConfiguration);
+
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
+       cJSON_Delete(jsonConfig);
+
+       return SR_ERR_OK;
+}
+
+int controller_username_changed(char *new_username)
+{
+       char *stringConfiguration = readConfigFileInString();
+
+       if (stringConfiguration == NULL)
+       {
+               printf("Could not read configuration file!\n");
+               return SR_ERR_OPERATION_FAILED;
+       }
+
+       cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
+       if (jsonConfig == NULL)
+       {
+               free(stringConfiguration);
+               const char *error_ptr = cJSON_GetErrorPtr();
+               if (error_ptr != NULL)
+               {
+                       fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
+               }
+               return SR_ERR_OPERATION_FAILED;
+       }
+       //we don't need the string anymore
+       free(stringConfiguration);
+       stringConfiguration = NULL;
+
+       cJSON *controllerDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "controller-details");
+       if (!cJSON_IsObject(controllerDetails))
+       {
+               printf("Configuration JSON is not as expected: controller-details is not an object");
+               cJSON_Delete(jsonConfig);
+               return SR_ERR_OPERATION_FAILED;
+       }
+
+       cJSON *controllerUsername = cJSON_GetObjectItemCaseSensitive(controllerDetails, "controller-username");
+       if (!cJSON_IsString(controllerUsername))
+       {
+               printf("Configuration JSON is not as expected: controller-username is not a string");
+               cJSON_Delete(jsonConfig);
+               return SR_ERR_OPERATION_FAILED;
+       }
+
+       //we set the value of the fault-notification-delay-period object
+       cJSON_ReplaceItemInObject(controllerDetails, "controller-username", cJSON_CreateString(new_username));
+
+       //writing the new JSON to the configuration file
+       stringConfiguration = cJSON_Print(jsonConfig);
+       writeConfigFile(stringConfiguration);
+
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
+       cJSON_Delete(jsonConfig);
+
+       return SR_ERR_OK;
+}
+
+int controller_password_changed(char *new_password)
+{
+       char *stringConfiguration = readConfigFileInString();
+
+       if (stringConfiguration == NULL)
+       {
+               printf("Could not read configuration file!\n");
+               return SR_ERR_OPERATION_FAILED;
+       }
+
+       cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
+       if (jsonConfig == NULL)
+       {
+               free(stringConfiguration);
+               const char *error_ptr = cJSON_GetErrorPtr();
+               if (error_ptr != NULL)
+               {
+                       fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
+               }
+               return SR_ERR_OPERATION_FAILED;
+       }
+       //we don't need the string anymore
+       free(stringConfiguration);
+       stringConfiguration = NULL;
+
+       cJSON *controllerDetails = cJSON_GetObjectItemCaseSensitive(jsonConfig, "controller-details");
+       if (!cJSON_IsObject(controllerDetails))
+       {
+               printf("Configuration JSON is not as expected: controller-details is not an object");
+               cJSON_Delete(jsonConfig);
+               return SR_ERR_OPERATION_FAILED;
+       }
+
+       cJSON *controllerPassword = cJSON_GetObjectItemCaseSensitive(controllerDetails, "controller-password");
+       if (!cJSON_IsString(controllerPassword))
+       {
+               printf("Configuration JSON is not as expected: controller-password is not a string");
+               cJSON_Delete(jsonConfig);
+               return SR_ERR_OPERATION_FAILED;
+       }
+
+       //we set the value of the fault-notification-delay-period object
+       cJSON_ReplaceItemInObject(controllerDetails, "controller-password", cJSON_CreateString(new_password));
+
+       //writing the new JSON to the configuration file
+       stringConfiguration = cJSON_Print(jsonConfig);
+       writeConfigFile(stringConfiguration);
+
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
+       cJSON_Delete(jsonConfig);
+
+       return SR_ERR_OK;
+}
+
+int netconf_call_home_changed(cJSON_bool new_bool)
+{
+       char *stringConfiguration = readConfigFileInString();
+
+       if (stringConfiguration == NULL)
+       {
+               printf("Could not read configuration file!\n");
+               return SR_ERR_OPERATION_FAILED;
+       }
+
+       cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
+       if (jsonConfig == NULL)
+       {
+               free(stringConfiguration);
+               const char *error_ptr = cJSON_GetErrorPtr();
+               if (error_ptr != NULL)
+               {
+                       fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
+               }
+               return SR_ERR_OPERATION_FAILED;
+       }
+       //we don't need the string anymore
+       free(stringConfiguration);
+       stringConfiguration = NULL;
+
+       cJSON *netconfCallHome = cJSON_GetObjectItemCaseSensitive(jsonConfig, "netconf-call-home");
+       if (!cJSON_IsBool(netconfCallHome))
+       {
+               printf("Configuration JSON is not as expected: netconf-call-home is not a bool.");
+               cJSON_Delete(jsonConfig);
+               return SR_ERR_OPERATION_FAILED;
+       }
+
+       //we set the value of the ves-registration object
+       cJSON_ReplaceItemInObject(jsonConfig, "netconf-call-home", cJSON_CreateBool(new_bool));
+
+       //writing the new JSON to the configuration file
+       stringConfiguration = cJSON_Print(jsonConfig);
+       writeConfigFile(stringConfiguration);
+
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
+       cJSON_Delete(jsonConfig);
+
+       return SR_ERR_OK;
+}
+
+static int start_device_notification(char *exec_id)
+{
+    struct MemoryStruct curl_response_mem;
+
+    curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
+    curl_response_mem.size = 0;    /* no data at this point */
+
+    CURLcode res;
+
+    curl_easy_reset(curl);
+    set_curl_common_info();
+
+    char url[500];
+    sprintf(url, "http:/v%s/exec/%s/start", getenv("DOCKER_ENGINE_VERSION"), exec_id);
+
+    curl_easy_setopt(curl, CURLOPT_URL, url);
+
+    cJSON *postDataJson = cJSON_CreateObject();
+
+    if (cJSON_AddFalseToObject(postDataJson, "Detach") == NULL)
+    {
+        printf("Could not create JSON object: Detach\n");
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    if (cJSON_AddFalseToObject(postDataJson, "Tty") == NULL)
+    {
+        printf("Could not create JSON object: Tty\n");
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    char *post_data_string = NULL;
+
+    post_data_string = cJSON_PrintUnformatted(postDataJson);
+
+    printf("Post data JSON:\n%s\n", post_data_string);
+
+    if (postDataJson != NULL)
+    {
+        cJSON_Delete(postDataJson);
+    }
+
+    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data_string);
+
+    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
+
+    res = curl_easy_perform(curl);
+
+    if (post_data_string != NULL)
+    {
+        free(post_data_string);
+    }
+
+    if (res != CURLE_OK)
+    {
+        return SR_ERR_OPERATION_FAILED;
+    }
+    else
+    {
+        cJSON *json_response = cJSON_Parse(curl_response_mem.memory);
+        const cJSON *message = NULL;
+
+        printf("%lu bytes retrieved\n", (unsigned long)curl_response_mem.size);
+
+        message = cJSON_GetObjectItemCaseSensitive(json_response, "message");
+
+        if (cJSON_IsString(message) && (message->valuestring != NULL))
+        {
+            printf("Message: \"%s\"\n", message->valuestring);
+        }
+
+        cJSON_Delete(json_response);
+    }
+
+    return SR_ERR_OK;
+}
+
+static int inspect_device_notification_execution(char *exec_id)
+{
+    int rc = SR_ERR_OK;
+
+    struct MemoryStruct curl_response_mem;
+
+    curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
+    curl_response_mem.size = 0;    /* no data at this point */
+
+    CURLcode res;
+
+    curl_easy_reset(curl);
+    set_curl_common_info();
+
+    char url[500];
+    sprintf(url, "http:/v%s/exec/%s/json", getenv("DOCKER_ENGINE_VERSION"), exec_id);
+
+    curl_easy_setopt(curl, CURLOPT_URL, url);
+
+    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
+    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
+
+    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
+
+    res = curl_easy_perform(curl);
+
+    if (res != CURLE_OK)
+    {
+        rc = SR_ERR_OPERATION_FAILED;
+    }
+    else
+    {
+        cJSON *json_response = cJSON_Parse(curl_response_mem.memory);
+        const cJSON *exit_code = NULL;
+
+        exit_code = cJSON_GetObjectItemCaseSensitive(json_response, "ExitCode");
+
+        if (cJSON_IsNumber(exit_code))
+        {
+            rc = exit_code->valueint;
+        }
+        else
+        {
+            printf("Exit code is not a number!\n");
+            rc = SR_ERR_OPERATION_FAILED;
+        }
+        
+        cJSON_Delete(json_response);
+    }
+
+    return rc;
+}
+
+int invoke_device_notification(char *device_id, char *module_name, char *notification_string)
+{
+    int rc = SR_ERR_OK;
+
+    printf("Device-name = %s\nModule-name = %s\nNotification-object = %s\n", device_id, module_name, notification_string);
+
+    struct MemoryStruct curl_response_mem;
+
+    curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
+    curl_response_mem.size = 0;    /* no data at this point */
+
+    CURLcode res;
+
+    curl_easy_reset(curl);
+    set_curl_common_info();
+
+    char url[300];
+    sprintf(url, "http:/v%s/containers/%s/exec", getenv("DOCKER_ENGINE_VERSION"), device_id);
+
+    curl_easy_setopt(curl, CURLOPT_URL, url);
+
+    cJSON *postDataJson = cJSON_CreateObject();
+
+    if (cJSON_AddFalseToObject(postDataJson, "AtttachStdin") == NULL)
+    {
+        printf("Could not create JSON object: AtttachStdin\n");
+        rc = SR_ERR_OPERATION_FAILED;
+        goto cleanup;
+    }
+
+    if (cJSON_AddTrueToObject(postDataJson, "AtttachStdout") == NULL)
+    {
+        printf("Could not create JSON object: AtttachStdout\n");
+        rc = SR_ERR_OPERATION_FAILED;
+        goto cleanup;
+    }
+
+    if (cJSON_AddTrueToObject(postDataJson, "AtttachStderr") == NULL)
+    {
+        printf("Could not create JSON object: AtttachStderr\n");
+        rc = SR_ERR_OPERATION_FAILED;
+        goto cleanup;
+    }
+
+    if (cJSON_AddTrueToObject(postDataJson, "Privileged") == NULL)
+    {
+        printf("Could not create JSON object: Privileged\n");
+        rc = SR_ERR_OPERATION_FAILED;
+        goto cleanup;
+    }
+
+    if (cJSON_AddStringToObject(postDataJson, "User", "root") == NULL)
+    {
+        printf("Could not create JSON object: User\n");
+        rc = SR_ERR_OPERATION_FAILED;
+        goto cleanup;
+    }
+
+    cJSON *cmd_array = cJSON_CreateArray();
+    if (cmd_array == NULL)
+    {
+        printf("Could not create JSON object: Cmd array\n");
+        rc = SR_ERR_OPERATION_FAILED;
+        goto cleanup;
+    }
+
+    cJSON_AddItemToObject(postDataJson, "Cmd", cmd_array);
+
+    cJSON *cmd_string_1 = cJSON_CreateString("sh");
+    cJSON_AddItemToArray(cmd_array, cmd_string_1);
+
+    cJSON *cmd_string_2 = cJSON_CreateString("-c");
+    cJSON_AddItemToArray(cmd_array, cmd_string_2);
+
+    //some notifications require a really long notification object
+    char string_command[1000000];
+    sprintf(string_command, "/usr/local/bin/generic-notifications %s '%s'", module_name, notification_string);
+
+    cJSON *cmd_string_3 = cJSON_CreateString(string_command);
+    cJSON_AddItemToArray(cmd_array, cmd_string_3);
+
+    char *post_data_string = NULL;
+
+    post_data_string = cJSON_PrintUnformatted(postDataJson);
+
+    printf("Post data JSON:\n%s\n", post_data_string);
+
+    if (postDataJson != NULL)
+    {
+        cJSON_Delete(postDataJson);
+    }
+
+    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data_string);
+
+    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
+
+    res = curl_easy_perform(curl);
+
+    if (post_data_string != NULL)
+    {
+        free(post_data_string);
+    }
+
+    if (res != CURLE_OK)
+    {
+        rc = SR_ERR_OPERATION_FAILED;
+        goto cleanup;
+    }
+    else
+    {
+        cJSON *json_response = cJSON_Parse(curl_response_mem.memory);
+        const cJSON *exec_id = NULL;
+
+        exec_id = cJSON_GetObjectItemCaseSensitive(json_response, "Id");
+
+        if (cJSON_IsString(exec_id) && (exec_id->valuestring != NULL))
+        {
+            printf("Exec id: \"%s\"\n", exec_id->valuestring);
+
+            rc = start_device_notification(exec_id->valuestring);
+            if (rc != SR_ERR_OK)
+            {
+                printf("Could not start the execution of the notification...\n");
+            }
+
+            sleep(1);
+
+            rc = inspect_device_notification_execution(exec_id->valuestring);
+        }
+
+        cJSON_Delete(json_response);
+    }
+
+cleanup:
+    if (device_id != NULL)
+    {
+        free(device_id);
+    }
+    if (module_name != NULL)
+    {
+        free(module_name);
+    }
+    if (notification_string != NULL)
+    {
+        free(notification_string);
+    }
+
+    return rc;
+}
+
+int pull_docker_image_of_simulated_device()
+{
+    struct MemoryStruct curl_response_mem;
+
+    curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
+    curl_response_mem.size = 0;    /* no data at this point */
+
+    CURLcode res;
+
+    curl_easy_reset(curl);
+    set_curl_common_info();
+
+    char url[300];
+    sprintf(url, "http:/v%s/images/create?fromImage=%s", getenv("DOCKER_ENGINE_VERSION"), getenv("MODELS_IMAGE"));
+
+    curl_easy_setopt(curl, CURLOPT_URL, url);
+
+    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
+
+    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
+
+    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 300L);
+
+    res = curl_easy_perform(curl);
+
+    if (res != CURLE_OK)
+    {
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    return SR_ERR_OK;
+}
\ No newline at end of file