Re: How to create an "AppendToLineIfNotContains" rule

"'Nick Anderson' via help-cfengine" <[email protected]>
Newsgroups gmane.comp.sysutils.cfengine.general
Message-ID <[email protected]>
On Thursday, March 17, 2022 at 10:55:52 AM UTC-5 Jay2k1 wrote:

      error: Promised replacement
      'WEB_SERVERS=10.0.0.5,10.0.06,10.0.0.8,10.0.0.42,10.0.0.66'
      on line 'WEB_SERVERS=10.0.0.5,10.0.06,10.0.0.8,10.0.0.42'
      for pattern '^WEB_SERVERS=(.*')' is not convergent while
      editing '/etc/firewall/aliases.cfg' (regular expression
      matches the replacement string)

      How would I fix this?

Hi Jay,

Welcome to CFEngine 3, I hope you enjoy your stay.

As the error states, the regular expression matches the end result and
it's not convergent, meaning if we let it, it would do the work to
repair the line constantly. Your regular expression needs to avoid
matching the line in the case the value you want to append actually
appears in the line. For that, a negative look ahead (?!) will be your
friend.

For example:

,----
| bundle agent __main__
| {
|   files:
|       "/tmp/example.txt"
|         content => "# Be sure to check various cases
| # Case 0: IP present at end of line
| WEB_SERVERS=10.0.0.5,10.0.06,10.0.0.8,10.0.0.42,10.0.0.66
| # Case 1: IP present after =
| WEB_SERVERS=10.0.0.66,10.0.0.5,10.0.06,10.0.0.8,10.0.0.42
| # Case 2: IP absent
| WEB_SERVERS=10.0.0.5,10.0.06,10.0.0.8,10.0.0.42
| # Case 3: IP present in middle
| WEB_SERVERS=10.0.0.5,10.0.06,10.0.0.66,10.0.0.8,10.0.0.42
| # Case 4: No IPs present
| WEB_SERVERS=
| ";
| 
|       "/tmp/example.txt"
|         edit_line => append_if_not_in_line_matching("10.0.0.66",
| 
|                                                     #"(^WEB_SERVERS=)((?!.*\Q10.0.0.66\E).*)"); # This would match the case of WEB_SERVERS= and then you would append ,IP and that leading comma might be problematic.
|                                                     "(^WEB_SERVERS=)((?!.*\Q10.0.0.66\E).+)"); # This avoids matching empty WEB_SERVERS= but also won't set the IP, so that could be handled with other promises in the edit_line bundle
| 
| 
|   reports:
|       "/tmp/example.txt"
|         printfile => cat( $(this.promiser) );
| }
| 
| bundle edit_line append_if_not_in_line_matching( append_str, line_reg )
| {
|   replace_patterns:
|       "$(line_reg)"
|         replace_with => append_to_line( "$(append_str)" );
| }
| 
| body replace_with append_to_line( append_str )
| {
|   replace_value => "$(match.1)$(match.2),$(append_str)";
| }
`----
Listing 1: Example Policy

,----
|     info: Updated content of '/tmp/example.txt' with content '# Be sure to check various cases
| # Case 0: IP present at end of line
| WEB_SERVERS=10.0.0.5,10.0.06,10.0.0.8,10.0.0.42,10.0.0.66
| # Case 1: IP present after =
| WEB_SERVERS=10.0.0.66,10.0.0.5,10.0.06,10.0.0.8,10.0.0.42
| # Case 2: IP absent
| WEB_SERVERS=10.0.0.5,10.0.06,10.0.0.8,10.0.0.42
| # Case 3: IP present in middle
| WEB_SERVERS=10.0.0.5,10.0.06,10.0.0.66,10.0.0.8,10.0.0.42
| # Case 4: No IPs present
| WEB_SERVERS=
| '
|     info: Replaced pattern '(^WEB_SERVERS=)((?!.*\Q10.0.0.66\E).+)' in '/tmp/example.txt'
|     info: replace_patterns promise '(^WEB_SERVERS=)((?!.*\Q10.0.0.66\E).+)' repaired
|     info: Edited file '/tmp/example.txt'
| R: /tmp/example.txt
| R: # Be sure to check various cases
| R: # Case 0: IP present at end of line
| R: WEB_SERVERS=10.0.0.5,10.0.06,10.0.0.8,10.0.0.42,10.0.0.66
| R: # Case 1: IP present after =
| R: WEB_SERVERS=10.0.0.66,10.0.0.5,10.0.06,10.0.0.8,10.0.0.42
| R: # Case 2: IP absent
| R: WEB_SERVERS=10.0.0.5,10.0.06,10.0.0.8,10.0.0.42,10.0.0.66
| R: # Case 3: IP present in middle
| R: WEB_SERVERS=10.0.0.5,10.0.06,10.0.0.66,10.0.0.8,10.0.0.42
| R: # Case 4: No IPs present
| R: WEB_SERVERS=
`----

I think it's best to do full file management, but sometimes you have to
deal with partial management and it can get really sticky as you work
out edge cases.

I hope you find this example useful.

Here is another policy that uses replace_patterns with negative look
ahead:

<https://github.com/nickanderson/cfengine-security-hardening/blob/e2519214e8a29c7f37a36ca8a4beec687712448d/ntp-maxpoll/ntp-maxpoll.cf>

-- 
You received this message because you are subscribed to the Google Groups "help-cfengine" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To view this discussion on the web visit https://groups.google.com/d/msgid/help-cfengine/874k3w2v4e.fsf%40northern.tech.

-- 
Nick Anderson | Doer of Things | (+1) 785-550-1767 | https://northern.tech

-- 
You received this message because you are subscribed to the Google Groups "help-cfengine" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To view this discussion on the web visit https://groups.google.com/d/msgid/help-cfengine/874k3w2v4e.fsf%40northern.tech.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.