-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #49822 from mchugh19/xml_module
initial xml module/state
- Loading branch information
Showing
5 changed files
with
425 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
# -*- coding: utf-8 -*- | ||
''' | ||
XML file mangler | ||
.. versionadded:: Neon | ||
''' | ||
from __future__ import absolute_import, print_function, unicode_literals | ||
|
||
import logging | ||
import xml.etree.ElementTree as ET | ||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
||
# Define the module's virtual name | ||
__virtualname__ = 'xml' | ||
|
||
|
||
def __virtual__(): | ||
''' | ||
Only load the module if all modules are imported correctly. | ||
''' | ||
return __virtualname__ | ||
|
||
|
||
def get_value(file, element): | ||
''' | ||
Returns the value of the matched xpath element | ||
CLI Example: | ||
.. code-block:: bash | ||
salt '*' xml.get_value /tmp/test.xml ".//element" | ||
''' | ||
try: | ||
root = ET.parse(file) | ||
element = root.find(element) | ||
return element.text | ||
except AttributeError: | ||
log.error("Unable to find element matching %s", element) | ||
return False | ||
|
||
|
||
def set_value(file, element, value): | ||
''' | ||
Sets the value of the matched xpath element | ||
CLI Example: | ||
.. code-block:: bash | ||
salt '*' xml.set_value /tmp/test.xml ".//element" "new value" | ||
''' | ||
try: | ||
root = ET.parse(file) | ||
relement = root.find(element) | ||
except AttributeError: | ||
log.error("Unable to find element matching %s", element) | ||
return False | ||
relement.text = str(value) | ||
root.write(file) | ||
return True | ||
|
||
|
||
def get_attribute(file, element): | ||
''' | ||
Return the attributes of the matched xpath element. | ||
CLI Example: | ||
.. code-block:: bash | ||
salt '*' xml.get_attribute /tmp/test.xml ".//element[@id='3']" | ||
''' | ||
try: | ||
root = ET.parse(file) | ||
element = root.find(element) | ||
return element.attrib | ||
except AttributeError: | ||
log.error("Unable to find element matching %s", element) | ||
return False | ||
|
||
|
||
def set_attribute(file, element, key, value): | ||
''' | ||
Set the requested attribute key and value for matched xpath element. | ||
CLI Example: | ||
.. code-block:: bash | ||
salt '*' xml.set_attribute /tmp/test.xml ".//element[@id='3']" editedby "gal" | ||
''' | ||
try: | ||
root = ET.parse(file) | ||
element = root.find(element) | ||
except AttributeError: | ||
log.error("Unable to find element matching %s", element) | ||
return False | ||
element.set(key, str(value)) | ||
root.write(file) | ||
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# -*- coding: utf-8 -*- | ||
''' | ||
XML Mangler | ||
=========== | ||
State managment of XML files | ||
''' | ||
from __future__ import absolute_import, print_function, unicode_literals | ||
|
||
# Import Python libs | ||
import logging | ||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
||
def __virtual__(): | ||
''' | ||
Only load if the XML execution module is available. | ||
''' | ||
if 'xml.get_value' in __salt__: | ||
return 'xml' | ||
else: | ||
return False, "The xml execution module is not available" | ||
|
||
|
||
def value_present(name, xpath, value, **kwargs): | ||
''' | ||
.. versionadded:: Neon | ||
Manages a given XML file | ||
name : string | ||
The location of the XML file to manage, as an absolute path. | ||
xpath : string | ||
xpath location to manage | ||
value : string | ||
value to ensure present | ||
.. code-block:: yaml | ||
ensure_value_true: | ||
xml.value_present: | ||
- name: /tmp/test.xml | ||
- xpath: .//playwright[@id='1'] | ||
- value: William Shakespeare | ||
''' | ||
ret = {'name': name, | ||
'changes': {}, | ||
'result': True, | ||
'comment': ''} | ||
|
||
if 'test' not in kwargs: | ||
kwargs['test'] = __opts__.get('test', False) | ||
|
||
current_value = __salt__['xml.get_value'](name, xpath) | ||
if not current_value: | ||
ret['result'] = False | ||
ret['comment'] = 'xpath query {0} not found in {1}'.format(xpath, name) | ||
return ret | ||
|
||
if current_value != value: | ||
if kwargs['test']: | ||
ret['result'] = None | ||
ret['comment'] = '{0} will be updated'.format(name) | ||
ret['changes'] = {name: {'old': current_value, 'new': value}} | ||
else: | ||
results = __salt__['xml.set_value'](name, xpath, value) | ||
ret['result'] = results | ||
ret['comment'] = '{0} updated'.format(name) | ||
ret['changes'] = {name: {'old': current_value, 'new': value}} | ||
else: | ||
ret['comment'] = '{0} is already present'.format(value) | ||
|
||
return ret |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
# -*- coding: utf-8 -*- | ||
''' | ||
Tests for xml module | ||
''' | ||
|
||
from __future__ import absolute_import, print_function, unicode_literals | ||
|
||
import os | ||
import tempfile | ||
|
||
from salt.modules import xml | ||
|
||
from tests.support.mixins import LoaderModuleMockMixin | ||
from tests.support.unit import TestCase, skipIf | ||
from tests.support.mock import ( | ||
NO_MOCK, | ||
NO_MOCK_REASON | ||
) | ||
|
||
XML_STRING = ''' | ||
<root xmlns:foo="http://www.foo.org/" xmlns:bar="http://www.bar.org"> | ||
<actors> | ||
<actor id="1">Christian Bale</actor> | ||
<actor id="2">Liam Neeson</actor> | ||
<actor id="3">Michael Caine</actor> | ||
</actors> | ||
<foo:singers> | ||
<foo:singer id="4">Tom Waits</foo:singer> | ||
<foo:singer id="5">B.B. King</foo:singer> | ||
<foo:singer id="6">Ray Charles</foo:singer> | ||
</foo:singers> | ||
</root> | ||
''' | ||
|
||
|
||
@skipIf(NO_MOCK, NO_MOCK_REASON) | ||
class XmlTestCase(TestCase, LoaderModuleMockMixin): | ||
''' | ||
Test cases for salt.modules.xml | ||
''' | ||
|
||
def setup_loader_modules(self): | ||
return {xml: {}} | ||
|
||
def test_get_value(self): | ||
''' | ||
Verify xml.get_value | ||
''' | ||
with tempfile.NamedTemporaryFile('w+', delete=False) as xml_file: | ||
xml_file.write(XML_STRING) | ||
xml_file.flush() | ||
|
||
xml_result = xml.get_value(xml_file.name, ".//actor[@id='2']") | ||
self.assertEqual(xml_result, "Liam Neeson") | ||
|
||
os.remove(xml_file.name) | ||
|
||
def test_set_value(self): | ||
''' | ||
Verify xml.set_value | ||
''' | ||
with tempfile.NamedTemporaryFile('w+', delete=False) as xml_file: | ||
xml_file.write(XML_STRING) | ||
xml_file.flush() | ||
|
||
xml_result = xml.set_value(xml_file.name, ".//actor[@id='2']", "Patrick Stewart") | ||
assert xml_result is True | ||
|
||
xml_result = xml.get_value(xml_file.name, ".//actor[@id='2']") | ||
self.assertEqual(xml_result, "Patrick Stewart") | ||
|
||
os.remove(xml_file.name) | ||
|
||
def test_get_attribute(self): | ||
''' | ||
Verify xml.get_attribute | ||
''' | ||
with tempfile.NamedTemporaryFile('w+', delete=False) as xml_file: | ||
xml_file.write(XML_STRING) | ||
xml_file.flush() | ||
|
||
xml_result = xml.get_attribute(xml_file.name, ".//actor[@id='3']") | ||
self.assertEqual(xml_result, {"id": "3"}) | ||
|
||
os.remove(xml_file.name) | ||
|
||
def test_set_attribute(self): | ||
''' | ||
Verify xml.set_value | ||
''' | ||
with tempfile.NamedTemporaryFile('w+', delete=False) as xml_file: | ||
xml_file.write(XML_STRING) | ||
xml_file.flush() | ||
|
||
xml_result = xml.set_attribute(xml_file.name, ".//actor[@id='3']", "edited", "uh-huh") | ||
assert xml_result is True | ||
|
||
xml_result = xml.get_attribute(xml_file.name, ".//actor[@id='3']") | ||
self.assertEqual(xml_result, {'edited': 'uh-huh', 'id': '3'}) | ||
|
||
os.remove(xml_file.name) |
Oops, something went wrong.