Search code examples
xmlpuppetaugeas

augeas adding xml section to if node does not exist


<root>
<node name="Client">
    <node name="Attributes">
        <info>
            <hash>
                <entry><key>colour</key><value type="string">blue</value></entry>
            </hash>
        </info>
    </node>
</node>
<node name="Network">
    <node name="A">
        <info>
            <hash>
                <entry><key>NetName</key><value type="string">bnx1</value></entry>
                <entry><key>transport</key><value type="string">internet</value></entry>
                <entry><key>ipAddr</key><value type="string">125.125.125.142</value></entry>
                <entry><key>portNo</key><value type="string">1234</value></entry>
                <entry><key>protocolType</key><value type="string">tcp</value></entry>
            </hash>
        </info>
    </node>
    <node name="B">
        <info>
            <hash>
                <entry><key>transport</key><value type="string">internet</value></entry>
                <entry><key>ipAddr</key><value type="string">125.125.125.142</value></entry>
                <entry><key>portNo</key><value type="string">1234</value></entry>
                <entry><key>protocolType</key><value type="string">tcp</value></entry>
            </hash>
        </info>
    </node>
</node>
</root>

I want to create an entry with a key NetName and a value bnx2 in the node with name=B and if it's not present. I'm using augeas with puppet.


Solution

  • Here's what you can do with augtool:

    augtool> defvar hash /files/39143450.xml/root/node[#attribute/name="Network"]/node[#attribute/name="B"]/info/hash
    augtool> defnode entry $hash/entry[key/#text="NetName"]
    augtool> set $entry/key/#text "NetName"
    augtool> set $entry/value/#attribute/type "string"
    augtool> set $entry/value/#text "bnx2"
    augtool> save
    

    Translating that into a Puppet defined type:

    define entry (
      $value,
      $file,
      $ensure = 'present',
      $node = 'B',
    ) {
      case $ensure {
        'present': {
          $changes = [
            "defnode entry entry[key/#text='${name}'] ''",
            "set \$entry/key/#text '${name}'",
            "set \$entry/value/#attribute/type 'string'",
            "set \$entry/value/#text '${value}'",
          ]
        }
    
        'absent': {
          $changes = "rm entry[key/#text='${name}']"
        }
    
        default: {
          fail("Unknown value for ensure: ${ensure}")
        }
      }
    
      augeas { "Set ${title} in ${file}":
        incl    => $file,
        lens    => 'Xml.lns',
        context => "/files${file}/root/node[#attribute/name='Network']/node[#attribute/name='${node}']/info/hash",
        changes => $changes,
      }
    }
    
    entry { 'NetName':
      value => 'bnx2',
      file  => '/path/to/39143450.xml',
    }
    

    Running Puppet:

    Notice: Compiled catalog for example.com in environment production in 0.15 seconds
    Notice: /Stage[main]/Main/Entry[NetName]/Augeas[Set NetName in /path/to/39143450.xml]/returns: executed successfully
    Notice: Applied catalog in 0.09 seconds