Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #18069: Parse log_* keywords #3153

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions rudder-lang/src/ast.rs
Expand Up @@ -561,6 +561,9 @@ impl<'src> AST<'src> {
"nodefault",
"fail",
"log",
"log_debug",
"log_info",
"log_warn",
"return",
"noop",
// historical invalid identifiers
Expand Down
104 changes: 41 additions & 63 deletions rudder-lang/src/ast/resource.rs
Expand Up @@ -282,7 +282,9 @@ pub enum Statement<'src> {
// Stop engine
Fail(Value<'src>),
// Inform the user of something
Log(Value<'src>),
LogDebug(Value<'src>),
LogInfo(Value<'src>),
LogWarn(Value<'src>),
// Return a specific outcome
Return(Token<'src>),
// Do nothing
Expand Down Expand Up @@ -310,6 +312,19 @@ fn push_default_parameters<'src>(
Ok(())
}

fn string_value<'src, VG>(getter: &VG, enum_list: &EnumList<'src>, pvalue: PValue<'src>) -> Result<Value<'src>>
where VG: Fn(Token<'src>) -> Option<VarKind<'src>>,
{
let value = Value::from_pvalue(enum_list, &getter, pvalue)?;
// check that definition use existing variables
value.context_check(&getter)?;
// we must have a string
match &value {
Value::String(_) => Ok(value),
_ => unimplemented!(), // TODO must fail here with a message
}
}

impl<'src> Statement<'src> {
pub fn fom_pstatement<'b>(
context: &'b mut VarContext<'src>,
Expand All @@ -319,17 +334,18 @@ impl<'src> Statement<'src> {
parameter_defaults: &HashMap<(Token<'src>, Option<Token<'src>>), Vec<Option<Value<'src>>>>,
enum_list: &EnumList<'src>,
) -> Result<Statement<'src>> {
// TODO common getter
// we must not capture the context in this common getter since it is used
// as mutable elsewhere in this function
let common_getter = |ctx: &VarContext<'src>, k: Token<'src>| {
ctx
.variables
.get(&k)
.or_else(|| global_context.variables.get(&k))
.map(VarKind::clone)
};
Ok(match st {
PStatement::VariableDefinition(pmetadata, var, val) => {
let getter = |k| {
context
.variables
.get(&k)
.or_else(|| global_context.variables.get(&k))
.map(VarKind::clone)
};
let value = Value::from_pvalue(enum_list, &getter, val)?;
let value = Value::from_pvalue(enum_list, &{ |x| common_getter(context,x) }, val)?;
match value {
Value::Boolean(_, _) => context.new_enum_variable(
Some(global_context),
Expand All @@ -339,7 +355,7 @@ impl<'src> Statement<'src> {
)?,
_ => {
// check that definition use existing variables
value.context_check(&getter)?;
value.context_check(&{ |x| common_getter(context,x) })?;
context.new_variable(Some(global_context), var, value.clone())?;
}
}
Expand All @@ -366,19 +382,12 @@ impl<'src> Statement<'src> {
)?;
}
children.insert(resource);
let getter = |k| {
context
.variables
.get(&k)
.or_else(|| global_context.variables.get(&k))
.map(VarKind::clone)
};
let mut resource_params = map_vec_results(resource_params.into_iter(), |v| {
Value::from_pvalue(enum_list, &getter, v)
Value::from_pvalue(enum_list, &{ |x| common_getter(context,x) }, v)
})?;
push_default_parameters(resource, None, parameter_defaults, &mut resource_params)?;
let mut state_params = map_vec_results(state_params.into_iter(), |v| {
Value::from_pvalue(enum_list, &getter, v)
Value::from_pvalue(enum_list, &{ |x| common_getter(context,x) }, v)
})?;
push_default_parameters(
resource,
Expand All @@ -387,8 +396,8 @@ impl<'src> Statement<'src> {
&mut state_params,
)?;
// check that parameters use existing variables
map_results(resource_params.iter(), |p| p.context_check(&getter))?;
map_results(state_params.iter(), |p| p.context_check(&getter))?;
map_results(resource_params.iter(), |p| p.context_check(&{ |x| common_getter(context,x) }))?;
map_results(state_params.iter(), |p| p.context_check(&{ |x| common_getter(context,x) }))?;
let (mut _errors, metadata) = create_metadata(metadata);
Statement::StateDeclaration(StateDeclaration {
source,
Expand All @@ -402,40 +411,16 @@ impl<'src> Statement<'src> {
})
}
PStatement::Fail(f) => {
let getter = |k| {
context
.variables
.get(&k)
.or_else(|| global_context.variables.get(&k))
.map(VarKind::clone)
};
let value = Value::from_pvalue(enum_list, &getter, f)?;
// check that definition use existing variables
value.context_check(&getter)?;
// we must fail with a string
match &value {
Value::String(_) => (),
_ => unimplemented!(), // TODO must fail here with a message
}
Statement::Fail(value)
Statement::Fail(string_value(&{ |x| common_getter(context,x) }, enum_list, f)?)
}
PStatement::Log(l) => {
let getter = |k| {
context
.variables
.get(&k)
.or_else(|| global_context.variables.get(&k))
.map(VarKind::clone)
};
let value = Value::from_pvalue(enum_list, &getter, l)?;
// check that definition use existing variables
value.context_check(&getter)?;
// we must fail with a string
match &value {
Value::String(_) => (),
_ => unimplemented!(), // TODO must fail here with a message
}
Statement::Log(value)
PStatement::LogDebug(l) => {
Statement::LogDebug(string_value(&{ |x| common_getter(context,x) }, enum_list, l)?)
}
PStatement::LogInfo(l) => {
Statement::LogInfo(string_value(&{ |x| common_getter(context,x) }, enum_list, l)?)
}
PStatement::LogWarn(l) => {
Statement::LogWarn(string_value(&{ |x| common_getter(context,x) }, enum_list, l)?)
}
PStatement::Return(r) => {
if r == Token::new("", "kept")
Expand All @@ -455,14 +440,7 @@ impl<'src> Statement<'src> {
PStatement::Case(case, v) => Statement::Case(
case,
map_vec_results(v.into_iter(), |(exp, sts)| {
let getter = |k| {
context
.variables
.get(&k)
.or_else(|| global_context.variables.get(&k))
.map(VarKind::clone)
};
let expr = enum_list.canonify_expression(&getter, exp)?;
let expr = enum_list.canonify_expression(&{ |x| common_getter(context,x) }, exp)?;
Ok((
expr,
map_vec_results(sts.into_iter(), |st| {
Expand Down
22 changes: 21 additions & 1 deletion rudder-lang/src/generators/cfengine.rs
Expand Up @@ -177,7 +177,17 @@ impl CFEngine {
"_abort",
vec![quoted("policy_fail"), self.value_to_string(msg, true)?],
)]),
Statement::Log(msg) => Ok(vec![Promise::usebundle(
Statement::LogDebug(msg) => Ok(vec![Promise::usebundle(
"log_rudder_mode",
vec![
quoted("log_debug"),
self.value_to_string(msg, true)?,
quoted("None"),
// TODO: unique class prefix
quoted("log_debug"),
],
)]),
Statement::LogInfo(msg) => Ok(vec![Promise::usebundle(
"log_rudder_mode",
vec![
quoted("log_info"),
Expand All @@ -187,6 +197,16 @@ impl CFEngine {
quoted("log_info"),
],
)]),
Statement::LogWarn(msg) => Ok(vec![Promise::usebundle(
"log_rudder_mode",
vec![
quoted("log_warn"),
self.value_to_string(msg, true)?,
quoted("None"),
// TODO: unique class prefix
quoted("log_warn"),
],
)]),
Statement::Return(outcome) => {
// handle end of bundle
self.return_condition = Some(match self.current_cases.last() {
Expand Down
10 changes: 9 additions & 1 deletion rudder-lang/src/generators/dsc.rs
Expand Up @@ -331,7 +331,15 @@ impl DSC {
" \"method_call\" usebundle => ncf_fail({});\n",
self.parameter_to_dsc(msg, "Fail")?
)),
Statement::Log(msg) => Ok(format!(
Statement::LogDebug(msg) => Ok(format!(
" \"method_call\" usebundle => ncf_log({});\n",
self.parameter_to_dsc(msg, "Log")?
)),
Statement::LogInfo(msg) => Ok(format!(
" \"method_call\" usebundle => ncf_log({});\n",
self.parameter_to_dsc(msg, "Log")?
)),
Statement::LogWarn(msg) => Ok(format!(
" \"method_call\" usebundle => ncf_log({});\n",
self.parameter_to_dsc(msg, "Log")?
)),
Expand Down
8 changes: 6 additions & 2 deletions rudder-lang/src/parser.rs
Expand Up @@ -796,7 +796,9 @@ pub enum PStatement<'src> {
// Stop engine with a final message
Fail(PValue<'src>),
// Inform the user of something
Log(PValue<'src>),
LogDebug(PValue<'src>),
LogInfo(PValue<'src>),
LogWarn(PValue<'src>),
// Return a specific outcome
Return(Token<'src>),
// Do nothing
Expand Down Expand Up @@ -876,7 +878,9 @@ fn pstatement(i: PInput) -> PResult<PStatement> {
PStatement::Return,
),
map(preceded(sp(etag("fail")), pvalue), PStatement::Fail),
map(preceded(sp(etag("log")), pvalue), PStatement::Log),
map(preceded(sp(etag("log_debug")), pvalue), PStatement::LogDebug),
map(preceded(sp(etag("log_info")), pvalue), PStatement::LogInfo),
map(preceded(sp(etag("log_warn")), pvalue), PStatement::LogWarn),
map(etag("noop"), |_| PStatement::Noop),
))(i)
}
Expand Down
4 changes: 2 additions & 2 deletions rudder-lang/tests/compile.rs
Expand Up @@ -205,7 +205,7 @@ Configure_NTP state technique() {
# this case makes no sense, testing purpose
system=~ubuntu => file("/tmp").absent(),
system=~debian => file("/tmp").present(),
default => log "info: ok"
default => log_info "ok"
}
}"#; "s_state_case")]
#[test_case("f_state_case", r#"@format=0
Expand Down Expand Up @@ -233,7 +233,7 @@ Configure_NTP state technique() {
case {
# this case makes no sense, testing purpose
system=~ubuntu => file("/tmp").absent(),
default => log "info: ok"
default => log_info "ok"
}
}"#; "s_state_casedefault")]
#[test_case("f_state_if_recursive", r#"@format=0
Expand Down
2 changes: 1 addition & 1 deletion rudder-lang/tests/compile_techniques/s_state_case.rl
Expand Up @@ -6,6 +6,6 @@ Configure_NTP state technique() {
# this case makes no sense, testing purpose
system=~ubuntu => file("/tmp").absent(),
system=~debian => file("/tmp").present(),
default => log "info: ok"
default => log_info "ok"
}
}
2 changes: 1 addition & 1 deletion rudder-lang/tests/tmp/s_state_case/technique.rl
Expand Up @@ -36,6 +36,6 @@ bundle agent Configure_NTP_technique {
unless => concat("debian");
"${report_data.directive_id}_0" usebundle => log_rudder("Skipping method 'any' with key parameter '/tmp' since condition 'debian' is not reached", "/tmp", canonify("${class_prefix}_file_present_/tmp"), canonify("${class_prefix}_file_present_/tmp"), @{args}),
unless => concat("debian");
"${report_data.directive_id}_0" usebundle => ncf_log(info: ok);
"${report_data.directive_id}_0" usebundle => log_rudder_mode("log_info", "ok", "None", "log_info");

}