Add NF addressing method as ENV.
[sim/o1-interface.git] / ntsimulator / ntsim-ng / core / framework.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 "framework.h"
21 #include <string.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <limits.h>
26 #include <assert.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <cjson/cJSON.h>
30
31 #include "utils/sys_utils.h"
32 #include "utils/log_utils.h"
33 #include "utils/rand_utils.h"
34
35 framework_arguments_t framework_arguments;
36 framework_environment_t framework_environment;
37 framework_config_t framework_config;
38
39 const char *argp_program_version = 0;    //is set later
40 const char *argp_program_bug_address = "<alexandru.stancu@highstreet-technologies.com> / <adrian.lita@highstreet-technologies.com>";
41 static char doc[] = "ntsim - new generation";
42
43 static struct argp_option options[] = {
44     { "container-init", 'i', 0, 0, "Runs initialization tasks for the Docker container that's being built. Do not run manually." },
45     { "supervisor", 's', 0, 0, "Run as supervisor; manager/network-function is chosen via config.json"},
46     { "manager", 'm', 0, 0, "Run the daemon as manager." },
47     { "network-function", 'f', 0, 0, "Run the daemon as network function." },
48     { "generate", 'g', 0, 0, "Generate population data without commiting." },
49     { "test-mode", 't', 0, 0, "Test mode." },
50     
51     // tools
52     { "ls", '1', 0, 0, "Print all available root paths." },
53     { "schema", '2', "XPATH", 0, "Print schema for XPATH." },
54     
55     { "fixed-rand", 'r', "SEED", 0, "Initialize RAND seed to a fixed value (for debugging purposes)." },
56     { "verbose", 'v', "LEVEL", 0, "Verbosity level for printing to stdout (logs will still save everything). LEVEL is: 0=errors only, 1=requested info(default), 2=info" },
57     { "workspace", 'w', "PATH", 0, "Initialize workspace to a different one than the current working directory." },
58     { 0 } 
59 };
60
61 volatile sig_atomic_t framework_sigint;
62
63 static int framework_env_init(void);
64 static int framework_config_init(void);
65
66 static void framework_signal_handler(int signo);
67 static error_t parse_opt(int key, char *arg, struct argp_state *state);
68
69 int framework_init(int argc, char **argv) {
70     //environment vars
71     framework_environment.nts.version = (getenv(ENV_VAR_NTS_BUILD_VERSION) && strlen(getenv(ENV_VAR_NTS_BUILD_VERSION))) ? strdup(getenv(ENV_VAR_NTS_BUILD_VERSION)) : strdup(NTS_VERSION_FALLBACK"!");
72     framework_environment.nts.build_time = (getenv(ENV_VAR_NTS_BUILD_TIME) && strlen(getenv(ENV_VAR_NTS_BUILD_TIME))) ? strdup(getenv(ENV_VAR_NTS_BUILD_TIME)) : strdup("N/A");
73
74     //set argp_version
75     char *version = 0;
76     asprintf(&version, "ntsim-ng v%s build %s", framework_environment.nts.version, framework_environment.nts.build_time);
77     argp_program_version = version;
78
79     //initialize app arguments
80     framework_arguments.nts_mode = NTS_MODE_DEFAULT;
81
82     framework_arguments.argc = argc;
83     framework_arguments.argv = argv;
84
85     framework_arguments.no_rand = false;
86     framework_arguments.fixed_seed = 0;
87     framework_arguments.verbosity_level = 1;
88
89     framework_arguments.print_root_paths = false;
90     framework_arguments.print_structure_xpath = 0;
91
92     //parse provided command line arguments
93     struct argp argp = { options, parse_opt, 0, doc, 0, 0, 0 };
94     argp_parse(&argp, argc, argv, 0, 0, &framework_arguments);
95
96     //manage signals
97     framework_sigint = 0;
98     signal(SIGINT, framework_signal_handler);
99     signal(SIGTERM, framework_signal_handler);
100     signal(SIGQUIT, framework_signal_handler);
101
102     //disable buffering for stdout
103     setbuf(stdout, NULL);
104
105     //init logging subsystem
106     char *log_file = 0;
107     char *stderr_file = 0;
108
109     if(!dir_exists("log")) {
110         mkdir("log", 0777);
111     }
112
113     switch(framework_arguments.nts_mode) {
114         case NTS_MODE_CONTAINER_INIT:
115             log_file = "log/log-install.txt";
116             stderr_file = "log/stderr-install.txt";
117             break;
118
119         case NTS_MODE_SUPERVISOR:
120             log_file = "log/log-supervisor.txt";
121             stderr_file = "log/stderr-supervisor.txt";
122             break;
123
124         case NTS_MODE_GENERATE_DATA:
125             log_file = "log/log-generate.txt";
126             stderr_file = "log/stderr-generate.txt";
127             break;
128
129         default:
130             log_file = "log/log.txt";
131             stderr_file = "log/stderr.txt";
132             break;
133     }
134
135     log_init(log_file);
136     log_redirect_stderr(stderr_file);
137
138     char cwd[PATH_MAX];
139     getcwd(cwd, sizeof(cwd));
140     log_add_verbose(2, "[framework] current working dir is: %s\n", cwd);
141
142     //init rand generator if needed
143     if(framework_arguments.no_rand == false) {
144         rand_init();
145     }
146     else {
147         rand_init_fixed(framework_arguments.fixed_seed);
148     }
149
150     log_add_verbose(2, "[framework] app was called: ");
151     for(int i = 0; i < argc; i++) {
152         log_add(2, "%s ", argv[i]);
153     }
154     log_add(2, "\n");
155
156     if(framework_env_init() != NTS_ERR_OK) {
157         log_error("[framework] framework_env_init() failed\n");
158         return NTS_ERR_FAILED;
159     }
160
161     if(framework_config_init() != NTS_ERR_OK) {
162         log_error("[framework] framework_config_init() failed\n");
163         return NTS_ERR_FAILED;
164     }
165
166     log_add_verbose(2, "[framework] init complete\n");
167     return NTS_ERR_OK;
168 }
169
170 static int framework_env_init(void) {
171     log_add_verbose(2, "[framework-env] started\n");
172
173     /*
174     The following env vars are taken care of by framework_init()
175         framework_environment.nts.version
176         framework_environment.nts.build_time
177     */
178
179     framework_environment.nts.manual = getenv(ENV_VAR_NTS_MANUAL) ? true : false;
180     framework_environment.nts.function_type = getenv(ENV_VAR_NTS_FUNCTION_TYPE) ? strdup(getenv(ENV_VAR_NTS_FUNCTION_TYPE)) : strdup("");
181     framework_environment.nts.nf_standalone_start_features = getenv(ENV_VAR_NTS_NF_STANDALONE_START_FEATURES) ? strdup(getenv(ENV_VAR_NTS_NF_STANDALONE_START_FEATURES)) : strdup("");
182     framework_environment.nts.nf_mount_point_addressing_method = getenv(ENV_VAR_NTS_NF_MOUNT_POINT_ADDRESSING_METHOD) ? strdup(getenv(ENV_VAR_NTS_NF_MOUNT_POINT_ADDRESSING_METHOD)) : strdup("docker-mapping");
183
184     framework_environment.settings.docker_repository = getenv(ENV_VAR_DOCKER_REPOSITORY) ? strdup(getenv(ENV_VAR_DOCKER_REPOSITORY)) : strdup("");
185     if(strlen(framework_environment.settings.docker_repository)) {
186         if(framework_environment.settings.docker_repository[strlen(framework_environment.settings.docker_repository) - 1] == '/') {
187             framework_environment.settings.docker_repository[strlen(framework_environment.settings.docker_repository) - 1] = 0;
188         }
189     }
190     framework_environment.settings.docker_engine_version = getenv(ENV_VAR_DOCKER_ENGINE_VERSION) ? strdup(getenv(ENV_VAR_DOCKER_ENGINE_VERSION)) : strdup("1.40");
191     framework_environment.settings.hostname = getenv(ENV_VAR_HOSTNAME) ? strdup(getenv(ENV_VAR_HOSTNAME)) : strdup("localhost");
192
193     bool ip_ok = get_local_ips("eth0", &framework_environment.settings.ip_v4, &framework_environment.settings.ip_v6);
194     if(!ip_ok) {
195         log_error("[framework-env] could not get local IP addresses\n");
196     }
197
198     char *ipv6_env_var = getenv(ENV_VAR_IPV6ENABLED);
199     if(ipv6_env_var == 0) {
200         log_error("[framework-env] could not get the IPv6 Enabled env variable\n");
201     }
202     framework_environment.settings.ip_v6_enabled = (strcmp(ipv6_env_var, "true") == 0) ? true : false;
203     framework_environment.settings.ssh_connections = get_int_from_string_with_default(getenv(ENV_VAR_SSH_CONNECTIONS), 1);
204     framework_environment.settings.tls_connections = get_int_from_string_with_default(getenv(ENV_VAR_TLS_CONNECTIONS), 0);
205     framework_environment.settings.ftp_connections = 1;
206     framework_environment.settings.sftp_connections = 1;
207
208     //build version and build time are set in the begining of the function
209     framework_environment.host.ip = getenv(ENV_VAR_HOST_IP) ? strdup(getenv(ENV_VAR_HOST_IP)) : strdup("127.0.0.1");
210     framework_environment.host.base_port = get_int_from_string_with_default(getenv(ENV_VAR_HOST_BASE_PORT), 1000);
211     framework_environment.host.ssh_base_port = get_int_from_string_with_default(getenv(ENV_VAR_HOST_NETCONF_SSH_BASE_PORT), 0);
212     framework_environment.host.tls_base_port = get_int_from_string_with_default(getenv(ENV_VAR_HOST_NETCONF_TLS_BASE_PORT), 0);
213     framework_environment.host.ftp_base_port = get_int_from_string_with_default(getenv(ENV_VAR_HOST_TRANSFER_FTP_BASE_PORT), 0);
214     framework_environment.host.sftp_base_port = get_int_from_string_with_default(getenv(ENV_VAR_HOST_TRANSFER_SFTP_BASE_PORT), 0);
215     
216     framework_environment.sdn_controller.protocol = getenv(ENV_VAR_SDN_CONTROLLER_IP) ? strdup(getenv(ENV_VAR_SDN_CONTROLLER_PROTOCOL)) : strdup("https");
217     framework_environment.sdn_controller.ip = getenv(ENV_VAR_SDN_CONTROLLER_IP) ? strdup(getenv(ENV_VAR_SDN_CONTROLLER_IP)) : strdup("127.0.0.1");
218     framework_environment.sdn_controller.port = get_int_from_string_with_default(getenv(ENV_VAR_SDN_CONTROLLER_PORT), 8181);
219     framework_environment.sdn_controller.callhome_port = get_int_from_string_with_default(getenv(ENV_VAR_SDN_CONTROLLER_CALLHOME_PORT), 6666);
220     framework_environment.sdn_controller.username = getenv(ENV_VAR_SDN_CONTROLLER_USERNAME) ? strdup(getenv(ENV_VAR_SDN_CONTROLLER_USERNAME)) : strdup("admin");
221     framework_environment.sdn_controller.password = getenv(ENV_VAR_SDN_CONTROLLER_PASSWORD) ? strdup(getenv(ENV_VAR_SDN_CONTROLLER_PASSWORD)) : strdup("admin");
222
223     framework_environment.ves_endpoint.common_header_version = getenv(ENV_VAR_VES_COMMON_HEADER_VERSION) ? strdup(getenv(ENV_VAR_VES_COMMON_HEADER_VERSION)) : strdup("7.2");
224     framework_environment.ves_endpoint.protocol = getenv(ENV_VAR_VES_ENDPOINT_PROTOCOL) ? strdup(getenv(ENV_VAR_VES_ENDPOINT_PROTOCOL)) : strdup("https");
225     framework_environment.ves_endpoint.ip = getenv(ENV_VAR_VES_ENDPOINT_IP) ? strdup(getenv(ENV_VAR_VES_ENDPOINT_IP)) : strdup("127.0.0.1");
226     framework_environment.ves_endpoint.port = get_int_from_string_with_default(getenv(ENV_VAR_VES_ENDPOINT_PORT), 1234);
227     framework_environment.ves_endpoint.auth_method = getenv(ENV_VAR_VES_ENDPOINT_AUTH_METHOD) ? strdup(getenv(ENV_VAR_VES_ENDPOINT_AUTH_METHOD)) : strdup("no-auth");
228     framework_environment.ves_endpoint.username = getenv(ENV_VAR_VES_ENDPOINT_USERNAME) ? strdup(getenv(ENV_VAR_VES_ENDPOINT_USERNAME)) : strdup("admin");
229     framework_environment.ves_endpoint.password = getenv(ENV_VAR_VES_ENDPOINT_PASSWORD) ? strdup(getenv(ENV_VAR_VES_ENDPOINT_PASSWORD)) : strdup("admin");
230     framework_environment.ves_endpoint.certificate = getenv(ENV_VAR_VES_ENDPOINT_CERTIFICATE) ? strdup(getenv(ENV_VAR_VES_ENDPOINT_CERTIFICATE)) : strdup("");
231
232     log_add_verbose(2, "[framework-env] nts.manual = %d\n", framework_environment.nts.manual);
233     log_add_verbose(2, "[framework-env] nts.version = %s\n", framework_environment.nts.version);
234     log_add_verbose(2, "[framework-env] nts.build_time = %s\n", framework_environment.nts.build_time);
235     log_add_verbose(2, "[framework-env] nts.function_type = %s\n", framework_environment.nts.function_type);
236     log_add_verbose(2, "[framework-env] nts.nf_standalone_start_features = %s\n", framework_environment.nts.nf_standalone_start_features);
237     log_add_verbose(2, "[framework-env] nts.nf_mount_point_addressing_method = %s\n", framework_environment.nts.nf_mount_point_addressing_method);
238
239     log_add_verbose(2, "[framework-env] settings.docker_engine_version = %s\n", framework_environment.settings.docker_engine_version);
240     log_add_verbose(2, "[framework-env] settings.docker_repository = %s\n", framework_environment.settings.docker_repository);
241     log_add_verbose(2, "[framework-env] settings.hostname = %s\n", framework_environment.settings.hostname);
242     log_add_verbose(2, "[framework-env] settings.ip_v4 = %s\n", framework_environment.settings.ip_v4);
243     log_add_verbose(2, "[framework-env] settings.ip_v6 = %s\n", framework_environment.settings.ip_v6);
244     log_add_verbose(2, "[framework-env] settings.ip_v6_enabled = %s\n", framework_environment.settings.ip_v6_enabled ? "true" : "false");
245     log_add_verbose(2, "[framework-env] settings.ssh_connections = %d\n", framework_environment.settings.ssh_connections);
246     log_add_verbose(2, "[framework-env] settings.tls_connections = %d\n", framework_environment.settings.tls_connections);
247     log_add_verbose(2, "[framework-env] settings.ftp_connections = %d\n", framework_environment.settings.ftp_connections);
248     log_add_verbose(2, "[framework-env] settings.sftp_connections = %d\n", framework_environment.settings.sftp_connections);
249
250     //check ports
251     if(framework_environment.host.base_port < 1000) {
252         log_add_verbose(2, "[framework-env] host.base_port < 1000 -> disabling\n");
253         framework_environment.host.base_port = 0;
254     }
255
256     if(framework_environment.host.ssh_base_port < 1000) {
257         log_add_verbose(2, "[framework-env] host.ssh_base_port < 1000 -> using base_port\n");
258         framework_environment.host.ssh_base_port = framework_environment.host.base_port;
259     }
260
261     if(framework_environment.host.tls_base_port < 1000) {
262         log_add_verbose(2, "[framework-env] host.tls_base_port < 1000 -> using base_port\n");
263         framework_environment.host.tls_base_port = framework_environment.host.base_port;
264     }
265
266     if(framework_environment.host.ftp_base_port < 1000) {
267         log_add_verbose(2, "[framework-env] host.ftp_base_port < 1000 -> using base_port\n");
268         framework_environment.host.ftp_base_port = framework_environment.host.base_port;
269     }
270
271     if(framework_environment.host.sftp_base_port < 1000) {
272         log_add_verbose(2, "[framework-env] host.sftp_base_port < 1000 -> using base_port\n");
273         framework_environment.host.sftp_base_port = framework_environment.host.base_port;
274     }
275
276     if(framework_environment.host.base_port == 0) {
277         if(framework_environment.host.ssh_base_port == 0) {
278             log_error("[framework-env] host.ssh_base_port unknown\n");
279             return NTS_ERR_FAILED;
280         }
281
282         if(framework_environment.host.tls_base_port == 0) {
283             log_error("[framework-env] host.tls_base_port unknown\n");
284             return NTS_ERR_FAILED;
285         }
286
287         if(framework_environment.host.ftp_base_port == 0) {
288             log_error("[framework-env] host.ftp_base_port unknown\n");
289             return NTS_ERR_FAILED;
290         }
291
292         if(framework_environment.host.sftp_base_port == 0) {
293             log_error("[framework-env] host.sftp_base_port unknown\n");
294             return NTS_ERR_FAILED;
295         }
296     }
297     
298     log_add_verbose(2, "[framework-env] host.ip = %s\n", framework_environment.host.ip);
299     if(framework_environment.settings.ip_v6_enabled) {
300         if(strstr(framework_environment.host.ip, ".")) {
301             log_error("[framework-env] host.ip is an invalid IP v6\n");
302             return NTS_ERR_FAILED;
303         }
304     }
305     else {
306         if(strstr(framework_environment.host.ip, ":")) {
307             log_error("[framework-env] host.ip is an invalid IP v4\n");
308             return NTS_ERR_FAILED;
309         }
310     }
311
312     log_add_verbose(2, "[framework-env] host.base_port = %d\n", framework_environment.host.base_port);
313     log_add_verbose(2, "[framework-env] host.ssh_base_port = %d\n", framework_environment.host.ssh_base_port);
314     log_add_verbose(2, "[framework-env] host.tls_base_port = %d\n", framework_environment.host.tls_base_port);
315     log_add_verbose(2, "[framework-env] host.ftp_base_port = %d\n", framework_environment.host.ftp_base_port);
316     log_add_verbose(2, "[framework-env] host.sftp_base_port = %d\n", framework_environment.host.sftp_base_port);
317     
318     log_add_verbose(2, "[framework-env] sdn_controller.protocol = %s\n", framework_environment.sdn_controller.protocol);
319     log_add_verbose(2, "[framework-env] sdn_controller.ip = %s\n", framework_environment.sdn_controller.ip);
320     log_add_verbose(2, "[framework-env] sdn_controller.port = %d\n", framework_environment.sdn_controller.port);
321     log_add_verbose(2, "[framework-env] sdn_controller.callhome_port = %d\n", framework_environment.sdn_controller.callhome_port);
322     log_add_verbose(2, "[framework-env] sdn_controller.username = %s\n", framework_environment.sdn_controller.username);
323     log_add_verbose(2, "[framework-env] sdn_controller.password = %s\n", framework_environment.sdn_controller.password);
324
325     log_add_verbose(2, "[framework-env] ves_endpoint.common_header_version = %s\n", framework_environment.ves_endpoint.common_header_version);
326     log_add_verbose(2, "[framework-env] ves_endpoint.protocol = %s\n", framework_environment.ves_endpoint.protocol);
327     log_add_verbose(2, "[framework-env] ves_endpoint.ip = %s\n", framework_environment.ves_endpoint.ip);
328     log_add_verbose(2, "[framework-env] ves_endpoint.port = %d\n", framework_environment.ves_endpoint.port);
329     log_add_verbose(2, "[framework-env] ves_endpoint.auth_method = %s\n", framework_environment.ves_endpoint.auth_method);
330     log_add_verbose(2, "[framework-env] ves_endpoint.username = %s\n", framework_environment.ves_endpoint.username);
331     log_add_verbose(2, "[framework-env] ves_endpoint.password = %s\n", framework_environment.ves_endpoint.password);
332     log_add_verbose(2, "[framework-env] ves_endpoint.certificate = %s\n", framework_environment.ves_endpoint.certificate);
333
334     log_add_verbose(2, "[framework-env] finished\n");
335     return NTS_ERR_OK;
336 }
337
338 static int framework_config_init(void) {
339     log_add_verbose(2, "[framework-config] started\n");
340
341     //init app config
342     framework_config.docker.excluded_modules = 0;
343     framework_config.docker.excluded_modules_count = 0;
344     framework_config.docker.excluded_features = 0;
345     framework_config.docker.excluded_features_count = 0;
346
347     framework_config.supervisor.rules_count = 0;
348     framework_config.supervisor.rules = 0;
349
350     framework_config.datastore_generate.debug_max_string_size = 0;
351     framework_config.datastore_generate.excluded_modules = 0;
352     framework_config.datastore_generate.excluded_modules_count = 0;
353     framework_config.datastore_generate.default_list_instances = 1;
354     framework_config.datastore_generate.custom_list_instances_count = 0;
355     framework_config.datastore_generate.custom_list_instances = 0;
356     framework_config.datastore_generate.restrict_schema_count = 0;
357     framework_config.datastore_generate.restrict_schema = 0;
358
359     framework_config.datastore_populate.random_generation_enabled = 1;
360     framework_config.datastore_populate.preg_operational_count = 0;
361     framework_config.datastore_populate.preg_operational = 0;
362     framework_config.datastore_populate.preg_running_count = 0;
363     framework_config.datastore_populate.preg_running = 0;
364
365     //config init
366     if(!dir_exists("config")) {
367         log_add_verbose(2, "[framework-config] config/ folder wasn't found; created.\n");
368         mkdir("config", 0777);
369     }
370
371     if(!file_exists("config/config.json")) {
372         log_add_verbose(2, "[framework-config] config.json file missing; created.\n");
373         file_touch("config/config.json", "{}");
374     }    
375
376     log_add_verbose(2, "[framework-config] parsing config.json\n");
377     char *config_contents = file_read_content("config/config.json");
378     cJSON *json = cJSON_Parse(config_contents);
379     free(config_contents);
380     if(!json) {
381         log_error("[framework-config] config.json error: %s\n", cJSON_GetErrorPtr());
382     }
383     else {
384         cJSON *main_node;
385         cJSON *node;
386
387         if(framework_arguments.nts_mode == NTS_MODE_CONTAINER_INIT) {
388             main_node = cJSON_GetObjectItem(json, "container-rules");
389             if(main_node) {
390                 node = cJSON_GetObjectItem(main_node, "excluded-modules");
391                 if(node) {
392                     if(cJSON_IsArray(node)) {
393                         cJSON *element;
394                         cJSON_ArrayForEach(element, node) {
395                             if(cJSON_IsString(element)) {
396                                 log_add_verbose(2, "[framework-config] adding container-rules/exclude-modules: %s\n", element->valuestring);
397                                 framework_config.docker.excluded_modules = (char **)realloc(framework_config.docker.excluded_modules, sizeof(char*) * (framework_config.docker.excluded_modules_count + 1));
398                                 if(!framework_config.docker.excluded_modules) {
399                                     log_error("[framework-config] bad realloc\n");
400                                 }
401                                 framework_config.docker.excluded_modules[framework_config.docker.excluded_modules_count] = (char *)malloc(sizeof(char) * (strlen(element->valuestring) + 1));
402                                 if(!framework_config.docker.excluded_modules[framework_config.docker.excluded_modules_count]) {
403                                     log_error("[framework-config] bad malloc\n");
404                                 }
405                                 strcpy(framework_config.docker.excluded_modules[framework_config.docker.excluded_modules_count], element->valuestring);
406                                 framework_config.docker.excluded_modules_count++;
407                             }
408                         }
409                     }
410                 }
411
412                 node = cJSON_GetObjectItem(main_node, "excluded-features");
413                 if(node) {
414                     if(cJSON_IsArray(node)) {
415                         cJSON *element;
416                         cJSON_ArrayForEach(element, node) {
417                             if(cJSON_IsString(element)) {
418                                 log_add_verbose(2, "[framework-config] adding container-rules/excluded-features: %s\n", element->valuestring);
419                                 framework_config.docker.excluded_features = (char **)realloc(framework_config.docker.excluded_features, sizeof(char*) * (framework_config.docker.excluded_features_count + 1));
420                                 if(!framework_config.docker.excluded_features) {
421                                     log_error("[framework-config] bad realloc\n");
422                                 }
423                                 framework_config.docker.excluded_features[framework_config.docker.excluded_features_count] = (char *)malloc(sizeof(char) * (strlen(element->valuestring) + 1));
424                                 if(!framework_config.docker.excluded_features[framework_config.docker.excluded_features_count]) {
425                                     log_error("[framework-config] bad malloc\n");
426                                 }
427                                 strcpy(framework_config.docker.excluded_features[framework_config.docker.excluded_features_count], element->valuestring);
428                                 framework_config.docker.excluded_features_count++;
429                             }
430                         }
431                     }
432                 }
433             }
434         }
435         else if(framework_arguments.nts_mode == NTS_MODE_SUPERVISOR) {
436             main_node = cJSON_GetObjectItem(json, "supervisor-rules");
437             if(main_node) {
438                 cJSON *app;
439                 cJSON_ArrayForEach(app, main_node) {
440                     if(cJSON_IsObject(app)) {
441                         cJSON *object = cJSON_GetObjectItem(app, "path");
442                         if(object) {
443                             framework_config.supervisor.rules = (supervisor_rules_t *)realloc(framework_config.supervisor.rules, sizeof(supervisor_rules_t) * (framework_config.supervisor.rules_count + 1));
444                             if(!framework_config.supervisor.rules) {
445                                 log_error("[framework-config] bad realloc\n");
446                             }
447                             
448                             char *path = strdup(object->valuestring);
449                             bool autorestart = false;
450                             bool nomanual = false;
451                             char *stdout_path = 0;
452                             char *stderr_path = 0;
453
454                             int args_count = 0;
455                             char **args = 0;
456                             cJSON *args_json = cJSON_GetObjectItem(app, "args");
457                             if(args_json) {
458                                 args_count = cJSON_GetArraySize(args_json);
459                                 if(args_count) {
460                                     args = malloc(sizeof(char *) * args_count);
461                                     int i = 0;
462                                     cJSON *arg;
463                                     cJSON_ArrayForEach(arg, args_json) {
464                                         args[i] = strdup(arg->valuestring);
465                                         i++;
466                                     }
467                                 }
468                             }
469
470                             object = cJSON_GetObjectItem(app, "autorestart");
471                             if(object) {
472                                 autorestart = object->valueint;
473                             }
474
475                             object = cJSON_GetObjectItem(app, "nomanual");
476                             if(object) {
477                                 nomanual = object->valueint;
478                             }
479
480                             object = cJSON_GetObjectItem(app, "stdout");
481                             if(object) {
482                                 stdout_path = strdup(object->valuestring);
483                             }
484
485                             object = cJSON_GetObjectItem(app, "stderr");
486                             if(object) {
487                                 stderr_path = strdup(object->valuestring);
488                             }
489
490                             framework_config.supervisor.rules[framework_config.supervisor.rules_count].name = strdup(app->string);
491                             framework_config.supervisor.rules[framework_config.supervisor.rules_count].path = path;
492                             framework_config.supervisor.rules[framework_config.supervisor.rules_count].args = args;
493                             framework_config.supervisor.rules[framework_config.supervisor.rules_count].args_count = args_count;
494                             framework_config.supervisor.rules[framework_config.supervisor.rules_count].autorestart = autorestart;
495                             framework_config.supervisor.rules[framework_config.supervisor.rules_count].nomanual = nomanual;
496                             framework_config.supervisor.rules[framework_config.supervisor.rules_count].stdout_path = stdout_path;
497                             framework_config.supervisor.rules[framework_config.supervisor.rules_count].stderr_path = stderr_path;
498
499                             log_add_verbose(2, "[framework-config] adding supervisor command: %s with autorestart: %d\n", path, autorestart);
500                             framework_config.supervisor.rules_count++;
501                         }
502                     }
503                 }
504             }
505         }
506         else {
507             main_node = cJSON_GetObjectItem(json, "datastore-random-generation-rules");
508             if(main_node) {
509                 node = cJSON_GetObjectItem(main_node, "excluded-modules");
510                 if(node) {
511                     if(cJSON_IsArray(node)) {
512                         cJSON *element;
513                         cJSON_ArrayForEach(element, node) {
514                             if(cJSON_IsString(element)) {
515                                 log_add_verbose(2, "[framework-config] adding datastore-random-generation-rules/excluded-modules: %s\n", element->valuestring);
516                                 framework_config.datastore_generate.excluded_modules = (char **)realloc(framework_config.datastore_generate.excluded_modules, sizeof(char*) * (framework_config.datastore_generate.excluded_modules_count + 1));
517                                 if(!framework_config.datastore_generate.excluded_modules) {
518                                     log_error("[framework-config] bad realloc\n");
519                                 }
520                                 framework_config.datastore_generate.excluded_modules[framework_config.datastore_generate.excluded_modules_count] = (char *)malloc(sizeof(char) * (strlen(element->valuestring) + 1));
521                                 if(!framework_config.datastore_generate.excluded_modules[framework_config.datastore_generate.excluded_modules_count]) {
522                                     log_error("[framework-config] bad malloc\n");
523                                 }
524                                 strcpy(framework_config.datastore_generate.excluded_modules[framework_config.datastore_generate.excluded_modules_count], element->valuestring);
525                                 framework_config.datastore_generate.excluded_modules_count++;
526                             }
527                         }
528                     }
529                 }
530
531                 node = cJSON_GetObjectItem(main_node, "debug-max-string-size");
532                 if(node) {
533                     framework_config.datastore_generate.debug_max_string_size = node->valueint;
534                     log_add_verbose(2, "[framework-config] setting datastore-random-generation-rules/debug-max-string-size: %d\n", framework_config.datastore_generate.debug_max_string_size);
535                 }
536
537                 node = cJSON_GetObjectItem(main_node, "default-list-instances");
538                 if(node) {
539                     if(cJSON_IsNumber(node)) {
540                         framework_config.datastore_generate.default_list_instances = node->valueint;
541                         log_add_verbose(2, "[framework-config] setting datastore-random-generation-rules/default-list-instances: %d\n", framework_config.datastore_generate.default_list_instances);
542                     }
543                 }
544
545                 node = cJSON_GetObjectItem(main_node, "custom-list-instances");
546                 if(node) {
547                     if(cJSON_IsArray(node)) {
548                         cJSON *element;
549                         cJSON_ArrayForEach(element, node) {
550                             if(cJSON_IsObject(element)) {
551                                 cJSON *object;
552                                 cJSON_ArrayForEach(object, element) {
553                                     char *path = object->string;
554                                     int count = object->valueint;
555                                     log_add_verbose(2, "[framework-config] adding datastore-random-generation-rules/custom-list-instances %s - %d\n", path, count);
556                                     framework_config.datastore_generate.custom_list_instances = (custom_list_instances_t *)realloc(framework_config.datastore_generate.custom_list_instances, sizeof(custom_list_instances_t) * (framework_config.datastore_generate.custom_list_instances_count + 1));
557                                     if(!framework_config.datastore_generate.custom_list_instances) {
558                                         log_error("[framework-config] bad realloc\n");
559                                     }
560                                     
561                                     framework_config.datastore_generate.custom_list_instances[framework_config.datastore_generate.custom_list_instances_count].path = (char *)malloc(sizeof(char) * (strlen(path) + 1));
562                                     if(!framework_config.datastore_generate.custom_list_instances[framework_config.datastore_generate.custom_list_instances_count].path) {
563                                         log_error("[framework-config] bad malloc\n");
564                                     }
565                                     strcpy(framework_config.datastore_generate.custom_list_instances[framework_config.datastore_generate.custom_list_instances_count].path, path);
566                                     framework_config.datastore_generate.custom_list_instances[framework_config.datastore_generate.custom_list_instances_count].count = count;
567                                     framework_config.datastore_generate.custom_list_instances_count++;
568                                 }
569                             }
570                         }
571                     }
572                 }
573
574                 node = cJSON_GetObjectItem(main_node, "restrict-schema");
575                 if(node) {
576                     if(cJSON_IsArray(node)) {
577                         cJSON *element;
578                         cJSON_ArrayForEach(element, node) {
579                             if(cJSON_IsObject(element)) {
580                                 cJSON *object;
581                                 cJSON_ArrayForEach(object, element) {
582                                     char *path = object->string;
583
584                                     log_add_verbose(2, "[framework-config] adding datastore-random-generation-rules/restrict-schema: %s with values:", path);
585                                     framework_config.datastore_generate.restrict_schema = (restrict_schema_t *)realloc(framework_config.datastore_generate.restrict_schema, sizeof(restrict_schema_t) * (framework_config.datastore_generate.restrict_schema_count + 1));
586                                     if(!framework_config.datastore_generate.restrict_schema) {
587                                         log_error("[framework-config] bad realloc\n");
588                                     }
589                                     
590                                     framework_config.datastore_generate.restrict_schema[framework_config.datastore_generate.restrict_schema_count].path = (char *)malloc(sizeof(char) * (strlen(path) + 1));
591                                     if(!framework_config.datastore_generate.restrict_schema[framework_config.datastore_generate.restrict_schema_count].path) {
592                                         log_error("[framework-config] bad malloc\n");
593                                     }
594                                     strcpy(framework_config.datastore_generate.restrict_schema[framework_config.datastore_generate.restrict_schema_count].path, path);
595
596
597                                     framework_config.datastore_generate.restrict_schema[framework_config.datastore_generate.restrict_schema_count].values_count = 0;
598                                     framework_config.datastore_generate.restrict_schema[framework_config.datastore_generate.restrict_schema_count].values = 0;
599                                     framework_config.datastore_generate.restrict_schema[framework_config.datastore_generate.restrict_schema_count].index = 0;
600                                     cJSON *value;
601                                     cJSON_ArrayForEach(value, object) {
602                                         if(cJSON_IsString(value)) {
603                                             framework_config.datastore_generate.restrict_schema[framework_config.datastore_generate.restrict_schema_count].values = (char **)realloc(framework_config.datastore_generate.restrict_schema[framework_config.datastore_generate.restrict_schema_count].values, sizeof(char*) * (framework_config.datastore_generate.restrict_schema[framework_config.datastore_generate.restrict_schema_count].values_count + 1));
604                                             if(!framework_config.datastore_generate.restrict_schema[framework_config.datastore_generate.restrict_schema_count].values) {
605                                                 log_error("[framework-config] bad realloc\n");
606                                             }
607                                             framework_config.datastore_generate.restrict_schema[framework_config.datastore_generate.restrict_schema_count].values[framework_config.datastore_generate.restrict_schema[framework_config.datastore_generate.restrict_schema_count].values_count] = (char *)malloc(sizeof(char) * (strlen(value->valuestring) + 1));
608                                             if(!framework_config.datastore_generate.restrict_schema[framework_config.datastore_generate.restrict_schema_count].values[framework_config.datastore_generate.restrict_schema[framework_config.datastore_generate.restrict_schema_count].values_count]) {
609                                                 log_error("[framework-config] bad malloc\n");
610                                             }
611                                             strcpy(framework_config.datastore_generate.restrict_schema[framework_config.datastore_generate.restrict_schema_count].values[framework_config.datastore_generate.restrict_schema[framework_config.datastore_generate.restrict_schema_count].values_count], value->valuestring);
612                                             framework_config.datastore_generate.restrict_schema[framework_config.datastore_generate.restrict_schema_count].values_count++;
613
614                                             log_add(2, " %s", value->valuestring);
615                                         }
616                                     }
617                                     log_add(2, "\n");
618
619                                     framework_config.datastore_generate.restrict_schema_count++;
620                                 }
621                             }
622                         }
623                     }
624                 }
625             }
626
627             main_node = cJSON_GetObjectItem(json, "datastore-populate-rules");
628             if(main_node) {
629                 node = cJSON_GetObjectItem(main_node, "random-generation-enabled");
630                 if(node) {
631                     framework_config.datastore_populate.random_generation_enabled = node->valueint;
632                     log_add_verbose(2, "[framework-config] setting datastore-populate-rules/random-generation-enabled: %d\n", framework_config.datastore_populate.random_generation_enabled);
633                 }
634                 else {
635                     log_add_verbose(2, "[framework-config] setting datastore-populate-rules/random-generation-enabled: %d [default value]\n", framework_config.datastore_populate.random_generation_enabled);
636                 }
637                 
638                 node = cJSON_GetObjectItem(main_node, "pre-generated-operational-data");
639                 if(node) {
640                     if(cJSON_IsArray(node)) {
641                         cJSON *element;
642                         cJSON_ArrayForEach(element, node) {
643                             if(cJSON_IsString(element)) {
644                                 log_add_verbose(2, "[framework-config] adding datastore-populate-rules/pre-generated-operational-data: %s\n", element->valuestring);
645                                 framework_config.datastore_populate.preg_operational = (char **)realloc(framework_config.datastore_populate.preg_operational, sizeof(char*) * (framework_config.datastore_populate.preg_operational_count + 1));
646                                 if(!framework_config.datastore_populate.preg_operational) {
647                                     log_error("[framework-config] bad realloc\n");
648                                 }
649                                 framework_config.datastore_populate.preg_operational[framework_config.datastore_populate.preg_operational_count] = (char *)malloc(sizeof(char) * (strlen(element->valuestring) + 1));
650                                 if(!framework_config.datastore_populate.preg_operational[framework_config.datastore_populate.preg_operational_count]) {
651                                     log_error("[framework-config] bad malloc\n");
652                                 }
653                                 strcpy(framework_config.datastore_populate.preg_operational[framework_config.datastore_populate.preg_operational_count], element->valuestring);
654                                 framework_config.datastore_populate.preg_operational_count++;
655                             }
656                         }
657                     }
658                 }
659
660                 node = cJSON_GetObjectItem(main_node, "pre-generated-running-data");
661                 if(node) {
662                     if(cJSON_IsArray(node)) {
663                         cJSON *element;
664                         cJSON_ArrayForEach(element, node) {
665                             if(cJSON_IsString(element)) {
666                                 log_add_verbose(2, "[framework-config] adding datastore-populate-rules/pre-generated-running-data: %s\n", element->valuestring);
667                                 framework_config.datastore_populate.preg_running = (char **)realloc(framework_config.datastore_populate.preg_running, sizeof(char*) * (framework_config.datastore_populate.preg_running_count + 1));
668                                 if(!framework_config.datastore_populate.preg_running) {
669                                     log_error("[framework-config] bad realloc\n");
670                                 }
671                                 framework_config.datastore_populate.preg_running[framework_config.datastore_populate.preg_running_count] = (char *)malloc(sizeof(char) * (strlen(element->valuestring) + 1));
672                                 if(!framework_config.datastore_populate.preg_running[framework_config.datastore_populate.preg_running_count]) {
673                                     log_error("[framework-config] bad malloc\n");
674                                 }
675                                 strcpy(framework_config.datastore_populate.preg_running[framework_config.datastore_populate.preg_running_count], element->valuestring);
676                                 framework_config.datastore_populate.preg_running_count++;
677                             }
678                         }
679                     }
680                 }
681
682             }
683         }
684
685         cJSON_Delete(json);
686         
687     }
688     log_add_verbose(2, "[framework-config] finished parsing config.json\n");
689
690     return NTS_ERR_OK;
691 }
692
693 void framework_free(void) {
694     log_add_verbose(2, "[framework-config] framework_free()... ");
695
696     signal(SIGINT, 0);
697     signal(SIGTERM, 0);
698     signal(SIGQUIT, 0);
699
700     free((char *)argp_program_version);
701     argp_program_version = 0;
702
703     free(framework_environment.nts.version);
704     free(framework_environment.nts.build_time);
705     free(framework_environment.nts.function_type);
706     free(framework_environment.nts.nf_standalone_start_features);
707     free(framework_environment.nts.nf_mount_point_addressing_method);
708     free(framework_environment.settings.ip_v4);
709     free(framework_environment.settings.ip_v6);
710     free(framework_environment.settings.docker_engine_version);
711     free(framework_environment.settings.docker_repository);
712     free(framework_environment.settings.hostname);
713     free(framework_environment.host.ip);
714     free(framework_environment.sdn_controller.protocol);
715     free(framework_environment.sdn_controller.ip);
716     free(framework_environment.sdn_controller.username);
717     free(framework_environment.sdn_controller.password);
718     free(framework_environment.ves_endpoint.common_header_version);
719     free(framework_environment.ves_endpoint.protocol);
720     free(framework_environment.ves_endpoint.ip);
721     free(framework_environment.ves_endpoint.auth_method);
722     free(framework_environment.ves_endpoint.username);
723     free(framework_environment.ves_endpoint.password);
724     free(framework_environment.ves_endpoint.certificate);
725
726     free(framework_arguments.print_structure_xpath);
727     framework_arguments.print_structure_xpath = 0;
728
729     for(int i = 0; i < framework_config.supervisor.rules_count; i++) {
730         free(framework_config.supervisor.rules[i].name);
731         free(framework_config.supervisor.rules[i].path);
732         for(int j = 0; j < framework_config.supervisor.rules[i].args_count; j++) {
733             free(framework_config.supervisor.rules[i].args[j]);
734         }
735         free(framework_config.supervisor.rules[i].args);
736         free(framework_config.supervisor.rules[i].stdout_path);
737         free(framework_config.supervisor.rules[i].stderr_path);
738     }
739
740     free(framework_config.supervisor.rules);
741
742     for(int i = 0; i < framework_config.docker.excluded_modules_count; i++) {
743         free(framework_config.docker.excluded_modules[i]);
744     }
745     free(framework_config.docker.excluded_modules);
746
747     for(int i = 0; i < framework_config.docker.excluded_features_count; i++) {
748         free(framework_config.docker.excluded_features[i]);
749     }
750     free(framework_config.docker.excluded_features);
751     
752     for(int i = 0; i < framework_config.datastore_generate.excluded_modules_count; i++) {
753         free(framework_config.datastore_generate.excluded_modules[i]);
754     }
755     free(framework_config.datastore_generate.excluded_modules);
756
757
758     for(int i = 0; i < framework_config.datastore_generate.custom_list_instances_count; i++) {
759         free(framework_config.datastore_generate.custom_list_instances[i].path);
760         
761     }
762     free(framework_config.datastore_generate.custom_list_instances);
763
764     for(int i = 0; i < framework_config.datastore_generate.restrict_schema_count; i++) {
765         free(framework_config.datastore_generate.restrict_schema[i].path);
766         for(int j = 0; j < framework_config.datastore_generate.restrict_schema[i].values_count; j++) {
767             free(framework_config.datastore_generate.restrict_schema[i].values[j]);
768         }
769         free(framework_config.datastore_generate.restrict_schema[i].values);
770     }
771     free(framework_config.datastore_generate.restrict_schema);
772
773     for(int i = 0; i < framework_config.datastore_populate.preg_operational_count; i++) {
774         free(framework_config.datastore_populate.preg_operational[i]);
775     }
776     free(framework_config.datastore_populate.preg_operational);
777
778     for(int i = 0; i < framework_config.datastore_populate.preg_running_count; i++) {
779         free(framework_config.datastore_populate.preg_running[i]);
780     }
781     free(framework_config.datastore_populate.preg_running);
782
783
784     log_add(2, "done\n");
785     log_close();
786 }
787
788 static void framework_signal_handler(int signo) {
789     framework_sigint = 1;
790 }
791
792 static error_t parse_opt(int key, char *arg, struct argp_state *state) {
793     framework_arguments_t *iter_arguments = state->input;
794     switch (key) {
795         case 'i':
796             iter_arguments->nts_mode = NTS_MODE_CONTAINER_INIT;
797             break;
798
799         case 's':
800             iter_arguments->nts_mode = NTS_MODE_SUPERVISOR;
801             break;
802
803         case 'm':
804             iter_arguments->nts_mode = NTS_MODE_MANAGER;
805             break;
806
807         case 'f':
808             iter_arguments->nts_mode = NTS_MODE_NETWORK_FUNCTION;
809             break;
810
811         case 'g':
812             iter_arguments->nts_mode = NTS_MODE_GENERATE_DATA;
813             break;
814
815         case 't':
816             iter_arguments->nts_mode = NTS_MODE_TEST;
817             break;
818
819         case 'r':
820             iter_arguments->no_rand = true;
821             framework_arguments.fixed_seed = 0;
822             int i = 0;
823             while(arg[i]) {
824                 framework_arguments.fixed_seed *= 10;
825                 framework_arguments.fixed_seed += arg[i] - '0';
826                 i++;
827             }
828             break;
829
830         case 'v':
831             iter_arguments->verbosity_level = arg[0] - '0';
832             break;
833
834         case 'w':
835             chdir(arg);
836             break;
837
838         case '1':
839             iter_arguments->print_root_paths = true;
840             break;
841
842         case '2':
843             iter_arguments->print_structure_xpath = (char *)malloc(sizeof(char) * (strlen(arg) + 1));
844             if(!iter_arguments->print_structure_xpath) {
845                 log_error("[framework-arg] bad malloc\n");
846                 return 1;
847             }
848             strcpy(iter_arguments->print_structure_xpath, arg);
849             if(arg[strlen(arg) - 1] == '/') {
850                 iter_arguments->print_structure_xpath[strlen(arg) - 1] = 0;
851             }
852             break;
853
854         case ARGP_KEY_ARG:
855             if (state->arg_num >= 2) {
856                 argp_usage(state);
857             }
858             break;
859
860         case ARGP_KEY_END:
861
862             break;
863
864         default:
865             return ARGP_ERR_UNKNOWN;
866     }
867     
868     return 0;
869 }