Forum: CFEngine Help
Subject: Re: filecopy, transform with grep.
Author: sauer
Link to topic: https://cfengine.com/forum/read.php?3,22985,23089#msg-23089

The underlying problem here seems to be coming from the issue that the cfengine 
code is ostensibly way more complicated than a two-line shell script. That 
misses the point that Cfengine is also doing a *lot* of extra work in the 
background.  All that extra work is not just wasted cycles, but rather, 
improved efficiency.  It "costs" a tad more code, but delivers a substantially 
greater value for the investment; kinda like how living in a cardboard box is 
way cheap, but most people agree that the additional cost of a real structure 
is justifiable.

The example above:
 - checks to see if the destination exists
 - checks to see if the source is newer than the destination
 - checks to see if the files are in sync
 - validates that the contents are as expected
 - does any neccesary edits in a temporray file
 - doesn't touch the destination file until it can ensure consistency
 - keeps a pre-edit backup of the destination file for historical purposes
 - provides for detailed individual reporting on all of the above steps

The shell script, instead, takes a big hammer and goes "smash" every time you 
run it.  In the no trespassing analogy, your shell script is hiring a vagrant 
to stand outside and shoot anyone who walks too closely to your fence.  Yeah, 
the ultimate goal of "no one done gets on ma property" is reached, but society 
would prefer that you used a bit more finnesse.

Back to the first question asked (before it devolved into whether or not 
convergence and promise theory are useful in the "real world") - how to justify 
the much larger set of code to collegues.  Well, in order to add all of the 
safety checks that we all know we should do in our shell scripts, but that we 
also all usually skip right over, you'll do it pretty much the same way.  
You'll check for adequate free space in /tmp, then grep -v from the source to 
/tmp, then do a diff between the temp file and the destination.  If there was a 
difference, then you'd check for adequate free space on the destination, and 
copy the file over.  That would be a lot more than one line in a shell script, 
and it'd be a lot less self-explanatory than the CFEngine equivalent.  Besides, 
it's not like the grep source code is simple; it's just "already there".


In any event, this can actually be done quite easily without explicitly 
creating the temp file.  When you edit a file within CFEngine, the edits are 
done in memory, and then compared against the output file before writing them 
out.  So really, all you need is something like this:


#!/var/cfengine/bin/cf-agent -Kf
body common control{ bundlesequence => { "a" }; }
bundle agent a {
files:
  "/tmp/noroot"
    edit_line     => grep_v("root:.*", "/etc/passwd"),
    edit_defaults => empty,
    create        => true;
}
bundle edit_line grep_v(patt, file){
insert_lines:
  "$(file)" insert_type   => "file",
            insert_select => ignore_patt("$(patt)");
}
body insert_select ignore_patt(patt){
  insert_if_not_match_from_list => { "$(patt)" };
}
body edit_defaults empty {
  empty_file_before_editing => "true";
}


The grep_v bundle will take the given source file and insert any lines which 
don't match the given pattern.  Combine that with the empty edit_defaults from 
COPBL (or mine), and you're only writing three lines per additional file to get 
your grep -v stdout transformer, but you get it without having to break the 
whole theory that Cfengine's built upon.  And really, that bundle (along with 
the two supporting bodies) can very easily be added to a standard library so it 
only takes four lines (or fewer; the whitespace doesn't /have/ to be newlines).

Does it work?

user@host
$ rm /tmp/noroot
user@host
$ ./filecopy.cf3
user@host
$ diff /tmp/noroot /etc/passwd
0a1
> root:x:0:0:root:/root:/bin/bash
user@host
$


Hooray!

If people still whine about that being too much to write, just make those three 
things parameters to another meta bundle, as in:


bundle agent superduperstuff{
methods:
  "random_name" usemethod => transform_grep_v_thingie("/path/to/src", 
"/path/to/dst", "anchored_pattern");
}
bundle agent transform_grep_v_thingie(src, dst, patt) {
files:
  "$(src)"
    edit_line     => grep_v("$(patt)", "$(dst)"),
    edit_defaults => empty,
    create        => true;
}
...


Look at that; we've reduced all of that complexity down to a single-line 
command.  You can move the complexity out to a separate library, and, just like 
in ol' Mark's grand plan, you can either get a quick overview by looking at the 
methods section in one bundle, or get a little more detail by looking at the 
implementation of the transform thingie, or even more detail by reading the 
grep_v and other lower-level bundles.  A friendly ogre might suggest that it's 
like an onion...

As an aside, parts of this (or something similar) might be useful to toss into 
the COPBL. ;)

_______________________________________________
Help-cfengine mailing list
[email protected]
https://cfengine.org/mailman/listinfo/help-cfengine

Reply via email to