Skip to content

Configuration Commands XML

Jason Heiss edited this page Aug 25, 2014 · 1 revision

Deprecated

This page documents the deprecated XML format. New deployments should use the YAML format.

Etch was originally focused on managing the exact state of things on disk, file contents and metadata like permissions and ownership, symlinks and directories. You could execute commands to manipulate configuration, but only as a side-effect to managing the state of a specific file.

However, some system configuration must by done solely via the execution of a command. Solaris loves this sort of thing, but it exists elsewhere too. Package installation or removal is another example.

As such we've added support for "configuration commands" to etch.

The idea is that you specify both "what command should I run" and "when should I run it". I.e. the "command" and the "guard". You test the guard, and if false (indicating that things are not yet properly configured) you run the command, then re-run the guard to ensure that things are now correct. Some commands should only be run once, or only if something is misconfigured, so the guard provides a way for the user to test for that and avoid running the command if things are properly configured and working.

Configuration for these "configuration commands" lives within a commands/ directory at the top of the etch server configuration hierarchy. You create arbitrarily named directories within that commands/ directory and place a commands.xml in each one. Unlike the source/ directory where the directory structure maps to the file being generated there's no such obvious naming convention here, so you can name the directories in any way that makes sense to you, i.e. solaris_printing or linux_packages or solaris_ldapclient.

The directory structure in visual form:

  • commands/
    • linux_packages/
      • commands.xml
    • solaris_ldapclient/
      • commands.xml
  • config.dtd
  • defaults.xml
  • nodes.xml
  • source/

Some examples:

Package management:

<commands>
  <step operatingsystem="/RedHat|CentOS/">
    <guard>
      <exec>rpm --quiet -q emacs</exec>
    </guard>
    <command>
      <exec>yum -y install emacs</exec>
    </command>
  </step>
  <step operatingsystem="/RedHat|CentOS/">
    <guard>
      <exec>rpm --quiet -q xterm</exec>
    </guard>
    <command>
      <exec>yum -y install xterm</exec>
    </command>
  </step>
</commands>

Solaris LDAP client configuration:

<commands>
  <step operatingsystem="Solaris">
    <guard>
      <exec>ldapclient list | grep NS_LDAP_SEARCH_BASEDN= dc=example,dc=com</exec>
    </guard>
    <command>
      <exec>ldapclient manual -a defaultSearchBase=dc=example,dc=com -a defaultServerList="ldap1.example.com ldap2.example.com"</exec>
    </command>
  </step>
</commands>

Commands can depend on other commands and/or files:

<commands>
  <depend>othercommands</depend>
  <dependfile>/etc/passwd</dependfile>
  <step>
    <guard>
      <exec>false</exec>
    </guard>
    <command>
      <exec>true</exec>
    </command>
  </step>
</commands>

Acknowledgments

I was introduced to this concept by Trey Harris' "A New Approach to Scripting" presentation at LISA '04. He created an implementation in Perl called Commands::Guarded. His documentation explains the concept very lucidly so I have not attempted to recreate that overall explanation of the concept here. He in turn references Edsger W. Dijkstra's 1975 paper Guarded commands, nondeterminacy and formal derivation of programs.