From eeed6a19e9e9c308162237383d5d33a21eae6492 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sat, 9 Jul 2022 17:33:21 -0500 Subject: [PATCH] Feature: The controller program should expose the "define" and "parameter" at the Entry and Exit level. The "define" and "parameter" should be made available in the Entry and Exit files. This allows for passing data to all Rules. Update documentation. --- level_3/controller/c/common/private-entry.h | 7 + level_3/controller/c/common/private-setting.c | 6 + level_3/controller/c/entry/private-entry.c | 49 +++++++ level_3/controller/c/entry/private-entry.h | 22 +++ level_3/controller/c/rule/private-rule.c | 189 ++++++++++++++++++++++---- level_3/controller/documents/entry.txt | 117 +++++++++------- level_3/controller/documents/exit.txt | 65 +++++---- level_3/controller/documents/rule.txt | 22 +-- level_3/controller/specifications/entry.txt | 12 +- 9 files changed, 373 insertions(+), 116 deletions(-) diff --git a/level_3/controller/c/common/private-entry.h b/level_3/controller/c/common/private-entry.h index 5f5068c..a5dde65 100644 --- a/level_3/controller/c/common/private-entry.h +++ b/level_3/controller/c/common/private-entry.h @@ -174,6 +174,8 @@ extern "C" { * timeout_kill: The timeout to wait relating to using a kill signal. * timeout_start: The timeout to wait relating to starting a process. * timeout_stop: The timeout to wait relating to stopping a process. + * define: Any defines (environment variables) made available to all Rules in this entry for IKI substitution or just as environment variables. + * parameter: Any parameters made available to all Rules in this entry for IKI substitution. * items: The array of entry items. */ #ifndef _di_controller_entry_t_ @@ -205,6 +207,9 @@ extern "C" { f_number_unsigned_t timeout_start; f_number_unsigned_t timeout_stop; + f_string_maps_t define; + f_string_maps_t parameter; + controller_entry_items_t items; } controller_entry_t; @@ -216,6 +221,8 @@ extern "C" { 0, \ 0, \ 0, \ + f_string_maps_t_initialize, \ + f_string_maps_t_initialize, \ controller_entry_items_t_initialize, \ } #endif // _di_controller_entry_t_ diff --git a/level_3/controller/c/common/private-setting.c b/level_3/controller/c/common/private-setting.c index 71723de..f703980 100644 --- a/level_3/controller/c/common/private-setting.c +++ b/level_3/controller/c/common/private-setting.c @@ -18,6 +18,12 @@ extern "C" { controller_control_delete_simple(&setting->control); + f_string_maps_resize(0, &setting->entry.define); + f_string_maps_resize(0, &setting->entry.parameter); + + f_string_maps_resize(0, &setting->exit.define); + f_string_maps_resize(0, &setting->exit.parameter); + controller_entry_items_delete_simple(&setting->entry.items); controller_entry_items_delete_simple(&setting->exit.items); diff --git a/level_3/controller/c/entry/private-entry.c b/level_3/controller/c/entry/private-entry.c index 507c10f..c8f2d70 100644 --- a/level_3/controller/c/entry/private-entry.c +++ b/level_3/controller/c/entry/private-entry.c @@ -2035,6 +2035,21 @@ extern "C" { global.setting->control.user = number; global.setting->control.flag |= controller_control_flag_has_user_e; } + else if (fl_string_dynamic_compare(controller_define_s, cache->action.name_action) == F_equal_to) { + if (cache->content_actions.array[i].used != 2) { + controller_entry_settings_read_print_setting_requires_exactly(global, is_entry, *cache, 1); + + continue; + } + + status = controller_entry_settings_read_map(cache->buffer_file, cache->content_actions.array[i], &entry->define); + + if (F_status_is_error(status)) { + controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "controller_entry_settings_read_map", F_true, global.thread); + + continue; + } + } else if (is_entry && fl_string_dynamic_compare(controller_mode_s, cache->action.name_action) == F_equal_to) { if (cache->content_actions.array[i].used != 1) { controller_entry_settings_read_print_setting_requires_exactly(global, is_entry, *cache, 1); @@ -2054,6 +2069,21 @@ extern "C" { continue; } } + else if (fl_string_dynamic_compare(controller_parameter_s, cache->action.name_action) == F_equal_to) { + if (cache->content_actions.array[i].used != 2) { + controller_entry_settings_read_print_setting_requires_exactly(global, is_entry, *cache, 1); + + continue; + } + + status = controller_entry_settings_read_map(cache->buffer_file, cache->content_actions.array[i], &entry->parameter); + + if (F_status_is_error(status)) { + controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "controller_entry_settings_read_map", F_true, global.thread); + + continue; + } + } else if (fl_string_dynamic_compare(controller_pid_s, cache->action.name_action) == F_equal_to) { if (cache->content_actions.array[i].used != 1) { controller_entry_settings_read_print_setting_requires_exactly(global, is_entry, *cache, 1); @@ -2159,6 +2189,25 @@ extern "C" { } #endif // _di_controller_entry_settings_read_ +#ifndef _di_controller_entry_settings_read_map_ + f_status_t controller_entry_settings_read_map(const f_string_static_t buffer, const f_string_ranges_t ranges, f_string_maps_t *setting_maps) { + + f_status_t status = f_string_maps_increase(controller_common_allocation_small_d, setting_maps); + if (F_status_is_error(status)) return status; + + setting_maps->array[setting_maps->used].name.used = 0; + setting_maps->array[setting_maps->used].value.used = 0; + + status = f_string_dynamic_partial_append_nulless(buffer, ranges.array[0], &setting_maps->array[setting_maps->used].name); + if (F_status_is_error(status)) return status; + + status = f_string_dynamic_partial_append_nulless(buffer, ranges.array[1], &setting_maps->array[setting_maps->used].value); + if (F_status_is_error(status)) return status; + + ++setting_maps->used; + } +#endif // _di_controller_entry_settings_read_map_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_3/controller/c/entry/private-entry.h b/level_3/controller/c/entry/private-entry.h index 603c7d1..73576ca 100644 --- a/level_3/controller/c/entry/private-entry.h +++ b/level_3/controller/c/entry/private-entry.h @@ -212,6 +212,28 @@ extern "C" { extern f_status_t controller_entry_settings_read(const controller_global_t global, const bool is_entry, const f_string_range_t content_range, controller_cache_t * const cache) F_attribute_visibility_internal_d; #endif // _di_controller_entry_settings_read_ +/** + * Load the given ranges within the buffer into the provided map. + * + * @param buffer + * The buffer the ranges are associated with. + * @param ranges + * The ranges to load from the buffer. + * This expects the caller to already ensure the ranges.used = 2. + * @param setting_maps + * The map to load the settings into. + * + * @return + * Errors (with error bit) from: f_string_dynamic_partial_append_nulless(). + * Errors (with error bit) from: f_string_maps_increase(). + * + * @see f_string_dynamic_partial_append_nulless() + * @see f_string_maps_increase() + */ +#ifndef _di_controller_entry_settings_read_map_ + f_status_t controller_entry_settings_read_map(const f_string_static_t buffer, const f_string_ranges_t ranges, f_string_maps_t *setting_maps) F_attribute_visibility_internal_d; +#endif // _di_controller_entry_settings_read_map_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_3/controller/c/rule/private-rule.c b/level_3/controller/c/rule/private-rule.c index 65b7adf..d2ebfe8 100644 --- a/level_3/controller/c/rule/private-rule.c +++ b/level_3/controller/c/rule/private-rule.c @@ -969,7 +969,7 @@ extern "C" { const f_string_dynamics_t arguments_none = f_string_dynamics_t_initialize; - controller_execute_set_t execute_set = macro_controller_execute_set_t_initialize(0, 0, process->rule.has & controller_rule_has_environment_d ? &environment : 0, &signals, 0, fl_execute_as_t_initialize); + controller_execute_set_t execute_set = macro_controller_execute_set_t_initialize(0, 0, &environment, &signals, 0, fl_execute_as_t_initialize); if (process->rule.affinity.used) { execute_set.as.affinity = &process->rule.affinity; @@ -1018,54 +1018,156 @@ extern "C" { execute_set.as.id_user = &process->rule.user; } - status = fl_environment_load_names(process->rule.environment, &environment); + if (process->rule.has & controller_rule_has_environment_d) { + status = fl_environment_load_names(process->rule.environment, &environment); - if (F_status_is_error(status)) { - controller_print_error(global.thread, global.main->error, F_status_set_fine(status), "fl_environment_load_names", F_true); + if (F_status_is_error(status)) { + controller_print_error(global.thread, global.main->error, F_status_set_fine(status), "fl_environment_load_names", F_true); - return status; - } + return status; + } - // @todo Much of this loop really should be moved into the processing stage where define names that are not in the environment are not loaded (for better performance and resource utilization). - // When a "define" is in the "environment", add it to the exported environments (and overwrite any existing environment variable of the same name). - for (i = 0; i < process->rule.define.used; ++i) { + // When a "define" from the entry/exit is in the "environment", add it to the exported environments (and overwrite any existing environment variable of the same name). + controller_entry_t *entry = 0; - for (j = 0; j < process->rule.environment.used; ++j) { + if (process->type == controller_process_type_entry_e) { + entry = &global.setting->entry; + } + else if (process->type == controller_process_type_exit_e) { + entry = &global.setting->exit; + } - if (fl_string_dynamic_compare(process->rule.define.array[i].name, process->rule.environment.array[j]) == F_equal_to) { + if (entry) { + for (i = 0; i < entry->define.used; ++i) { - for (k = 0; k < environment.used; ++k) { + for (j = 0; j < process->rule.environment.used; ++j) { - if (fl_string_dynamic_compare(process->rule.define.array[i].name, environment.array[k].name) == F_equal_to) { + if (fl_string_dynamic_compare(entry->define.array[i].name, process->rule.environment.array[j]) == F_equal_to) { - environment.array[k].value.used = 0; + for (k = 0; k < environment.used; ++k) { - status = f_string_dynamic_append(process->rule.define.array[i].value, &environment.array[k].value); + if (fl_string_dynamic_compare(entry->define.array[i].name, environment.array[k].name) == F_equal_to) { - if (F_status_is_error(status)) { - controller_print_error(global.thread, global.main->error, F_status_set_fine(status), "f_string_dynamic_append", F_true); + environment.array[k].value.used = 0; - return status; + status = f_string_dynamic_append(entry->define.array[i].value, &environment.array[k].value); + + if (F_status_is_error(status)) { + controller_print_error(global.thread, global.main->error, F_status_set_fine(status), "f_string_dynamic_append", F_true); + + return status; + } + + break; + } + } // for + + if (k == environment.used) { + status = f_string_maps_append(entry->define.array[i], &environment); + + if (F_status_is_error(status)) { + controller_print_error(global.thread, global.main->error, F_status_set_fine(status), "f_string_maps_append", F_true); + + return status; + } } break; } } // for + } // for + } - if (k == environment.used) { - status = f_string_maps_append(process->rule.define.array[i], &environment); + // When a "define" is in the "environment", add it to the exported environments (and overwrite any existing environment variable of the same name). + for (i = 0; i < process->rule.define.used; ++i) { - if (F_status_is_error(status)) { - controller_print_error(global.thread, global.main->error, F_status_set_fine(status), "f_string_maps_append", F_true); + for (j = 0; j < process->rule.environment.used; ++j) { - return status; + if (fl_string_dynamic_compare(process->rule.define.array[i].name, process->rule.environment.array[j]) == F_equal_to) { + + for (k = 0; k < environment.used; ++k) { + + if (fl_string_dynamic_compare(process->rule.define.array[i].name, environment.array[k].name) == F_equal_to) { + + environment.array[k].value.used = 0; + + status = f_string_dynamic_append(process->rule.define.array[i].value, &environment.array[k].value); + + if (F_status_is_error(status)) { + controller_print_error(global.thread, global.main->error, F_status_set_fine(status), "f_string_dynamic_append", F_true); + + return status; + } + + break; + } + } // for + + if (k == environment.used) { + status = f_string_maps_append(process->rule.define.array[i], &environment); + + if (F_status_is_error(status)) { + controller_print_error(global.thread, global.main->error, F_status_set_fine(status), "f_string_maps_append", F_true); + + return status; + } } + + break; } + } // for + } // for + } + else { + controller_entry_t *entry = 0; - break; + if (process->type == controller_process_type_entry_e) { + entry = &global.setting->entry; + } + else if (process->type == controller_process_type_exit_e) { + entry = &global.setting->exit; + } + + // When a custom define is specified, it needs to be exported into the environment. + if (entry->define.used || process->rule.define.used) { + + // Copy all environment variables over when a custom define is used. + status = f_environment_get_all(&environment); + + if (F_status_is_error(status)) { + controller_print_error(global.thread, global.main->error, F_status_set_fine(status), "f_environment_get_all", F_true); + + return status; } - } // for - } // for + + for (i = 0; i < entry->define.used; ++i) { + + status = f_string_maps_append(entry->define.array[i], &environment); + + if (F_status_is_error(status)) { + controller_print_error(global.thread, global.main->error, F_status_set_fine(status), "f_string_maps_append", F_true); + + return status; + } + } // for + + for (i = 0; i < process->rule.define.used; ++i) { + + status = f_string_maps_append(process->rule.define.array[i], &environment); + + if (F_status_is_error(status)) { + controller_print_error(global.thread, global.main->error, F_status_set_fine(status), "f_string_maps_append", F_true); + + return status; + } + } // for + } + else { + + // When no custom environment variables are defined, just let the original environment pass through. + execute_set.parameter.environment = 0; + } + } for (i = 0; i < process->rule.items.used && controller_thread_is_enabled_process(process, global.thread); ++i) { @@ -1941,6 +2043,24 @@ extern "C" { } // for if (i == process->rule.define.used) { + controller_entry_t * const entry = process->type == controller_process_type_entry_e ? &((controller_setting_t *) process->main_setting)->entry : &((controller_setting_t *) process->main_setting)->exit; + + for (i = 0; i < entry->define.used; ++i) { + + if (fl_string_dynamic_partial_compare_string(entry->define.array[i].name.string, source, entry->define.array[i].name.used, content) == F_equal_to) { + status = f_string_dynamic_append(entry->define.array[i].value, destination); + if (F_status_is_error(status)) return status; + + break; + } + } // for + + if (i == entry->define.used) { + i = process->rule.define.used; + } + } + + if (i == process->rule.define.used) { f_string_static_t buffer = f_string_static_t_initialize; buffer.used = (content.stop - content.start) + 1; @@ -1959,8 +2079,9 @@ extern "C" { } } else if (fl_string_dynamic_partial_compare_string(controller_parameter_s.string, source, controller_parameter_s.used, vocabulary) == F_equal_to) { + f_array_length_t i = 0; - for (f_array_length_t i = 0; i < process->rule.parameter.used; ++i) { + for (; i < process->rule.parameter.used; ++i) { if (fl_string_dynamic_partial_compare_string(process->rule.parameter.array[i].name.string, source, process->rule.parameter.array[i].name.used, content) == F_equal_to) { status = f_string_dynamic_append(process->rule.parameter.array[i].value, destination); @@ -1969,6 +2090,20 @@ extern "C" { break; } } // for + + if (i == process->rule.parameter.used) { + controller_entry_t * const entry = process->type == controller_process_type_entry_e ? &((controller_setting_t *) process->main_setting)->entry : &((controller_setting_t *) process->main_setting)->exit; + + for (i = 0; i < entry->parameter.used; ++i) { + + if (fl_string_dynamic_partial_compare_string(entry->parameter.array[i].name.string, source, entry->parameter.array[i].name.used, content) == F_equal_to) { + status = f_string_dynamic_append(entry->parameter.array[i].value, destination); + if (F_status_is_error(status)) return status; + + break; + } + } // for + } } else if (fl_string_dynamic_partial_compare_string(controller_program_s.string, source, controller_program_s.used, vocabulary) == F_equal_to) { f_string_static_t * const argv = ((controller_main_t *) process->main_data)->parameters.arguments.array; diff --git a/level_3/controller/documents/entry.txt b/level_3/controller/documents/entry.txt index 9e3f660..17335fc 100644 --- a/level_3/controller/documents/entry.txt +++ b/level_3/controller/documents/entry.txt @@ -14,9 +14,43 @@ Entry Documentation: Execution of all Items are top-down. - The "setting" item Object\: - Represents settings and is not an "item" that can be executed. + Represents Entry settings and is not an "item" that can be executed. A number of settings are supported, but if this Item Object is not specified, then defaults are used. - The following settings are available: "mode", "pid", "pid_file", "session", and "show". + The following settings are available: "control", "control_group", "control_mode", "control_user", "define", "mode", "parameter", "pid", "pid_file", "session", "show". + + - The "control" setting\: + Represents the path to the socket file in which the Controller uses to communicate over with clients such as a Control program. + A relative path is relative to the Controller PID directory. + An absolute path is treated exactly as the path given. + If no socket setting is specified, then no socket will be made available. + This socket file is only created once "ready" mode is achieved. + + Providing "readonly" after the socket path instructs the Controller program not to create or delete the Socket file because the file system is assumed to be readonly. + The socket file itself must therefore already exist. + This should be possible in the cases of file systems that have pre-created a socket file at the designated path. + When "readonly", the group, mode, and user are also not processed effectively resulting in the "control_group", "control_mode", and "control_user" settings being ignored. + + Future versions might expand this into supporting network addresses in addition to socket files. + + - The "control_group" setting\: + Represents the group name or group ID to assign to the socket file as the group. + + - The "control_mode" setting\: + Represents the file mode assigned to the socket file. + This could either be the string version that might look like "u+rw-x,g+r-wx,o-rwx" or a numeric value like "0750". + + - The "control_user" setting\: + Represents the user name or user ID to assign to the socket file as the owner. + + - The "define" setting\: + Use this to define an environment variable (this overwrites any existing environment variable with this name). + A define is both exported as an environment variable as well as exposed as an IKI variable. + Example IKI variable substitution: for "define PATH /bin:/sbin", the associated IKI variable would look like: define:"PATH". + + All environment variables, including those defined using this, must be in the "environment" list in any given Rule to be exported to the executed process. + Environment variables added here that are not added to the environment are still exposed as an IKI variable. + + This is only expanded within any Rule operated on by this Entry. - The "mode" setting\: Represents the mode in which the Entry is operating in. @@ -33,54 +67,37 @@ Entry Documentation: Does not support the Item Action "execute". This is the default mode. + - The "parameter" setting\: + Use this to define an IKI variable name and value. + These do not conflict with environment variables and are not exposed as environment variables. + Example IKI variable substitution: for "parameter hello world", the associated IKI variable would look like: parameter:"hello". + + This is only expanded within any Rule operated on by this Entry. + - The "pid" setting\: - Represents how the entry pid file is generated or not. + Represents how the Entry PID file is generated or not. The following modes are supported: "disable", "require", and "ready". - For "disable", not pid file representing the entry is created. - For "require", check to see if the PID file exists for an entry at startup and then when "ready" create a pid file, display error on pid file already exists or on failure and then fail. - For "ready", when "ready" create a pid file, display error on failure and then fail (does not check if PID file exists). + For "disable", not PID file representing the Entry is created. + For "require", check to see if the PID file exists for an Entry at startup and then when "ready" create a PID file, display error on PID file already exists or on failure and then fail. + For "ready", when "ready" create a PID file, display error on failure and then fail (does not check if PID file exists). - The "pid_file" setting\: - When "pid" is not disabed this represents the path to the pid file. + When "pid" is not disabed this represents the path to the PID file. If -p or --pid is passed to the controller program, then this value is ignored in favor of the value passed along the command line. - The "session" setting\: Represents the default way in which child processes are executed. This default can be overriden by individual Rules. - For "new", Execute rule processes in a new session setting the process group to the executed process' id (making the executed process a "controlling terminal"). - For "same", Execute rule processes in the same session where the process group is set to the parent process id. + For "new", Execute Rule processes in a new session setting the process group to the executed process' id (making the executed process a "controlling terminal"). + For "same", Execute Rule processes in the same session where the process group is set to the parent process id. - The "show" setting\: - Represents the way entry processing presents information to the screen. - This applies only to the entry and rule processing itself and does not handle the output of programs and scripts being executed by some entry or rule. + Represents the way Entry processing presents information to the screen. + This applies only to the Entry and Rule processing itself and does not handle the output of programs and scripts being executed by some Entry or Rule. The following show options are supported: "normal" and "init". - For "normal", will not report the start or stop of some entry or rule execution but will report any errors or warnings as appropriate. + For "normal", will not report the start or stop of some Entry or Rule execution but will report any errors or warnings as appropriate. For "init", will report when starting programs and may include reporting success and failure status. - - The "control" setting\: - Represents the path to the socket file in which the Controller uses to communicate over with clients such as a Control program. - A relative path is relative to the Controller PID directory. - An absolute path is treated exactly as the path given. - If no socket setting is specified, then no socket will be made available. - This socket file is only created once "ready" mode is achieved. - - Providing "readonly" after the socket path instructs the Controller program not to create or delete the Socket file because the file system is assumed to be readonly. - The socket file itself must therefore already exist. - This should be possible in the cases of file systems that have pre-created a socket file at the designated path. - When "readonly", the group, mode, and user are also not processed effectively resulting in the "control_group", "control_mode", and "control_user" settings being ignored. - - Future versions might expand this into supporting network addresses in addition to socket files. - - - The "control_group" setting\: - Represents the group name or group ID to assign to the socket file as the group. - - - The "control_mode" setting\: - Represents the file mode assigned to the socket file. - This could either be the string version that might look like "u+rw-x,g+r-wx,o-rwx" or a numeric value like "0750". - - - The "control_user" setting\: - Represents the user name or user ID to assign to the socket file as the owner. - - The "item" item Object\: Each "item" supports the following Action Names: "consider", "execute", "failsafe", "freeze", "item", "kill", "pause", "reload", "restart", "ready", "resume", "start", "stop", and "timeout". Of those types, the following are considered a "rule" Action: "freeze", "kill", "pause", "reload", "restart", "resume", "start", "stop", and "thaw". @@ -134,11 +151,11 @@ Entry Documentation: This Item Action will process the "resume" inner Content of the named Rule. - The "ready" Item Action\: - Instructs the controller program when it is safe to perform normal tasks, such as creating the pid file. + Instructs the controller program when it is safe to perform normal tasks, such as creating the PID file. When not specified, the state is always assumed to be ready. For example, the controller program may be used as a full blown "init" replacement and therefore may need to mount the /var/run/ directory. - If the pid file is created at program start, then the /var/run/controller.pid would be written before the /var/run/ directory is ready. - This could be a problem, such as on a read-only file system the pid creation fails and controller bails out on error. + If the PID file is created at program start, then the /var/run/controller.pid would be written before the /var/run/ directory is ready. + This could be a problem, such as on a read-only file system the PID creation fails and controller bails out on error. Adding "ready" essentially specifies a point in time in the Entry in which things are expected to be safe for such basic operations. When the optional "wait" is provided, then "ready" will wait for all currently started asynchronous processes to complete before operating. @@ -161,31 +178,31 @@ Entry Documentation: Each of these may only have a single one exist at a time (one "kill", one "start", one "stop", and one "wait"). Each successive "timeout" Item Action, specific to each Action Name (such as "start"), specified replaces the previously defined "timeout" Action (in a top-down manner). Each of these accepts a single Action Parameter that is a 0 or greater whole number representing the number of MegaTime (MT) (equivalent to milliseconds). - For "kill", this represents the number of MegaTime to wait after stopping some rule and that rule has not yet stopped to forcefully stop the rule (aka kill the rule). - For "start", this represents the number of MegaTime to wait after starting some rule before assuming something went wrong and the rule is returned as failed. - For "stop", this represents the number of MegaTime to wait after stopping some rule before assuming something went wrong and the rule is returned as failed. + For "kill", this represents the number of MegaTime to wait after stopping some Rule and that Rule has not yet stopped to forcefully stop the Rule (aka kill the Rule). + For "start", this represents the number of MegaTime to wait after starting some Rule before assuming something went wrong and the Rule is returned as failed. + For "stop", this represents the number of MegaTime to wait after stopping some Rule before assuming something went wrong and the Rule is returned as failed. A value of 0 disables this (prevents the timeout action). Entry Rule Documentation: There are multiple Entry Actions that are considered "rule" Actions. These are: "freeze", "kill", "pause", "reload", "restart", "resume", "start", "stop", and "thaw". - The "rule" Actions immediately execute a named rule file. - - The first Action Parameter represents the rule directory, which is a relative directory path the rule file is to be found. + The "rule" Actions immediately execute a named Rule file. + - The first Action Parameter represents the Rule directory, which is a relative directory path the Rule file is to be found. - Do not include leading or trailing slashes. - This is relative to the settings rules directory. - - The second Action Parameter represents the basename for the rule file, without the file extension. + - The second Action Parameter represents the base name for the Rule file, without the file extension. - This must not have any directory paths. - The remaining Action Parameters may be specified in any order\: - "asynchronous": Designates that execution will not block (wait). - - "require": Designates that this rule must succeed or trigger execution of failsafe. - - "wait": Designates that this rule will not execute until all other Actions before this (including "asynchronous" ones) finish executing (in a top-down manner). + - "require": Designates that this Rule must succeed or trigger execution of failsafe. + - "wait": Designates that this Rule will not execute until all other Actions before this (including "asynchronous" ones) finish executing (in a top-down manner). - The full path to the "rule" is relative to the settings, such that if the controller rule settings are found in "/etc/controller/rules/", then for a directory called "[directory]" and a rule basename of "[basename]", the resulting path would be: "/etc/controller/rules/[directory]/[basename].rule" + The full path to the "rule" is relative to the settings, such that if the controller Rule settings are found in "/etc/controller/rules/", then for a directory called "[directory]" and a Rule base name of "[base_name]", the resulting path would be: "/etc/controller/rules/[directory]/[base_name].rule" It is important to note that for any given "rule", execution within that "rule" may be internally asynchronous (even if the "rule" is synchronous). For example, a service that is often called a daemon will execute in the background. - Until that execution succeeds and the daemon goes into the background the representing rule will block. - After the daemon goes into the background, then the representing rule will no longer block and be fully executed. + Until that execution succeeds and the daemon goes into the background the representing Rule will block. + After the daemon goes into the background, then the representing Rule will no longer block and be fully executed. diff --git a/level_3/controller/documents/exit.txt b/level_3/controller/documents/exit.txt index 2576796..8d252e5 100644 --- a/level_3/controller/documents/exit.txt +++ b/level_3/controller/documents/exit.txt @@ -9,23 +9,42 @@ Exit Documentation: An Exit file, such as "default.exit", is intended to store a set of rules in which the controller will process on execution. These are used to run some set of commands, such as shutting down a system. + An Exit is a special variation or subset of an Entry. + - The "setting" Item Object\: Represents settings and is not an "item" that can be executed. A number of settings are supported, but if this Item Object is not specified, then defaults are used. The following settings are available: "pid" and "show". + - The "define" setting\: + Use this to define an environment variable (this overwrites any existing environment variable with this name). + A define is both exported as an environment variable as well as exposed as an IKI variable. + Example IKI variable substitution: for "define PATH /bin:/sbin", the associated IKI variable would look like: define:"PATH". + + All environment variables, including those defined using this, must be in the "environment" list in any given Rule to be exported to the executed process. + Environment variables added here that are not added to the environment are still exposed as an IKI variable. + + This is only expanded within any Rule operated on by this Exit. + + - The "parameter" setting\: + Use this to define an IKI variable name and value. + These do not conflict with environment variables and are not exposed as environment variables. + Example IKI variable substitution: for "parameter hello world", the associated IKI variable would look like: parameter:"hello". + + This is only expanded within any Rule operated on by this Exit. + - The "pid" setting\: - Represents how the entry pid file is generated or not. + Represents how the Exit PID file is generated or not. The following modes are supported: "disable", "require", and "ready". - For "disable", not pid file representing the entry is created. - For "require", check to see if the PID file exists for an entry at startup and then when "ready" create a pid file, display error on pid file already exists or on failure and then fail. - For "ready", when "ready" create a pid file, display error on failure and then fail (does not check if PID file exists). + For "disable", not PID file representing the Exit is created. + For "require", check to see if the PID file exists for an Exit at startup and then when "ready" create a PID file, display error on PID file already exists or on failure and then fail. + For "ready", when "ready" create a PID file, display error on failure and then fail (does not check if PID file exists). - The "show" setting\: - Represents the way entry processing presents information to the screen. - This applies only to the entry and rule processing itself and does not handle the output of programs and scripts being executed by some entry or rule. + Represents the way Exit processing presents information to the screen. + This applies only to the Exit and Rule processing itself and does not handle the output of programs and scripts being executed by some Exit or Rule. The following show options are supported: "normal" and "init". - For "normal", will not report the start or stop of some entry or rule execution but will report any errors or warnings as appropriate. + For "normal", will not report the start or stop of some Exit or Rule execution but will report any errors or warnings as appropriate. For "init", will report when starting programs and may include reporting success and failure status. - The "main" Item Object\: @@ -85,12 +104,12 @@ Exit Documentation: This Item Action will process the "resume" inner Content of the named Rule. - The "ready" Action\: - Instructs the controller program when it is safe to perform normal tasks, such as creating the pid file. + Instructs the controller program when it is safe to perform normal tasks, such as creating the PID file. When not specified, the state is always assumed to be ready. For example, the controller program may be used as a full blown "init" replacement and therefore may need to mount the /var/run/ directory. - If the pid file is created at program start, then the /var/run/controller.pid would be written before the /var/run/ directory is ready. - This could be a problem, such as on a read-only file system the pid creation fails and controller bails out on error. - Adding "ready" essentially specifies a point in time in the Entry in which things are expected to be safe for such basic operations. + If the PID file is created at program start, then the /var/run/controller.pid would be written before the /var/run/ directory is ready. + This could be a problem, such as on a read-only file system the PID creation fails and controller bails out on error. + Adding "ready" essentially specifies a point in time in the Exit in which things are expected to be safe for such basic operations. When the optional "wait" is provided, then "ready" will wait for all currently started asynchronous processes to complete before operating. - The "start" Item Action\: @@ -112,32 +131,32 @@ Exit Documentation: Each of these may only have a single one exist at a time (one "start", one "stop", and one "kill"). Each successive "timeout" Item Action, specific to each Action Name (such as "start"), specified replaces the previously defined "timeout" Action (in a top-down manner). Each of these accepts a single Action Parameter that is a 0 or greater whole number representing the number of MegaTime (MT) (equivalent to milliseconds). - For "start", this represents the number of MegaTime to wait after starting some rule before assuming something went wrong and the rule is returned as failed. - For "stop", this represents the number of MegaTime to wait after stopping some rule before assuming something went wrong and the rule is returned as failed. - For "kill", this represents the number of MegaTime to wait after stopping some rule and that rule has not yet stopped to forcefully stop the rule (aka kill the rule). + For "start", this represents the number of MegaTime to wait after starting some Rule before assuming something went wrong and the Rule is returned as failed. + For "stop", this represents the number of MegaTime to wait after stopping some Rule before assuming something went wrong and the Rule is returned as failed. + For "kill", this represents the number of MegaTime to wait after stopping some Rule and that Rule has not yet stopped to forcefully stop the Rule (aka kill the Rule). The timeouts are generally only valid for services such as daemon services. A value of 0 disables this (prevents any action). Exit Rule Documentation: - There are multiple Entry Actions that are considered "rule" Actions. + There are multiple Exit Actions that are considered "rule" Actions. These are: "freeze", "kill", "pause", "reload", "restart", "resume", "start", "stop", and "thaw". - The "rule" Actions immediately execute a named rule file. - - The first Action Parameter represents the rule directory, which is a relative directory path the rule file is to be found. + The "rule" Actions immediately execute a named Rule file. + - The first Action Parameter represents the Rule directory, which is a relative directory path the Rule file is to be found. - Do not include leading or trailing slashes. - This is relative to the settings rules directory. - - The second Action Parameter represents the basename for the rule file, without the file extension. + - The second Action Parameter represents the base name for the Rule file, without the file extension. - This must not have any directory paths. - The remaining Action Parameters may be specified in any order\: - "asynchronous": Designates that execution will not block (wait). - - "require": Designates that this rule must succeed or trigger execution of failsafe. - - "wait": Designates that this rule will not execute until all other Actions before this (including "asynchronous" ones) finish executing (in a top-down manner). + - "require": Designates that this Rule must succeed or trigger execution of failsafe. + - "wait": Designates that this Rule will not execute until all other Actions before this (including "asynchronous" ones) finish executing (in a top-down manner). - The full path to the "rule" is relative to the settings, such that if the controller rule settings are found in "/etc/controller/rules/", then for a directory called "[directory]" and a rule basename of "[basename]", the resulting path would be: "/etc/controller/rules/[directory]/[basename].rule" + The full path to the "rule" is relative to the settings, such that if the controller Rule settings are found in "/etc/controller/rules/", then for a directory called "[directory]" and a Rule base name of "[base_name]", the resulting path would be: "/etc/controller/rules/[directory]/[base_name].rule" It is important to note that for any given "rule", execution within that "rule" may be internally asynchronous (even if the "rule" is synchronous). For example, a service that is often called a daemon will execute in the background. - Until that execution succeeds and the daemon goes into the background the representing rule will block. - After the daemon goes into the background, then the representing rule will no longer block and be fully executed. + Until that execution succeeds and the daemon goes into the background the representing Rule will block. + After the daemon goes into the background, then the representing Rule will no longer block and be fully executed. diff --git a/level_3/controller/documents/rule.txt b/level_3/controller/documents/rule.txt index be2c1b2..60bde60 100644 --- a/level_3/controller/documents/rule.txt +++ b/level_3/controller/documents/rule.txt @@ -29,16 +29,16 @@ Rule Documentation: - "timeout": A set of timeouts to wait for in which to perform a set action or to consider failure. - "user": A single user name or ID to execute as. - - In the case of "capability"\: + - The "capability" setting\: If the user the controller program is run as does not have the desired capabilities already, they cannot be added. This essentially maintains or reduces the capabilities already available. Due to capabilities only being a draft in the POSIX standard, one may expect "capabilities" support may not be available and in such a case this setting will do nothing. If the dependent project (f_capability) does not have libcap support enabled, then capabilities will be unsupported by the compilation of this project. - - In the case of "control"\: + - The "control" setting\: The first argument is either "existing" or "new", where for "existing" the process is run inside the existing control used by the parent and when "new" the process is executed within a new control group namespace entirely. - - In the case of "define"\: + - The "define" setting\: Use this to define an environment variable (this overwrites any existing environment variable with this name). A define is both exported as an environment variable as well as exposed as an IKI variable. Example IKI variable substitution: for "define PATH /bin:/sbin", the associated IKI variable would look like: define:"PATH". @@ -46,21 +46,21 @@ Rule Documentation: All environment variables, including those defined using this, must be in the "environment" list to be exported to the executed process. Environment variables added here that are not added to the environment are still exposed as an IKI variable. - - In the case of "engine"\: + - The "engine" setting\: This engine is used for both "script" and "utility" Rule Types. The program that engine refers to must accept a standard input pipe to be supported. Additional parameters may be passed to the engine. - - In the case of "group" and "user"\: + - The "group" and "user" settings\: Only users and groups that the user the controller program is being run as is allowed to use may be used. - - In the case of "limit"\: + - The "limit" setting\: The first parameter must be one of: "as", "core", "cpu", "data", "fsize", "locks", "memlock", "msgqueue", "nice", "nofile", "nproc", "rss", "rtprio", "rttime", "sigpending", or "stack". The second parameter repesents the soft limit. The third parameter represents the hard limit. This may be specified multiply times, but only once for each type. - - In the case of "on"\: + - The "on" setting\: The first parameter represents the Action the dependency exists under and must be one of: "freeze", "kill", "pause", "reload", "restart", "resume", "start", "stop", or "thaw". The second parameter represents how the dependency is required and must be one of: "need", "want", or "wish". The third parameter is a partial path to the rule file. @@ -73,21 +73,21 @@ Rule Documentation: In the case of "want" and "wish", if the desired rule is either not found or is otherwise disabled, then this will not fail or otherwise block the wanting or wishing rule. - - In the case of "path"\: + - The "path" setting\: When specified, the PATH environment variable is automatically added to the "environment" setting. - - In the case of "parameter"\: + - The "parameter" setting\: Use this to define an IKI variable name and value. These do not conflict with environment variables and are not exposed as environment variables. Example IKI variable substitution: for "parameter hello world", the associated IKI variable would look like: parameter:"hello". - - In the case of "scheduler"\: + - The "scheduler" setting\: The valid range of the priority number is dependent on the scheduler. For example, non-real-time schedulers (such as "idle") only support a value of 0 whereas real-time schedulers (such as "fifo") only support an inclusive range of 1 to 99. Supported non-real-time schedulers are: "batch", "idle", and "other" (aka: normal/default). Supported real-time schedulers are: "deadline", "fifo", "round_robin". - - In the case of "timeout"\: + - The "timeout" setting\: The "timeout" Item Action provides default global settings for each of the three special situations: "kill", "start", and "stop". Each of these may only have a single one exist at a time (one "kill", one "start", one "stop", and one "wait"). Each successive "timeout" Item Action, specific to each Action Name (such as "start"), specified replaces the previously defined "timeout" Action (in a top-down manner). diff --git a/level_3/controller/specifications/entry.txt b/level_3/controller/specifications/entry.txt index 86636db..0ae7357 100644 --- a/level_3/controller/specifications/entry.txt +++ b/level_3/controller/specifications/entry.txt @@ -25,17 +25,19 @@ Entry Specification: The second Content represent the basename of the command file. - "setting": optional, Actions may be one of\: - - "mode": Exactly one Content that is one of "program" or "service". - - "pid": Exactly one Content that is one of "disable", "require", or "ready". - - "pid_file": Exactly one Content that is a relative or absolute path to a pid file. - - "session": Exactly one Content that is one of "new" or "same". - - "show": Exactly one Content that is one of "normal" or "init". - "control": One to two Content. The first Content is a relative or absolute path to a socket file. The second Content an optional "readonly". - "control_group": Exactly one Content that is a group name or group id. - "control_mode": Exactly one Content that is a valid file mode. - "control_user": Exactly one Content that is a user name or user id. + - "define": Two Content, the first Content must be a case-sensitive valid environment variable name (alpha-numeric or underscore, but no leading digits). + - "mode": Exactly one Content that is one of "program" or "service". + - "parameter": Two Content, the first Content must be a case-sensitive valid IKI name and the second being an IKI value. + - "pid": Exactly one Content that is one of "disable", "require", or "ready". + - "pid_file": Exactly one Content that is a relative or absolute path to a pid file. + - "session": Exactly one Content that is one of "new" or "same". + - "show": Exactly one Content that is one of "normal" or "init". The Entry file may have any other valid Item Objects, but only the above are reserved. -- 1.8.3.1