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