Forum: CFEngine Help Subject: Re: Deleting extra entries inside config that's built by edit_line(s) Author: terok Link to topic: https://cfengine.com/forum/read.php?3,25689,25810#msg-25810
Hi, Took another approach to the issue, in which I could take advantage of the edit_defaults => empty. Now I just hit another snag, which just seems irrational to me. My idea was to stage the config file first with a header line, which contains the config blocks that I use. With that I can workaround the issue of removing entire config block section from the promises, and get that to trigger re-staging of the config file. After the header would be verified (if_ok), then i'd iterate through the "edit_line => set_config_values_w_delim_and_block" promise. As a last step, i'd copy that from my staging place to the proper place. This will work around the issues that someone would edit the actual config by hand. This actually worked, sort of.. The problem I hit next, was that append_if_no_line gets into race condition with the set_config_values_w_delim_and_block. I do get the proper config out of this, but it's reset in each agent run and that's bad. For some reason the append_if_no_line, doesn't detect the line properly or is emptied all the time. Here's an example of what 'sort of works', it just _always_ repairs the conf. "Promises observed to be kept 76%, Promises repaired 24%, Promises not repaired 0%" body common control { bundlesequence => { "block_conf" }; } bundle agent block_conf { vars: "conf" string => "/tmp/test.conf"; "stage" string => "/tmp/stage_test.conf"; debian:: # List of config blocks we have. # Value is the without [] # Key is the array variable set below. "array_ref" string => "USER"; "array_ref" string => "HOST"; "array_ref" string => "API"; # block "user" string => "randomuser", policy => "free"; "user" string => "randompass", policy => "free"; # block "host" string => "randomhost", policy => "free"; "host" string => "randomport", policy => "free"; # block "api" string => "/randomget", policy => "free"; "api" string => "/randompost", policy => "free"; # Open up the array_ref array. "array_ref_keys" slist => getindices("array_ref"); "array_ref_blocks" slist => getvalues("array_ref"); # Create string of the blocks in array_ref to use as a header in the config file. "all_avail_blocks" string => join(", ","array_ref_blocks"); # Setup the header for config files. "conf_header" string => "#blocks in this conf: $(all_avail_blocks)"; files: "$(stage)" comment => "Stage the $(conf) config values to $(stage)", # Iterate over all available blocks and add the entries. edit_line => set_config_values_w_delim_and_block("block_conf.$(array_ref_keys)","=","$(array_ref[$(array_ref_keys)])"), ifvarclass => canonify("$(stage)_reset"), classes => if_repaired("$(stage)_set"); # "$(conf)" # comment => "Copy the $(conf) from $(stage)", # copy_from => local_dcp("$(stage)"); "$(stage)" comment => "re-stage the $(stage) for $(conf)", create => "true", edit_defaults => empty, edit_line => append_if_no_line("$(conf_header)"), classes => if_ok("$(stage)_reset"); } bundle edit_line set_config_values_w_delim_and_block(v,delim,block) # Sets the RHS of configuration items in the file of the form # LHS delim RHS _after_ the given block. Also adds the block as such before entries: # # # [$(block)] # lhs $(delim) rhs # # # If the line is commented out with #, it gets uncommented first. # Adds a new line if none exists. { vars: "index" slist => getindices("$(v)"); # Be careful if the index string contains funny chars "cindex[$(index)]" string => canonify("$(index)"); delete_lines: ".*" select_region => edit_in_between("^\[$(block)\]","^#\"), delete_select => not_starting_with("set_config_values_w_delim_and_block.index"), ifvarclass => "replace_attempted_$(cindex[$(index)])"; replace_patterns: # If the line is there, maybe commented out, uncomment and replace with # the correct value "^\s*($(index)\s+(?!$(delim)\s+$($(v)[$(index)])).*|# ?$(index)\s+.*)$" replace_with => value("$(index) $(delim) $($(v)[$(index)])"), select_region => edit_in_between("^\[$(block)\]","^#\"), classes => always("replace_attempted_$(cindex[$(index)])"); insert_lines: "#"; "[$(block)]"; "#"; "$(index) $(delim) $($(v)[$(index)])" #insert_type => "preserve_block", select_region => edit_in_between("^\[$(block)\]","^#\"), ifvarclass => "replace_attempted_$(cindex[$(index)])"; } # Select region between start and end patterns body select_region edit_in_between(start, end) { select_start => "$(start)"; select_end => "$(end)"; } body delete_select not_starting_with(s) { delete_if_not_startwith_from_list => { @(s) }; } body copy_from local_dcp(from) { source => "$(from)"; compare => "digest"; } body edit_defaults empty { empty_file_before_editing => "true"; edit_backup => "false"; max_file_size => "300000"; } bundle edit_line append_if_no_line(str) { insert_lines: "$(str)" comment => "Append a line to the file if it doesn't already exist"; } body classes always(x) # Define a class no matter what the outcome of the promise is { promise_repaired => { "$(x)" }; promise_kept => { "$(x)" }; repair_failed => { "$(x)" }; repair_denied => { "$(x)" }; repair_timeout => { "$(x)" }; } body replace_with value(x) { replace_value => "$(x)"; occurrences => "all"; } body classes if_repaired(x) { promise_repaired => { "$(x)" }; } body classes if_ok(x) { promise_repaired => { "$(x)" }; promise_kept => { "$(x)" }; } This produces: # cat /tmp/stage_test.conf #blocks in this conf: USER, HOST, API # password = randompass username = randomuser # # hostname = randomhost port = randomport # # get = /randomget post = /randompost # Meaby I'm missing some body option.. Any idea what's going on there and how to get those 2 promises to coexist nicely? /Tero _______________________________________________ Help-cfengine mailing list Help-cfengine@cfengine.org https://cfengine.org/mailman/listinfo/help-cfengine