0
<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.

Vash
  • 13
  • 2

2 Answers2

1

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
raphink
  • 3,625
  • 1
  • 28
  • 39
  • I'm struggling to get this to work in hiera. - "defnode entry /root/node[#attribute/name='Network']/node[#attribute/name='${node}']/info/hash/entry[key/#text='NetName'] ''" - "set \$entry/key/#text 'NetName'" - "set \$entry/value/#attribute/type 'string'" - "set \$entry/value/#text 'eth8'" It's failing with "could not evaluate" – Vash Aug 25 '16 at 14:15
  • Putting hiera into the equation sounds like another question. – raphink Aug 25 '16 at 20:59
-2

Having nested 'node' make this task hard. It would be better to have tags 'nodes' then 'node'. Try this

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication11
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);

            List<XElement> rootNodes = doc.Element("root").Elements("node").ToList();
            List<XElement> bNodes = rootNodes.Select(x => x.Elements("node").Where(y => (string)y.Attribute("name") == "B")).SelectMany(z => z).ToList();
            foreach (XElement bHash in bNodes.Descendants("hash"))
            {
                Boolean netName = bHash.Descendants("key").Where(x => (string)x == "NetName").Any();
                if (!netName)
                {
                    bHash.Add(new XElement("entry", new object[] {
                        new XElement("key","NetName"),
                        new XElement("value", new object[] {
                            new XAttribute("type","string"),
                            "value"
                        })
                    }));
                }
            }

        }
    }

}
jdweng
  • 33,250
  • 2
  • 15
  • 20