Skip to content

Commit

Permalink
Fixes #13667: Add condition_once and execute_once generic methods
Browse files Browse the repository at this point in the history
  • Loading branch information
amousset committed Oct 17, 2018
1 parent 5e744cb commit 234dc15
Show file tree
Hide file tree
Showing 5 changed files with 275 additions and 5 deletions.
12 changes: 11 additions & 1 deletion tests/acceptance/20_cfe_basics/flag_lib.cf
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ bundle agent test
"read an existing condition"
usebundle => get_flag("already"),
useresult => "get8";

"reserve"
usebundle => reserve_flag("test3"),
useresult => "reserve9";
"cancel" usebundle => cancel_flag("test3");
"read after"
usebundle => get_flag("test3"),
useresult => "get10";
}

bundle agent check
Expand All @@ -72,8 +80,10 @@ bundle agent check
"ok_6" expression => strcmp("${test.get6[1]}", "set");
"ok_7" expression => strcmp("${test.set7[1]}", "notreserved");
"ok_8" expression => strcmp("${test.get8[1]}", "set");
"ok_9" expression => strcmp("${test.reserve9[1]}", "ok");
"ok_10" expression => strcmp("${test.get10[1]}", "free");

"ok" expression => "ok_1.ok_2.ok_3.ok_4.ok_5.ok_6.ok_7.ok_8";
"ok" expression => "ok_1.ok_2.ok_3.ok_4.ok_5.ok_6.ok_7.ok_8.ok_9.ok_10";

reports:
ok::
Expand Down
63 changes: 63 additions & 0 deletions tests/acceptance/30_generic_methods/condition_once.cf
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#######################################################
#
# Test if only success classes are created
#
#######################################################

bundle common acc_path
{
vars:
"root" string => getenv("NCF_TESTS_ACCEPTANCE", 1024);
}

body common control
{
inputs => { "${acc_path.root}/default.cf.sub", "${acc_path.root}/default_ncf.cf.sub", "@{ncf_inputs.default_files}" };
bundlesequence => { configuration, initialization, default("$(this.promise_filename)") };
version => "1.0";
}

#######################################################

bundle agent init
{
methods:
"clean" usebundle => file_absent("${configuration.flag_file}");
}

#######################################################

bundle agent test
{
methods:
"ph1" usebundle => condition_once("first");
"enable dry-run" usebundle => set_dry_run_mode("true");
"ph2" usebundle => condition_once("second");
"disable dry-run" usebundle => set_dry_run_mode("false");
"reserve" usebundle => reserve_flag("condition_once_third");
"ph3" usebundle => condition_once("third");
"reserve" usebundle => reserve_flag("condition_once_fourth");
"re-enable" usebundle => set_dry_run_mode("true");
"ph4" usebundle => condition_once("fourth");
"re-disable" usebundle => set_dry_run_mode("true");

}

#######################################################

bundle agent check
{
classes:
"ok_class1" expression => "first.condition_once_first_repaired";
"ok_class2" expression => "second.condition_once_second_repaired";
"ok_class3" expression => "!third.condition_once_third_kept.!condition_once_third_repaired";
"ok_class4" expression => "!fourth.condition_once_fourth_kept.!condition_once_fourth_repaired";

"ok" expression => "ok_class1.ok_class2.ok_class3.ok_class4";

reports:
ok::
"$(this.promise_filename) Pass";
!ok::
"$(this.promise_filename) FAIL";
}
19 changes: 15 additions & 4 deletions tree/20_cfe_basics/flag_lib.cf
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@ bundle agent flag_initialization {
"flag_unique.value" string => "1";
}

bundle agent cancel_flag(name) {
vars:
"cname" string => canonify("${name}");
"cancel" string => "",
classes => if_ok_cancel("flag_reserved_${cname}"),
if => "flag_reserved_${cname}" ;
}

