I'm editing an iptables file via editfiles, and trying to make things "modular". Thus, if a host is part of the HttpHost class, the approriate rules to punch holes for port 80, 443, etc are made. If it also runs an rsync daemon, port 873 is opened up as well, and so on. This is an attempt to keep from having to maintain a specific per-host iptables file for all systems, if possible.
Here's an abstraced version of my problem. Given a file that looks like this: A B C D I want to insert three sets of lines after C, but before D (call them X, Y and Z). The order should be X, Y, Z. Y is actaully multiple lines, b= ut in a single string. Z is a variable number of lines, based on an slist. I also only want them inserted *once*--which is my problem. I can insert the lines correctly on the first call to cf-agent, but subsequent calls insert them again, and again, and again, etc... Here's a snippet that I think shows the problem: <---snip---> bundle random_service { vars: 'service_ips' slist => { '1.2.3.4', '5.6.7.8' }; files: some_class:: "/etc/sysconfig/iptables" edit_line => punch_holes("@{random_service.service_ips}"= ), classes => trigger('BounceIptables'); } bundle edit_lines punch_holes(servers) { insert_lines: # block "X" ":NEWCHAIN - [0:0]" =20 location => findline(':OUTPUT ACCEPT \[0:0\]'); # This is block "Y" as mentioned above. "-A NEWCHAIN -m tcp --dport 1234 -j ACCEPT -A NEWCHAIN -m tcp --dport 1235 -j ACCEPT -A NEWCHAIN -m tcp --dport 5544 -j ACCEPT" location => findline('^:NEWCHAIN.*'); # THis is block "Z", as mentioned above. "-A INPUT -s ${servers} -m tcp -p tcp -j NEWCHAIN" location => findline('^-A NEWCHAIN.*5544.*'); } body location findline(x) { select_line_matching => "^$(x).*"; before_after => "after"; } <---snip---> The problem is that block "Z" Is added repeatedly. Here is the content of the file before running these promises: A B C D After one run: A B C :NEWCHAIN - [0:0] -A NEWCHAIN -m tcp --dport 1234 -j ACCEPT -A NEWCHAIN -m tcp --dport 5544 -j ACCEPT -A INPUT -s 5.6.7.8 -m tcp -p tcp -j NEWCHAIN -A INPUT -s 1.2.3.4 -m tcp -p tcp -j NEWCHAIN D This is what I want. But after the 2nd run, I have this: A B C :NEWCHAIN - [0:0] -A NEWCHAIN -m tcp --dport 1234 -j ACCEPT -A NEWCHAIN -m tcp --dport 5544 -j ACCEPT -A INPUT -s 5.6.7.8 -m tcp -p tcp -j NEWCHAIN -A INPUT -s 1.2.3.4 -m tcp -p tcp -j NEWCHAIN -A INPUT -s 5.6.7.8 -m tcp -p tcp -j NEWCHAIN -A INPUT -s 1.2.3.4 -m tcp -p tcp -j NEWCHAIN D Which is not what I want. Inserting block X works, since it's a single line--nothing complicated here. Inserting block Y also works, since CFEngine treats it "like" a single string of text. I think that I even understand why block Z does *not* work: as @{servers} is iterated over, each line is inserted immediately after the requested location (matching regex '^-A NEWCHAIN.*5544.*$'). On subsequent passes, the line to insert has been "moved" such that it no longer immediately after the requested location, so it is re-inserted. I did also try this, but it didn't work (alas), since ${servers} is treated as a literal, and not iterated over: <---snip---> bundle edit_lines punch_holes(server) { vars: 'Server_Rules' slist => { "-A INPUT -s ${servers} -p tcp -m tcp -= j NEWCHAIN" }; 'One_Rule' string => join("${const.n}", 'Server_Rules'); insert_lines: "${One_Rule}" location => findline('^-A NEWCHAIN.*5544.*'); } <---snip---> So my question is: How to do this? I suppose that I could try to define the full iptables rules in the top-level bundle, instead of trying to construct it in an edit_lines bundle, but that doesn't seem like the right solution. Thanks, -- Jesse Becker NHGRI Linux support (Digicon Contractor) _______________________________________________ Help-cfengine mailing list Help-cfengine@cfengine.org https://cfengine.org/mailman/listinfo/help-cfengine