Talk:Editfiles Considered Harmful
From Cfwiki
config editing
The referred to block of editfiles evolved as a method of working around the harmful effects of editfiles; there are lots of caveats to using Editfiles which need to be known prior to using it -- for example it doesn't work if the configuration file is sectioned, such as the so-called INI format (e.g. /etc/my.cnf is near impossible to work with using this structure, as are Apache configuration files).
The scenario where I use editfiles is for those config files that are shipped by the vendor, (/etc/ssh/sshd_config is the example referenced here) where each line can be either a comment or a unique independent config option and value. With these constraints on the configuration file, the editfiles section works as expected, ensuring that a single option line exists and that the value assigned to that option is correct.
So yes, it's not perfect, and the method of setting configuration options is not ideal, either.
The other thing I should note is that I rarely write the editfiles section out by hand; with that many lines it's clearly a source of human error. Instead I prefer to let the m4 macro language handle the generation of the editfiles code, which has the added benefit that people can actually read the cfinput editfiles section and see what it means.
editfiles:
any::
CF_EDIT_FILE(/etc/ssh/sshd_config,
CF_EDITFILES_KEYVAL_SPACE(PermitEmptyPasswords, no)
, sshd_restart)
ends up as:
editfiles:
any::
{ /etc/ssh/sshd_config
# Don't make a backup file.
Backup "off"
# Create the file if it doesn't exist.
AutoCreate
# Tell us about it
Inform "on"
# set 'PermitEmptyPasswords' to 'no'
BeginGroupIfNoLineMatching '^PermitEmptyPasswords.*'
Append 'PermitEmptyPasswords'
EndGroup
ResetSearch "1"
LocateLineMatching '^PermitEmptyPasswords.*'
BeginGroupIfNoMatch '^PermitEmptyPasswords no$'
ReplaceLineWith 'PermitEmptyPasswords no'
EndGroup
ResetSearch "1"
DefineClasses "sshd_restart"
}
I've had a few requests for these macros, but there's no documentation, the code is very fragile and diverges from maintainability, it was more a proof of concept (and an excuse to learn m4) than something I want to release (though you can download a tarball from here). Instead, I'd much prefer to see the development of a new section, "config", in which one can express the changes to configuration files in a more robust and friendly manner:
config:
sshd_server::
{ /etc/ssh/sshd_config
Separator " "
Set "PermitEmptyPasswords" "no"
DefineClasses "sshd_restart"
}
mysql_server::
{ /etc/my.cnf
Format "ini"
Separator " "
Set "mysqld/bind-address" "0.0.0.0"
}
any::
{ /etc/hosts.allow
Separator ": "
Set "sshd" "ALL"
}
redhat::
{ /etc/sysconfig/network
Format "shell"
Set "NETWORKING" "on"
}
A little rough, but you get the idea. "Format" specifies some predefined templates for the config file, defaulting to "plain old text file with one unique option per line". "Separator" can override Format's idea of the key/value separator, allowing one to modify most types of configuration file (in the field I've seen whitespace, equals signs, colons as the most common separator tokens). The "Set" command takes a key (possibly a path-like key name indicating nested sections) and value, and finally our old friend DefineClasses.
I'll just mention in passing a library I started working on once (called librcfile) which had the goal of hiding all the dirty work of this behind a simple API that cfengine could use, but alas, due to time constraints, it doesn't do much at the moment. -- Jamie Wilkinson
A General Language
I (David Douthitt) would like to see a general purpose language (such as Awk, m4, or lua) used for the editfiles section. If you examine the "language" that is used now, it seems clear that each directive stands alone; there is no generic "end" statements but there are specific end statements for each section.
This is an off-the top example of what I think would be an interesting editfiles section:
editfiles:
/etc/inittab {
nocreate;
/^#-- modified by cfengine/ if exit;
s/^s[4-6]/#&/;
1s/^/#-- modified by cfengine/;
define class(init_mod)
}
This example is sort of Perl-ish or sed-ish; this is a good example. It may be possible to create a set of macros that make this work, or even a way to feed this section into Perl or sed to be analyzed and output as necessary.
An ini file could be done like this perhaps:
editfiles:
/etc/http/conf {
grouping("[\([^]*]\)]"); # defines what makes a section,
# as well as where the name is found
comment("#"); # defines what makes a comment
group(hosts) {
comment;
}
}
You can let your imagination run a little with this; with an embedded language of some kind (lua?) this would be possible.
