Add supoprt for D release use-case.
[sim/o1-interface.git] / ntsimulator / ntsim-ng / core / container.c
1 /*************************************************************************
2 *
3 * Copyright 2020 highstreet technologies GmbH and others
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 ***************************************************************************/
17
18 #define _GNU_SOURCE
19
20 #include "container.h"
21 #include "utils/log_utils.h"
22 #include "utils/sys_utils.h"
23 #include "utils/http_client.h"
24 #include "core/framework.h"
25 #include "core/session.h"
26 #include "core/context.h"
27 #include <sysrepo.h>
28 #include <dirent.h>
29 #include <assert.h>
30
31 struct installable_module {
32     char *name;
33     char *fullpath;
34     bool installed;
35     bool submodule;
36 };
37
38
39 static int get_installable_modules(struct installable_module **modules);    //list available modules for install
40 static void list_yangs(const char *path, struct installable_module **modules, int *total);
41 static bool container_rules_is_excluded_module(const char *module);
42 static bool container_rules_is_excluded_feature(const char *feature);
43
44 bool container_self_init(void) {
45     int rc;
46
47     sr_log_stderr(SR_LL_NONE);
48     log_add_verbose(1, "Entering container-init mode...\n");
49
50     // connect to sysrepo
51     rc = sr_connect(0, &session_connection);
52     if(SR_ERR_OK != rc) {
53         log_error("sr_connect failed\n");
54         return false;
55     }
56
57     /* get context */
58     session_context = (struct ly_ctx *)sr_get_context(session_connection);
59     if(session_context == 0) {
60         log_error("sr_get_context failed\n");
61         return false;
62     }
63
64     /* install yang files */
65     log_add_verbose(1, "Installing yang files...\n");
66     struct installable_module *modules;
67     int total_modules = get_installable_modules(&modules);
68     log_add_verbose(1, "Found total modules: %d\n", total_modules);
69
70     int old_failed_installations = 1;
71     int failed_installations = 0;
72     int install_round = 0;
73     while(failed_installations != old_failed_installations) {
74         old_failed_installations = failed_installations;
75         failed_installations = 0;
76         install_round++;
77         for(int i = 0; i < total_modules; i++) {
78             if(!modules[i].installed) {
79                 modules[i].submodule = context_yang_is_module(modules[i].fullpath);
80                 if(!modules[i].submodule) {
81                     if(!container_rules_is_excluded_module(modules[i].name)) {
82                         log_add_verbose(1, "[round %d] trying to install module %s from %s... ", install_round, modules[i].name, modules[i].fullpath);
83                         if(!context_module_install(modules[i].name, modules[i].fullpath)) {
84                             failed_installations++;
85                             log_add(1, LOG_COLOR_BOLD_YELLOW"failed"LOG_COLOR_RESET"\n");
86                         }
87                         else {
88                             log_add(1, LOG_COLOR_BOLD_GREEN"done"LOG_COLOR_RESET"\n");
89                             modules[i].installed = true;
90                         }
91                     }
92                     else {
93                         log_add_verbose(1, "[round %d] not installing module %s as it's excluded in config.\n", install_round, modules[i].name);
94                         modules[i].installed = true;
95                     }
96                 }
97                 else {
98                     log_add_verbose(1, "[round %d] %s is a submodule... "LOG_COLOR_BOLD_YELLOW"skipping"LOG_COLOR_RESET"\n", install_round, modules[i].name);
99                     modules[i].installed = true;
100                 }
101             }
102         }
103     }
104
105     if(failed_installations != 0) {
106         log_error("failed to install all modules in %d rounds...\n", install_round);
107         return false;
108     }
109     else {
110         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));
111     }
112
113     //set access for all installed modules
114     log_add_verbose(1, "Setting access configuration for installed modules... ");
115     for(int i = 0; i < total_modules; i++) {
116         if((!container_rules_is_excluded_module(modules[i].name)) && (!modules[i].submodule)) {
117             if(!context_module_set_access(modules[i].name)) {
118                 log_error("failed to set access to module %s...\n", modules[i].name);
119                 return false;
120             }
121         }
122     }
123     log_add(1, LOG_COLOR_BOLD_GREEN"done"LOG_COLOR_RESET"\n");
124
125     //cleanup module-install used memory
126     for(int i = 0; i < total_modules; i++) {
127         free(modules[i].name);
128         free(modules[i].fullpath);
129     }
130     free(modules);
131
132     //get context
133     session_context = (struct ly_ctx *)sr_get_context(session_connection);
134     if(session_context == 0) {
135         log_error("sr_get_context failed\n");
136         return false;
137     }
138
139     //init context so we can see all the available modules, features, etc
140     rc = context_init(session_context);
141     if(rc != 0) {
142         log_error("context_init() failed\n");
143         return false;
144     }
145
146     /* enable features */
147     log_add_verbose(1, "Enabling yang features...\n");
148     char **available_features;
149     int total_available_features;
150     total_available_features = context_get_features(&available_features);
151     log_add_verbose(1, "Found total features: %d\n", total_available_features);
152     for(int i = 0; i < total_available_features; i++) {
153         log_add_verbose(1, "feature %s: ", available_features[i]);
154
155         if(!context_get_feature_enabled(available_features[i])) {
156             if(!container_rules_is_excluded_feature(available_features[i])) {
157                 if(context_feature_enable(available_features[i])) {
158                     log_add(1, "enabling... "LOG_COLOR_BOLD_GREEN"done"LOG_COLOR_RESET"\n");
159                 }
160                 else {
161                     log_error("enabling... failed\n");
162                 }
163             }
164             else {
165                 log_add(1, "excluded in config, skipping\n");
166             }
167         }
168         else {
169             log_add(1, "already "LOG_COLOR_BOLD_GREEN"enabled"LOG_COLOR_RESET", skipping.\n");
170         }
171     }
172     for(int i = 0; i < total_available_features; i++) {
173         free(available_features[i]);
174     }
175     free(available_features);
176
177     sr_disconnect(session_connection);
178     context_free();
179
180     log_add_verbose(1, LOG_COLOR_BOLD_GREEN"ntsim successfully initialized Docker container"LOG_COLOR_RESET"\n");
181     return true;
182 }
183
184 static int get_installable_modules(struct installable_module **modules) {
185     int total = 0;
186     *modules = 0;
187     list_yangs("/opt/dev/deploy/yang", modules, &total);
188     return total;
189 }
190
191 static void list_yangs(const char *path, struct installable_module **modules, int *total) {
192     DIR *d;
193     struct dirent *dir;
194     d = opendir(path);
195     if(d) {
196         while((dir = readdir(d)) != NULL) {
197             if(dir->d_type == DT_DIR) {
198                 if(strcmp(dir->d_name, ".") != 0 && strcmp(dir->d_name, "..") != 0)
199                 {
200                     char new_path[1024];
201                     snprintf(new_path, sizeof(new_path), "%s/%s", path, dir->d_name);
202                     list_yangs(new_path, modules, total);
203                 }
204             } else {
205                 if(strstr(dir->d_name, ".yang") != 0) {
206                     *modules = (struct installable_module *)realloc(*modules, sizeof(struct installable_module) * (*total + 1));
207                     if(!*modules) {
208                         log_error("allocation failed\n");
209                         return;
210                     }
211
212                     (*modules)[*total].name = (char*)malloc(sizeof(char) * (strlen(dir->d_name) + 1));
213                     if(!(*modules)[*total].name) {
214                         log_error("allocation failed\n");
215                         return;
216                     }
217                     strcpy((*modules)[*total].name, dir->d_name);
218                     (*modules)[*total].name[strlen(dir->d_name) - 5] = 0;   //extract ".yang"
219                     char *rev = strstr((*modules)[*total].name, "@");
220                     if(rev) { //extract revision, if exists
221                         *rev = 0;
222                     }
223
224                     (*modules)[*total].fullpath = (char*)malloc(sizeof(char) * (strlen(path) + 1 + strlen(dir->d_name) + 1));
225                     if(!(*modules)[*total].fullpath) {
226                         log_error("allocation failed\n");
227                         return;
228                     }
229                     sprintf((*modules)[*total].fullpath, "%s/%s", path, dir->d_name);
230
231                     (*modules)[*total].installed = false;
232                     (*modules)[*total].submodule = false;
233
234                     (*total)++;
235                 }
236             }
237         }
238         closedir(d);
239     }
240 }
241
242 static bool container_rules_is_excluded_module(const char *module) {
243     assert(module);
244
245     for(int i = 0; i < framework_config.docker.excluded_modules_count; i++) {
246         if(strstr(module, framework_config.docker.excluded_modules[i]) != 0) {
247             return true;
248         }
249     }
250     
251     return false;
252 }
253
254 static bool container_rules_is_excluded_feature(const char *feature) {
255     assert(feature);
256
257     for(int i = 0; i < framework_config.docker.excluded_features_count; i++) {
258         if(strstr(feature, framework_config.docker.excluded_features[i]) != 0) {
259             return true;
260         }
261     }
262     
263     return false;
264 }