bundle agent reserve_flag(name) {
vars:
"cname" string => canonify("${name}");
Expand Down Expand Up @@ -124,8 +132,7 @@ bundle agent reserve_flag(name) {
comment => "${flag_unique.value}",
if => "free";

pass3::
"Failed, flag '${cname}' was not free"
"Could not reserve flag '${cname}', it was not free"
comment => "${flag_unique.value}",
if => "!free";
}
Expand All @@ -150,6 +157,7 @@ bundle agent set_flag(name) {
template_method => "mustache",
edit_template => "${sys.workdir}/modules/templates/datastate.json.tpl",
template_data => "@{set_flag.output}",
action => immediate_ignore_dry_run,
edit_defaults => no_backup,
classes => classes_generic("write_ncf_flag_${cname}"),
if => "flag_reserved_${cname}";
Expand All @@ -171,14 +179,15 @@ bundle agent set_flag(name) {
comment => "${flag_unique.value}",
if => "!flag_reserved_${cname}";

pass3::
"Flag '${cname}' (created ${time}) could not be set"
comment => "${flag_unique.value}",
if => "write_ncf_flag_${cname}_failed";
"Flag '${cname}' (created ${time}) could not be set as it was not reserved"
comment => "${flag_unique.value}",
if => "!flag_reserved_${cname}";

info::
pass3.info::
"Flag '${cname}' (created ${time}) was set"
comment => "${flag_unique.value}",
if => "write_ncf_flag_${cname}_ok";
Expand All @@ -193,6 +202,8 @@ bundle agent get_flag(name) {

classes:
"is_set" expression => isvariable("ncf_flags.data[${cname}]");
"pass3" expression => "pass2";
"pass2" expression => "pass1";
"pass1" expression => "any";

methods:
Expand All @@ -207,7 +218,7 @@ bundle agent get_flag(name) {
bundle_return_value_index => "1",
comment => "${flag_unique.value}",
if => "!is_set.!flag_reserved_${cname}";
info::
pass3.info::
"Flag '${cname}' is set"
comment => "${flag_unique.value}",
if => "is_set";
Expand Down
96 changes: 96 additions & 0 deletions tree/30_generic_methods/command_execution_once.cf
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#####################################################################################
# Copyright 2018 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################

# @name Command execution once
# @description Execute a command and create result conditions depending on its exit code
# @action
# @documentation Execute a command and create result conditions
# depending on the exit codes given in parameters.
# If an exit code is not in the list it will lead to an error status.
# If you want 0 to be a success you have to list it in the kept_codes list
#
# @parameter command The command to run
# @parameter ok_codes List of codes that produce a kept status separated with commas (ex: 1,2,5). Defaults to 0.
# @parameter until Try to execute the command until a particular state: 'ok', 'any' (defaults to 'any')
# @parameter_constraint until "allow_empty_string" : true
# @parameter_constraint until "select" : [ "", "any", "ok" ]
# @parameter unique_id To identify the command (allow to change the command without losing track)
#
# @class_prefix command_execution_once
# @class_parameter command

bundle agent command_execution_once(command, ok_codes, until, unique_id)
{
vars:
"c_unique_id" string => canonify("${unique_id}");
"old_class_prefix" string => canonify("command_execution_once_${command}");
"args" slist => { "${command}", "${ok_codes}", "${until}", "${unique_id}" };
"report_param" string => join("_", args);
"full_class_prefix" string => canonify("command_execution_once_${report_param}");
"class_prefix" string => string_head("${full_class_prefix}", "1000");

"ok_list" slist => splitstring("${ok_codes}", "\s*,\s*", "256");
"repaired_list" slist => {};

defaults:
"until" string => "any", if_match_regex => "";
"ok_codes" string => "0", if_match_regex => "";

classes:
"until_ok" expression => strcmp("${until}", "ok");

"reserved" expression => strcmp("${reserve[1]}", "ok");
"already_set" expression => strcmp("${reserve[1]}", "failed");
"set_ok" expression => strcmp("${set[1]}", "ok");

"${c_condition}" expression => "set_ok",
scope => "namespace";

any::
"pass3" expression => "pass2";
"pass2" expression => "pass1";
"pass1" expression => "any";

methods:
"reserve the flag" usebundle => reserve_flag("command_execution_once_${c_unique_id}"),
useresult => "reserve";
"set the flag" usebundle => set_flag("command_execution_once_${c_unique_id}"),
useresult => "set",
if => "reserved.${class_prefix}_repaired";

pass3.reserved.!set_ok::
"failure" usebundle => _classes_failure("${old_class_prefix}");
"failure" usebundle => _classes_failure("${class_prefix}");

pass3.already_set::
"success" usebundle => _classes_success("${old_class_prefix}");
"success" usebundle => _classes_success("${class_prefix}");

pass3::
"clean" usebundle => _classes_sanitize("${old_class_prefix}");
"clean" usebundle => _classes_sanitize("${class_prefix}");

"report"
usebundle => _log_v3("Execute the command '${command}' once", "${command}", "${old_class_prefix}", "${class_prefix}", @{args});

commands:
reserved::
"${command}"
contain => in_shell,
classes => classes_generic_return_code_list_two("${old_class_prefix}", "${class_prefix}", @{ok_list}, @{repaired_list});
}
90 changes: 90 additions & 0 deletions tree/30_generic_methods/condition_once.cf
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#####################################################################################
# Copyright 2018 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################

# @name Condition once
# @description Create a new condition only once
# @documentation This method evaluates an expression, and produces a `${condition}` when it is
# first called. Following calls will not define the condition.
#
# This allows executing actions only once on a given machine.
#
# The created condition is global to the agent.
#
# #### Example
#
# If you use:
#
# ```
# condition_once("my_condition")
# ```
#
# The first agent run will have `my_condition` defined, contrary to subsequent runs
# for which no class will be defined.
#
# See also : [command_execution_once](#command_execution_once)
# @parameter condition The condition to define
# @parameter_constraint condition "regex" : "^[\$\{\}\[\]a-zA-Z0-9_]+$"
#
# @class_prefix condition_once
# @class_parameter condition

bundle agent condition_once(condition)
{
vars:
"c_condition" string => canonify("${condition}");
"old_class_prefix" string => canonify("condition_once_${condition}");
"args" slist => { "${condition}" };
"report_param" string => join("_", args);
"full_class_prefix" string => canonify("condition_once_${report_param}");
"class_prefix" string => string_head("${full_class_prefix}", "1000");

classes:
"reserved" expression => strcmp("${reserve[1]}", "ok");
"already_set" expression => strcmp("${reserve[1]}", "failed");
"set_ok" expression => strcmp("${set[1]}", "ok");

"${c_condition}" expression => "set_ok",
scope => "namespace";

any::
"pass3" expression => "pass2";
"pass2" expression => "pass1";
"pass1" expression => "any";

methods:
"reserve the flag" usebundle => reserve_flag("condition_once_${c_condition}"),
useresult => "reserve";
reserved::
"set the flag" usebundle => set_flag("condition_once_${c_condition}"),
useresult => "set";

set_ok::
"success" usebundle => _classes_repaired("${old_class_prefix}");
"success" usebundle => _classes_repaired("${class_prefix}");

pass3.reserved.!set_ok::
"failure" usebundle => _classes_failure("${old_class_prefix}");
"failure" usebundle => _classes_failure("${class_prefix}");

pass3.already_set::
"success" usebundle => _classes_success("${old_class_prefix}");
"success" usebundle => _classes_success("${class_prefix}");

pass3::
"report" usebundle => _log_v3("Create the condition ${c_condition}", "${condition}", "${old_class_prefix}", "${class_prefix}", @{args});
}

0 comments on commit 234dc15

Please sign in to comment.