Skip to content

Commit

Permalink
Fixes #18701: create a generic method to delete an ini section in file
Browse files Browse the repository at this point in the history
  • Loading branch information
ncharles committed Nov 27, 2020
1 parent dd08536 commit caf16c5
Show file tree
Hide file tree
Showing 3 changed files with 296 additions and 0 deletions.
219 changes: 219 additions & 0 deletions tests/acceptance/30_generic_methods/file_ini_section_absent.cf
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
#######################################################
#
# Test checking if a section is absent in file
#
#######################################################

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, default("${this.promise_filename}") };
version => "1.0";
}

#######################################################
bundle agent init
{
vars:
"tmp" string => getenv("TEMP", 1024);

## REPAIRED
# Simple removal
"file[0]" string => "${tmp}/test0.ini";
"section[0]" string => "section1";
"status[0]" string => "repaired";
"initial[0]" string => "[section1]
foo";
"expected[0]" string => "";

# Simple removal ok middle section
"file[1]" string => "${tmp}/test1.ini";
"section[1]" string => "section1";
"status[1]" string => "repaired";
"initial[1]" string => "[section0]
some nice content
[section1]
foo
[section2]
foobar";
"expected[1]" string => "[section0]
some nice content
[section2]
foobar";

# remove first section with line already present in other sections
"file[2]" string => "${tmp}/test2.ini";
"section[2]" string => "section0";
"status[2]" string => "repaired";
"initial[2]" string => "[section0]
some nice content
bar
[section1]
some nice content
bar
[section2]
foobar";
"expected[2]" string => "[section1]
some nice content
bar
[section2]
foobar";

# Remove last section
"file[3]" string => "${tmp}/test3.ini";
"section[3]" string => "section2";
"status[3]" string => "repaired";
"initial[3]" string => "[section1]
foo
bar
foobar
[section1]
some nice content
bar
[section2]
foobar";
"expected[3]" string => "[section1]
foo
bar
foobar
[section1]
some nice content
bar";

## Non compliant: audit & section present
"file[4]" string => "${tmp}/test4.ini";
"section[4]" string => "section1";
"status[4]" string => "error";
"initial[4]" string => "[section0]
some nice content
[section1]
foo
[section2]
foobar";
"expected[4]" string => "${initial[4]}";

## SUCCESS - section not present
"file[5]" string => "${tmp}/test5.ini";
"section[5]" string => "section2";
"line[5]" string => "bar";
"status[5]" string => "success";
"initial[5]" string => "[section1]
foo
bar";
"expected[5]" string => "${initial[5]}";

"file[6]" string => "${tmp}/test6.ini";
"section[6]" string => "section1";
"line[6]" string => "bar";
"status[6]" string => "success";
"initial[6]" string => "[section0]
some nice content
section1
[section2]
foobar";
"expected[6]" string => "${initial[6]}";

## Compliant, section not present
"file[7]" string => "${tmp}/test7.ini";
"section[7]" string => "section2";
"line[7]" string => "bar";
"status[7]" string => "success";
"initial[7]" string => "[section1]
foo
bar";
"expected[7]" string => "${initial[5]}";

## Others
# In a non existing file
"file[10]" string => "${tmp}/test10.ini";
"section[10]" string => "section1";
"status[10]" string => "success";
"expected[10]" string => "";


"indices" slist => getindices("status");

files:
"${file[${indices}]}"
create => "true",
edit_line => insert_lines("${initial[${indices}]}"),
edit_defaults => empty,
unless => strcmp("${indices}", "10");
}

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

bundle agent test
{
vars:
"args${init.indices}" slist => { "${init.file[${init.indices}]}", "${init.section[${init.indices}]}"};

methods:
# Enforce
"ph0" usebundle => apply_gm("file_ini_section_absent", @{args0}, "${init.status[0]}", "ph0", "enforce" );
"ph1" usebundle => apply_gm("file_ini_section_absent", @{args1}, "${init.status[1]}", "ph1", "enforce" );
"ph2" usebundle => apply_gm("file_ini_section_absent", @{args2}, "${init.status[2]}", "ph2", "enforce" );
"ph3" usebundle => apply_gm("file_ini_section_absent", @{args3}, "${init.status[3]}", "ph3", "enforce" );
"ph4" usebundle => apply_gm("file_ini_section_absent", @{args4}, "${init.status[4]}", "ph4", "audit" );
"ph5" usebundle => apply_gm("file_ini_section_absent", @{args5}, "${init.status[5]}", "ph5", "enforce" );
"ph6" usebundle => apply_gm("file_ini_section_absent", @{args6}, "${init.status[6]}", "ph6", "enforce" );
"ph7" usebundle => apply_gm("file_ini_section_absent", @{args7}, "${init.status[7]}", "ph7", "audit" );
"ph10" usebundle => apply_gm("file_ini_section_absent", @{args10}, "${init.status[10]}", "ph10", "enforce" );
}

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

