From 97bc8f90b2f2e9c49e958c7309162d8f0af67d64 Mon Sep 17 00:00:00 2001 From: gpoblon Date: Wed, 8 Jul 2020 19:54:57 +0200 Subject: [PATCH] Work in progress --- rudder-lang/src/translate.rs | 76 +++++++++----- .../tests/test_files/translate/cis.json | 98 +++++++++---------- rudder-lang/tests/test_files/translate/cis.rl | 10 +- .../tests/test_files/translate/cis.rl.cf | 14 +++ .../tests/test_files/translate/s_basic.rl | 13 +++ .../tests/test_files/translate/s_ntp.rl.cf | 19 ++++ 6 files changed, 153 insertions(+), 77 deletions(-) create mode 100644 rudder-lang/tests/test_files/translate/cis.rl.cf create mode 100644 rudder-lang/tests/test_files/translate/s_basic.rl create mode 100644 rudder-lang/tests/test_files/translate/s_ntp.rl.cf diff --git a/rudder-lang/src/translate.rs b/rudder-lang/src/translate.rs index 81636d28719..ca07bc0f90b 100644 --- a/rudder-lang/src/translate.rs +++ b/rudder-lang/src/translate.rs @@ -49,9 +49,21 @@ struct MethodCall { #[derive(Serialize, Deserialize, Default)] struct Parameter { - name: String, + name: Option, value: String, } +impl Parameter { + pub fn new(name: Option<&str>, value: &str) -> Self { + let owned_name = match name { + Some(n) => Some(n.to_owned()), + None => None + }; + Self { + name: owned_name, + value: value.to_owned() + } + } +} pub fn translate_file(context: &IOContext) -> Result<()> { let input_path = context.source.to_string_lossy(); @@ -91,7 +103,10 @@ pub fn translate_file(context: &IOContext) -> Result<()> { let mut technique = serde_json::from_str::(&json_data) .map_err(|e| err!(Token::new(&input_path, ""), "{}", e))?; - technique.method_calls.iter_mut().for_each(|method| method.args.push(method.parameters.iter().map(|p| p.value.to_owned()).collect())); + technique.method_calls.iter_mut().for_each(|method| { + method.parameters.extend(method.args.iter().map(|v| Parameter::new(None, v)).collect::>()) + }); + info!( "|- {} (translation phase)", @@ -168,6 +183,28 @@ resource {bundle_name}({parameter_list}) _ => panic!(format!("The standard library contains several matches for the following method: {}", method_name)) } } + + fn translate_args(&self, args: I, template_vars: &mut Vec) -> Result + where I: Iterator + { + let mut updated_args = Vec::new(); + for arg in args { + // rl v2 behavior should make use of this, for now, just a syntax validator + if parse_cfstring(&arg.value).is_err() { + return Err(Error::User(format!("Invalid variable syntax in '{}'", arg.value))); + } + if arg.value.contains("$") { + updated_args.push(format!("p{}", template_vars.len())); + template_vars.push(format!(" p{}=\"{}\"", template_vars.len(), arg.value)); + } else { + updated_args.push(format!("\"{}\"", arg.value)); + } + } + + let validated_args = map_strings_results(updated_args.iter(), |x| Ok(x.to_owned()), ",")?; + + Ok(validated_args) + } fn translate_call(&self, call: &MethodCall) -> Result { let (resource, state) = match self.get_method_from_stdlib(&call.method_name) { @@ -194,9 +231,13 @@ resource {bundle_name}({parameter_list}) } Some(v) => v as usize, }; - let it = &mut call.args.iter(); - let res_args = map_strings_results(it.take(res_arg_count), |x| self.translate_arg(x), ",")?; - let st_args = map_strings_results(it, |x| self.translate_arg(x), ",")?; + + let it = &mut call.parameters.iter(); + let mut template_vars = Vec::new(); + let res_args = self.translate_args(it.take(res_arg_count), &mut template_vars)?; // automatically takes the first rather than getting the right resource param index + let st_args = self.translate_args(it, &mut template_vars)?; + // empty string purpose: add an ending newline when joined into a string + template_vars.push(String::new()); // call formating let call_str = format!("{}({}).{}({})", &resource, res_args, &state, st_args); @@ -239,13 +280,13 @@ resource {bundle_name}({parameter_list}) } Some(m) => m.as_integer().unwrap(), }; - let class_parameter_value = &call.args[class_parameter_id as usize]; - let canonic_parameter = canonify(class_parameter_value); + let class_parameter = &call.parameters[class_parameter_id as usize]; + let canonic_parameter = canonify(&class_parameter.value); let outcome = format!(" as {}_{}", class_prefix, canonic_parameter); // TODO remove outcome if there is no usage Ok(format!( - " @component = \"{}\"\n{}{}", - &call.component, out_state, outcome + "{} @component = \"{}\"\n{}{}", + template_vars.join("\n"), &call.component, out_state, outcome )) } @@ -287,15 +328,6 @@ resource {bundle_name}({parameter_list}) Ok((parameters_meta, parameter_list)) } - fn translate_arg(&self, arg: &str) -> Result { - let var = match parse_cfstring(arg) { - Err(_) => return Err(Error::User(format!("Invalid variable syntax in '{}'", arg))), - Ok((_, o)) => o, - }; - - map_strings_results(var.iter(), |x| Ok(format!("\"{}\"", x.to_string()?)), ",") - } - fn translate_condition(&self, expr: &str) -> Result { lazy_static! { static ref CLASS_RE: Regex = Regex::new(r"([\w${}.]+)").unwrap(); @@ -355,10 +387,9 @@ resource {bundle_name}({parameter_list}) } else if vec!["error", "not_ok", "failed", "denied", "timeout", "not_kept"].iter().any(|x| x == &outcome) { return Ok(format!("{} =~ error", method)); - } else if vec!["repaired", "ok", "reached"].iter().any(|x| x == &outcome) + } else if vec!["repaired", "ok", "reached", "true", "false"].iter().any(|x| x == &outcome) { return Ok(format!("{} =~ {}", method, outcome)); - } else if cond == "" { } }; @@ -469,11 +500,6 @@ fn parse_cfstring(i: &str) -> IResult<&str, Vec> { delimited(tag("${"), parse_cfvariable, tag("}")), CFStringElt::Variable, ), - // variable $() - map( - delimited(tag("$("), parse_cfvariable, tag(")")), - CFStringElt::Variable, - ), // constant map(take_until("$"), |s: &str| CFStringElt::Static(s.into())), // end of string diff --git a/rudder-lang/tests/test_files/translate/cis.json b/rudder-lang/tests/test_files/translate/cis.json index 62fd63c5bd5..22c178857f0 100644 --- a/rudder-lang/tests/test_files/translate/cis.json +++ b/rudder-lang/tests/test_files/translate/cis.json @@ -1,57 +1,57 @@ { - "bundle_name": "CIS_redhat7___Enable_Service", - "description": "test", - "name": "CIS redhat7 - Enable Service", - "version": "1.0", - "parameter": [ + "bundle_name": "CIS_redhat7___Enable_Service", + "description": "test", + "name": "CIS redhat7 - Enable Service", + "version": "1.0", + "parameter": [ + { + "id": "981a5b9d-b062-4011-8dff-df1810cb2fe6", + "name": "service", + "description": "" + } + ], + "category": "CIS_redhat7", + "method_calls": [ + { + "parameters": [ + { + "name": "condition_prefix", + "value": "skip_item_${report_data.canonified_directive_id}", + "$errors": [] + }, { - "id": "981a5b9d-b062-4011-8dff-df1810cb2fe6", - "name": "service", - "description": "" + "name": "variable_name", + "value": "node.properties[skip][${report_data.directive_id}]", + "$errors": [] } ], - "category": "CIS_redhat7", - "method_calls": [ - { - "parameters": [ - { - "name": "condition_prefix", - "value": "skip_item_${report_data.canonified_directive_id}", - "$errors": [] - }, - { - "name": "variable_name", - "value": "node.properties[skip][${report_data.directive_id}]", - "$errors": [] - } - ], - "class_context": "any", - "method_name": "condition_from_variable_existence", - "component": "condition_from_variable_existence" - }, + "class_context": "any", + "method_name": "condition_from_variable_existence", + "component": "condition_from_variable_existence" + }, + { + "parameters": [ { - "parameters": [ - { - "name": "service_name", - "value": "${service}", - "$errors": [] - } - ], - "class_context": "any.(skip_item_${report_data.canonified_directive_id}_ok)", - "method_name": "service_enabled", - "component": "service_enabled" - }, + "name": "service_name", + "value": "${service}", + "$errors": [] + } + ], + "class_context": "any.(skip_item_${report_data.canonified_directive_id}_false)", + "method_name": "service_enabled", + "component": "service_enabled" + }, + { + "parameters": [ { - "parameters": [ - { - "name": "service_name", - "value": "${service}", - "$errors": [] - } - ], - "class_context": "any.(skip_item_${report_data.canonified_directive_id}_not_ok)", - "method_name": "service_started", - "component": "service_started" + "name": "service_name", + "value": "${service}", + "$errors": [] } - ] + ], + "class_context": "any.(skip_item_${report_data.canonified_directive_id}_false)", + "method_name": "service_started", + "component": "service_started" } + ] +} diff --git a/rudder-lang/tests/test_files/translate/cis.rl b/rudder-lang/tests/test_files/translate/cis.rl index aa82046b96b..9c661133c88 100644 --- a/rudder-lang/tests/test_files/translate/cis.rl +++ b/rudder-lang/tests/test_files/translate/cis.rl @@ -9,10 +9,14 @@ resource CIS_redhat7___Enable_Service(service) CIS_redhat7___Enable_Service state technique() { + p0 = "skip_item_${report_data.canonified_directive_id}" + p1 = "node.properties[skip][${report_data.directive_id}]" @component = "condition_from_variable_existence" - condition("skip_item_","${report_data.canonified_directive_id}","node.properties[skip][","${report_data.directive_id}","]").from_variable_existence() as condition_from_variable_existence_skip_item___report_data_canonified_directive_id_node_properties_skip____report_data_directive_id__ + condition(p0).from_variable_existence(p1) as condition_from_variable_existence_skip_item___report_data_canonified_directive_id_ + p0 = "${service}" @component = "service_enabled" - if (skip_item_${report_data.canonified_directive_id} =~ ok) => service("service").enabled() as service_enabled___service_ + if (skip_item_${report_data.canonified_directive_id} =~ false) => service(p0).enabled() as service_enabled___service_ + p0 = "${service}" @component = "service_started" - if (skip_item_${report_data.canonified_directive_id} =~ error) => service("service").started() as service_started___service_ + if (skip_item_${report_data.canonified_directive_id} =~ false) => service(p0).started() as service_started___service_ } diff --git a/rudder-lang/tests/test_files/translate/cis.rl.cf b/rudder-lang/tests/test_files/translate/cis.rl.cf new file mode 100644 index 00000000000..4530aa77c42 --- /dev/null +++ b/rudder-lang/tests/test_files/translate/cis.rl.cf @@ -0,0 +1,14 @@ +# generated by rudder-lang +# @name CIS redhat7 - Enable Service +# @description test +# @version 1.0 +# @parameter { "name": "service", "id": "981a5b9d-b062-4011-8dff-df1810cb2fe6", "constraints": "" } + +bundle agent CIS_redhat7___Enable_Service_technique(service) +{ + vars: + "resources_dir" string => "${this.promise_dirname}/resources"; + methods: + "condition_from_variable_existence_${report_data.directive_id}_0" usebundle => _method_reporting_context("condition_from_variable_existence", "skip_item_"); + "condition_from_variable_existence_${report_data.directive_id}_0" usebundle => condition_from_variable_existence("skip_item_", "${report_data.canonified_directive_id}"); +} diff --git a/rudder-lang/tests/test_files/translate/s_basic.rl b/rudder-lang/tests/test_files/translate/s_basic.rl new file mode 100644 index 00000000000..ad437b1e376 --- /dev/null +++ b/rudder-lang/tests/test_files/translate/s_basic.rl @@ -0,0 +1,13 @@ +# This file has been generated with rltranslate +@format=0 +@name="Configure NTP" +@description="test" +@version="1.0" +@parameters= [ +] + +resource Configure_NTP() +Configure_NTP state technique() { + @component = "Package present" + package("ntp").present("","","") as package_present_ntp +} diff --git a/rudder-lang/tests/test_files/translate/s_ntp.rl.cf b/rudder-lang/tests/test_files/translate/s_ntp.rl.cf new file mode 100644 index 00000000000..5ee9a9d2623 --- /dev/null +++ b/rudder-lang/tests/test_files/translate/s_ntp.rl.cf @@ -0,0 +1,19 @@ +# generated by rudder-lang +# @name NTP Technique +# @description Configure the NTP +# @version 1.1 + +bundle agent NTP_Technique_technique +{ + vars: + "resources_dir" string => "${this.promise_dirname}/resources"; + methods: + "Package install_${report_data.directive_id}_0" usebundle => _method_reporting_context("Package install", "ntp"); + "Package install_${report_data.directive_id}_0" usebundle => package_install("ntp"); + "File ensure lines present_${report_data.directive_id}_1" usebundle => _method_reporting_context("File ensure lines present", "/etc/ntp.conf"); + "File ensure lines present_${report_data.directive_id}_1" usebundle => file_ensure_lines_present("/etc/ntp.conf", "server pool.ntp.org"); + "Service restart_${report_data.directive_id}_2" usebundle => _method_reporting_context("Service restart", "ntp"), + if => concat("file_ensure_lines_present__etc_ntp_conf1_outcome_repaired"); + "Service restart_${report_data.directive_id}_2" usebundle => service_restart("ntp"), + if => concat("file_ensure_lines_present__etc_ntp_conf1_outcome_repaired"); +}