I have a custom firewall system with our own simple configuration file. Its basically bash source defining a well known variables:

SERVICES="ping 80/tcp 443/tcp 22/tcp"

and I would like to manage these configuration files with puppet (probably via augeas if needed). Because I am new to the whole puppet ecosystem, I am looking for "best practice" of reasonably simple and clean way how to achieve this.

I need to be able to modify only some of the options (so I can not send the config as whole file from puppet master) and I do not want to limit the access to these files exclusively to puppet. All I need is a way how to ensure that certain subnet, service, etc... is (or is not) in the appropriate list, i.e. something like this:

firewall::superaccess { "LAN" :
         target => "",
          ensure=> "present",

I managed to force augeas into using Shell_variables lens and I was able to change the "simple" fields like FORWARDING. Unfortunatelly I did not succeed with the list values (i.e. SUPERACCESS) using the Shell_variables_list lens.

Maybe there is better way than using augeas. I tried to look on puppet forge if there is some module with similiar config format but I failed to find any. Unfortunately I do not know much of ruby and augeas lens language but I will learn some if needed. I just do not want to start in the wrong direction...

Update: Thanks to Raphink I managed to locate the problem. It is the comment in the middle of the line. If there is this line in the file:

service_ping="ping/icmp" #ping

I get this error:

/tmp/augcheck.TCTUBq/parse_file.aug:3.0-.58:exception thrown in test
/tmp/augcheck.TCTUBq/parse_file.aug:3.5-.54:exception: Iterated lens matched less than it should
    Lens: /usr/share/augeas/lenses/dist/shellvars_list.aug:40.12-.37:
    Error encountered at 176:0 (9906 characters into string)
    <--------\n#Built in services\n|=|service_ping="ping/icmp" #pi>

    Tree generated so far:

If I move the comment on separate line, it loads the file into the tree structure. Even augtool works as expected. I have these verison of augeas installed: ruby-augeas-0.4.1-3.fc17.x86_64, augeas-1.0.0-1.fc17.x86_64, augeas-libs-1.0.0-1.fc17.x86_64

Update 2: To solve the problem with inline comments I used code from ShellVars lens. The change is to copy/paste few definitions from ShellVars and change the definition of line:

  let empty_part_re = Util.empty_generic_re . /\n+/
  let semicol_eol = del (/[ \t]*[;\n]/ . empty_part_re*) "\n"
  let eol_for_comment = del /([ \t]*\n)([ \t]*(#[ \t]*)?\n)*/ "\n"
  (* comment_eol in shell MUST begin with a space *)
  let comment_eol = Util.comment_generic_seteol /[ \t]+#[ \t]*/ " # " eol_for_comment
  let comment_or_eol = comment_eol | semicol_eol

  let kv = [ key key_re . eq . ( squote_arr | dquote_arr | unquot_val ) .  comment_or_eol ]
  • Are these config files meant to change frequently? are there many of them in different machines, possibly with different configs?
    – dawud
    May 1 '13 at 19:28
  • no, they do not change often but they are on every machine and are really crucial as they manage the whole iptables firewall.. And yes, they vary a lot depending on what is installed on the machine... May 1 '13 at 19:34
  • @RadekHladík: Apparently, the Shellvars_list.lns lens doesn't support end-of-line comments (while the Shellvars.lns lens does). It shouldn't be too hard to implement.
    – raphink
    May 2 '13 at 6:47

Yes, the Shellvars_list lens should be able to parse your file as:

  { "quote" = """ }
  { "value" = "" }
  { "value" = "" }
  { "quote" = """ }
  { "value" = "ping" }
  { "value" = "80/tcp" }
  { "value" = "443/tcp" }
  { "value" = "22/tcp" }
  { "quote" = "" }
  { "value" = "1" }

Note: you can test that using augcheck:

augcheck /etc/firewall/config Shellvars_list

Now, the problem is: "How do you get from that tree to your definition?", that is:

firewall::superaccess { "LAN" :
         target => "",
          ensure=> "present",

where you'd want to ensure the presence of one element in a list.

You could do:

define firewall::superaccess (
  $ensure = 'present',
) {
  case $ensure {
    'present': {
      $changes = "set SUPERACCESS/value[.='${target}'] '${target}'"

    'absent': {
      $changes = "rm SUPERACCESS/value[.='${target}']"

    default: { fail "Wrong value for ensure: '${ensure}'" }

  augeas { "Set target ${target} in /etc/firewall/config":
    lens    => 'Shellvars_list.lns',
    incl    => '/etc/firewall/config',
    changes => $changes,
  • @Raphink, simply put: awesome. Nifty tool, augcheck.
    – dawud
    May 1 '13 at 20:46
  • Thanks a lot, augcheck tool is really nice. It is still not working completely but at least I see some debugging errors (instead of augtool just not loading the file without any info why) May 1 '13 at 21:48
  • And the puppet part is working like a charm too (after moving the comment on separate line). May 1 '13 at 22:11

What I would probably do is change your script so that the variables come from an external file, such as /etc/sysconfig/firewall-info or something (on say a redhat box or similar). Then you don't have to modify or manage the script at all, just the config file, and let the script read in the variables from the config file. Then you could easily manage the config file using the augeas shellvars lens, or even make a custom provider.

  • Maybe I did not stress it in my original post, but this is only the configuration file (it lives in /etc/firewall) and there is script (/sbin/setfire) that is taking care of setting the firewall. But I was not able to load this script with plain shellvars_list lens (and I dont know why). And I am not sure how difficult is to make my own provider and what would be needed for that... May 1 '13 at 19:43
  • Ah, ok. Shellvars is simple X=foo, SUPERACCESS above would just be set with a string, not a list. In order to have multiple whitespace separated strings in the quoted list, you would need to add the quotes manually in your augeas string.
    – lsd
    May 1 '13 at 19:47
  • There is the shellvars_list lens that looks like the one I need but I do not know how to debug why it does not load the file :-( May 1 '13 at 19:56
  • run augtool and try the commands by hand, error messages are listed under match /augeas//error: github.com/hercules-team/augeas/wiki/Tracking-down-errors
    – lsd
    May 2 '13 at 13:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.