bundle agent check
{
vars:
pass1::
"indices" slist => { @{init.indices} };

# function readfile adds an extra trailing newline if there is no trailing newline, too inconsistent
"content[${indices}]" string => execresult("${paths.cat} ${init.file[${indices}]}", "noshell"),
unless => strcmp("${indices}", "10");

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

pass2::
# file 10 is non existant
"content_ok_${indices}" expression => and(
strcmp("${content[${indices}]}", "${init.expected[${indices}]}"),
fileexists("${init.file[${indices}]}")
),
unless => strcmp("${indices}", "10");
"content_ok_10" expression => "any";

"content_not_ok" expression => "!content_ok_${indices}";
"classes_ok" expression => "ph0_ok.ph1_ok.ph2_ok.ph3_ok.ph4_ok.ph5_ok.ph6_ok.ph7_ok.ph10_ok";
"ok" expression => "!content_not_ok.classes_ok";


reports:
pass3::
"###########################
ERROR test ${indices} in
${init.file[${indices}]}
EXPECTED:
${init.expected[${indices}]}
---------------------------
FOUND:
${content[${indices}]}
###########################"
ifvarclass => "!content_ok_${indices}";

pass3.ok::
"$(this.promise_filename) Pass";
pass3.!ok::
"$(this.promise_filename) FAIL";
}

11 changes: 11 additions & 0 deletions tree/20_cfe_basics/files.cf
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,17 @@ bundle edit_line ensure_line_in_ini_section(section_name, line)
comment => "Insert line in section ${section_name}";
}

# Remove an section (INI-style)
bundle edit_line ensure_section_absent(section_name) {
delete_lines:
# delete everything in the section
".*"
select_region => INI_section("${section_name}");

# delete the section header
"\[${section_name}\]\s*$";
}

# Ensure that a line is present in an xml tag
# Won't create the tag if not there (we don't know where to put it)
bundle edit_line ensure_line_in_xml_tag(tag_name, line)
Expand Down
66 changes: 66 additions & 0 deletions tree/30_generic_methods/file_ini_section_absent.cf
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#####################################################################################
# Copyright 2020 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 File INI section absent
# @description Ensure that an INI section is absent from a file.
# It will purge the section, and remove its section header if the section is present.
#
# @parameter file File name to edit (absolute path on the target node)
# @parameter section Name of the INI-style section to remove (not including the [] brackets)
#
# @class_prefix file_ini_section_absent
# @class_parameter file

bundle agent file_ini_section_absent(file, section_name)
{
vars:
"old_class_prefix" string => canonify("file_ini_section_absent_${file}");

"args" slist => { "${file}", "${section_name}" };

"report_param" string => join("_", args);
"full_class_prefix" string => canonify("file_ini_section_absent_${report_param}");
"class_prefix" string => string_head("${full_class_prefix}", "1000");

"canonified_file" string => canonify("${file}");


classes:
# Check if the section exists
"section_present" expression => regline("^\[${section_name}\]$","${file}");

files:
# If the section is present in the file, its content will be removed
# and then the header
"${file}"
edit_line => ensure_section_absent("${section_name}"),
edit_defaults => ncf_empty_select("false"),
ifvarclass => "section_present",
comment => "Remove section from file",
classes => classes_generic_two("${old_class_prefix}", "${class_prefix}");


methods:
!section_present::
"success" usebundle => _classes_success("${class_prefix}");
"success" usebundle => _classes_success("${old_class_prefix}");

any::
"report" usebundle => _log_v3("Removing section ${section_name} from ${file}", "${file}", "${old_class_prefix}", "${class_prefix}", @{args});

}

0 comments on commit caf16c5

Please sign in to comment.