Search code examples
xmlsetpuppetaugeas

How to create separated XML nodes with "set" in Puppet using Augeas?


I am using the Augeas tool for Puppet 3.2 and I am trying to create an XML file. I want to be able to add multiple fields with the same name into my XML doc. For instance, I want to separate node2/location2 from node1/location1 by placing it in its own "node" field. This is my code:

    augeas { "update template":
        lens    => "Xml.lns",
        require => File["${buildpath}/tempfile.xml"],
        incl => "${buildpath}/tempfile.xml",
        changes => [
            "set member/acceptors[#attribute]/node[#attribute]/nodeIdentity[#attribute]/#text node2",
            "set member/acceptors/node/nodeLocation[#attribute]/#text location2",
            "set member/acceptors/node/nodeIdentity[#attribute]/#text node1",
            "set member/acceptors/node/nodeLocation[#attribute]/#text location1"
        ],
   }

This is the XML output that I get:

    <member>
        <acceptors>
            <node>
                <nodeIdentity>node2</nodeIdentity>
                <nodeLocation>location2</nodeLocation>
                <nodeIdentity>node1</nodeIdentity>
                <nodeLocation>location1</nodeLocation>
            </node>
        </acceptors>
    </member>

This is the output I want:

    <member>
        <acceptors>
            <node>
                <nodeIdentity>node2</nodeIdentity>
                <nodeLocation>location2</nodeLocation>
            </node>
            <node>
                <nodeIdentity>node1</nodeIdentity>
                <nodeLocation>location1</nodeLocation>
            </node>
        </acceptors>
    </member>

I have tried adding [#attribute] to the node1 line like the following:

     "set member/acceptors/node[#attribute]/nodeIdentity[#attribute]/#text node1",

But "node1" doesn't get outputted. Any suggestions?


Solution

  • You need to specify the node you want to impact with the XPath expression. In your case, you can write an idempotent change by doing this:

    augeas { "update template":
         lens    => "Xml.lns",
         require => File["${buildpath}/tempfile.xml"],
         incl    => "${buildpath}/tempfile.xml",
         changes => [
             "set member/acceptors/node[nodeIdentity/#text='node2']/nodeIdentity/#text node2",
             "set member/acceptors/node[nodeIdentity/#text='node2']/nodeLocation/#text location2",
             "set member/acceptors/node[nodeIdentity/#text='node1']/nodeIdentity/#text node1",
             "set member/acceptors/node[nodeIdentity/#text='node1']/nodeLocation/#text location1"
         ],
    }
    

    There is no need (that I see) to filter on the existence of #attribute sub-nodes, all the more that you don't create them, so you're changes won't be idempotent.