Add supoprt for D release use-case.
[sim/o1-interface.git] / ntsimulator / ntsim-ng / core / container.c
diff --git a/ntsimulator/ntsim-ng/core/container.c b/ntsimulator/ntsim-ng/core/container.c
new file mode 100644 (file)
index 0000000..a3e7b11
--- /dev/null
@@ -0,0 +1,264 @@
+/*************************************************************************
+*
+* 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 "container.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>
+
+struct installable_module {
+    char *name;
+    char *fullpath;
+    bool installed;
+    bool submodule;
+};
+
+
+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 bool container_rules_is_excluded_module(const char *module);
+static bool container_rules_is_excluded_feature(const char *feature);
+
+bool container_self_init(void) {
+    int rc;
+
+    sr_log_stderr(SR_LL_NONE);
+    log_add_verbose(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\n");
+        return false;
+    }
+
+    /* get context */
+    session_context = (struct ly_ctx *)sr_get_context(session_connection);
+    if(session_context == 0) {
+        log_error("sr_get_context failed\n");
+        return false;
+    }
+
+    /* install yang files */
+    log_add_verbose(1, "Installing yang files...\n");
+    struct installable_module *modules;
+    int total_modules = get_installable_modules(&modules);
+    log_add_verbose(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(!container_rules_is_excluded_module(modules[i].name)) {
+                        log_add_verbose(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_add(1, LOG_COLOR_BOLD_YELLOW"failed"LOG_COLOR_RESET"\n");
+                        }
+                        else {
+                            log_add(1, LOG_COLOR_BOLD_GREEN"done"LOG_COLOR_RESET"\n");
+                            modules[i].installed = true;
+                        }
+                    }
+                    else {
+                        log_add_verbose(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_add_verbose(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...\n", install_round);
+        return false;
+    }
+    else {
+        log_add_verbose(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_add_verbose(1, "Setting access configuration for installed modules... ");
+    for(int i = 0; i < total_modules; i++) {
+        if((!container_rules_is_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...\n", modules[i].name);
+                return false;
+            }
+        }
+    }
+    log_add(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\n");
+        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\n");
+        return false;
+    }
+
+    /* enable features */
+    log_add_verbose(1, "Enabling yang features...\n");
+    char **available_features;
+    int total_available_features;
+    total_available_features = context_get_features(&available_features);
+    log_add_verbose(1, "Found total features: %d\n", total_available_features);
+    for(int i = 0; i < total_available_features; i++) {
+        log_add_verbose(1, "feature %s: ", available_features[i]);
+
+        if(!context_get_feature_enabled(available_features[i])) {
+            if(!container_rules_is_excluded_feature(available_features[i])) {
+                if(context_feature_enable(available_features[i])) {
+                    log_add(1, "enabling... "LOG_COLOR_BOLD_GREEN"done"LOG_COLOR_RESET"\n");
+                }
+                else {
+                    log_error("enabling... failed\n");
+                }
+            }
+            else {
+                log_add(1, "excluded in config, skipping\n");
+            }
+        }
+        else {
+            log_add(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_add_verbose(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("allocation failed\n");
+                        return;
+                    }
+
+                    (*modules)[*total].name = (char*)malloc(sizeof(char) * (strlen(dir->d_name) + 1));
+                    if(!(*modules)[*total].name) {
+                        log_error("allocation failed\n");
+                        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("allocation failed\n");
+                        return;
+                    }
+                    sprintf((*modules)[*total].fullpath, "%s/%s", path, dir->d_name);
+
+                    (*modules)[*total].installed = false;
+                    (*modules)[*total].submodule = false;
+
+                    (*total)++;
+                }
+            }
+        }
+        closedir(d);
+    }
+}
+
+static bool container_rules_is_excluded_module(const char *module) {
+    assert(module);
+
+    for(int i = 0; i < framework_config.docker.excluded_modules_count; i++) {
+        if(strstr(module, framework_config.docker.excluded_modules[i]) != 0) {
+            return true;
+        }
+    }
+    
+    return false;
+}
+
+static bool container_rules_is_excluded_feature(const char *feature) {
+    assert(feature);
+
+    for(int i = 0; i < framework_config.docker.excluded_features_count; i++) {
+        if(strstr(feature, framework_config.docker.excluded_features[i]) != 0) {
+            return true;
+        }
+    }
+    
+    return false;
+}
\ No newline at end of file