URL: https://github.com/freeipa/freeipa/pull/241
Author: tiran
 Title: #241: Port ipapython.dnssec.odsmgr to xml.etree
Action: synchronized

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/241/head:pr241
git checkout pr241
From d22d1017657020582d30018b67887f3df8fb82fd Mon Sep 17 00:00:00 2001
From: Christian Heimes <chei...@redhat.com>
Date: Tue, 15 Nov 2016 12:57:13 +0100
Subject: [PATCH 1/2] Port ipapython.dnssec.odsmgr to xml.etree

The module ipapython.dnssec.odsmgr is the only module in ipalib,
ipaclient, ipapython and ipaplatform that uses lxml.etree.

https://fedorahosted.org/freeipa/ticket/6469

Signed-off-by: Christian Heimes <chei...@redhat.com>
---
 freeipa.spec.in                        |  3 +--
 ipapython/dnssec/odsmgr.py             | 38 ++++++++++++++++++-------------
 ipatests/test_ipapython/test_dnssec.py | 41 ++++++++++++++++++++++++++++++++++
 3 files changed, 65 insertions(+), 17 deletions(-)
 create mode 100644 ipatests/test_ipapython/test_dnssec.py

diff --git a/freeipa.spec.in b/freeipa.spec.in
index 7dbbf87..c7aeb52 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -248,6 +248,7 @@ Requires: %{name}-server-common = %{version}-%{release}
 Requires: %{name}-common = %{version}-%{release}
 Requires: python2-ipaclient = %{version}-%{release}
 Requires: python-ldap >= 2.4.15
+Requires: python-lxml
 Requires: python-gssapi >= 1.1.2
 Requires: python-sssdconfig
 Requires: python-pyasn1
@@ -509,7 +510,6 @@ Requires: keyutils
 Requires: pyOpenSSL
 Requires: python-nss >= 0.16
 Requires: python-cryptography >= 0.9
-Requires: python-lxml
 Requires: python-netaddr
 Requires: python-libipa_hbac
 Requires: python-qrcode-core >= 5.0.0
@@ -559,7 +559,6 @@ Requires: keyutils
 Requires: python3-pyOpenSSL
 Requires: python3-nss >= 0.16
 Requires: python3-cryptography
-Requires: python3-lxml
 Requires: python3-netaddr
 Requires: python3-libipa_hbac
 Requires: python3-qrcode-core >= 5.0.0
diff --git a/ipapython/dnssec/odsmgr.py b/ipapython/dnssec/odsmgr.py
index fb6d696..0308408 100644
--- a/ipapython/dnssec/odsmgr.py
+++ b/ipapython/dnssec/odsmgr.py
@@ -3,8 +3,11 @@
 # Copyright (C) 2014  FreeIPA Contributors see COPYING for license
 #
 
-from lxml import etree
 import dns.name
+try:
+    from xml.etree import cElementTree as etree
+except ImportError:
+    from xml.etree import ElementTree as etree
 
 from ipapython import ipa_log_manager, ipautil
 
@@ -59,13 +62,15 @@ class ODSZoneListReader(ZoneListReader):
     """One-shot parser for ODS zonelist.xml."""
     def __init__(self, zonelist_text):
         super(ODSZoneListReader, self).__init__()
-        xml = etree.fromstring(zonelist_text)
-        self._parse_zonelist(xml)
+        root = etree.fromstring(zonelist_text)
+        self._parse_zonelist(root)
 
-    def _parse_zonelist(self, xml):
+    def _parse_zonelist(self, root):
         """iterate over Zone elements with attribute 'name' and
         add IPA zones to self.zones"""
-        for zone_xml in xml.xpath('/ZoneList/Zone[@name]'):
+        if not root.tag == 'ZoneList':
+            raise ValueError(root.tag)
+        for zone_xml in root.findall('./Zone[@name]'):
             name, zid = self._parse_ipa_zone(zone_xml)
             self._add_zone(name, zid)
 
@@ -79,16 +84,19 @@ def _parse_ipa_zone(self, zone_xml):
             tuple (zone name, ID)
         """
         name = zone_xml.get('name')
-        in_adapters = zone_xml.xpath(
-            'Adapters/Input/Adapter[@type="File" '
-            'and starts-with(text(), "%s")]' % ENTRYUUID_PREFIX)
-        assert len(in_adapters) == 1, 'only IPA zones are supported: %s' \
-            % etree.tostring(zone_xml)
-
-        path = in_adapters[0].text
-        # strip prefix from path
-        zid = path[ENTRYUUID_PREFIX_LEN:]
-        return (name, zid)
+        zids = []
+        for in_adapter in zone_xml.findall(
+                './Adapters/Input/Adapter[@type="File"]'):
+            path = in_adapter.text
+            if path.startswith(ENTRYUUID_PREFIX):
+                # strip prefix from path
+                zids.append(path[ENTRYUUID_PREFIX_LEN:])
+
+        if len(zids) != 1:
+            raise ValueError('only IPA zones are supported: {}'.format(
+                etree.tostring(zone_xml)))
+
+        return name, zids[0]
 
 
 class LDAPZoneListReader(ZoneListReader):
diff --git a/ipatests/test_ipapython/test_dnssec.py b/ipatests/test_ipapython/test_dnssec.py
new file mode 100644
index 0000000..c4b830e
--- /dev/null
+++ b/ipatests/test_ipapython/test_dnssec.py
@@ -0,0 +1,41 @@
+#
+# Copyright (C) 2016  FreeIPA Contributors see COPYING for license
+#
+"""
+Test the `ipapython/dnssec` package.
+"""
+import dns.name
+
+from ipapython.dnssec.odsmgr import ODSZoneListReader
+
+
+ZONELIST_XML = """<?xml version="1.0" encoding="UTF-8"?>
+<ZoneList>
+  <Zone name="ipa.example">
+    <Policy>default</Policy>
+    <Adapters>
+      <Input>
+        <Adapter type="File">/var/lib/ipa/dns/zone/entryUUID/12345</Adapter>
+      </Input>
+      <Output>
+        <Adapter type="File">/var/lib/ipa/dns/zone/entryUUID/12345</Adapter>
+      </Output>
+    </Adapters>
+  </Zone>
+</ZoneList>
+"""
+
+
+def test_ods_zonelist_reader():
+    uuid = '12345'
+    name = dns.name.from_text('ipa.example.')
+
+    reader = ODSZoneListReader("<ZoneList/>")
+    assert reader.mapping == {}
+    assert reader.names == set()
+    assert reader.uuids == set()
+
+    reader = ODSZoneListReader(ZONELIST_XML)
+    assert reader.mapping == {uuid: name}
+    assert reader.names == {name}
+    assert reader.uuids == {uuid}

From e6e7e66c54717f993bfe3671fbc2fea27b0cb876 Mon Sep 17 00:00:00 2001
From: Christian Heimes <chei...@redhat.com>
Date: Wed, 16 Nov 2016 11:11:13 +0100
Subject: [PATCH 2/2] Use xml.etree in ipa-client-automount script

The ipa-client-automount script used lxml.etree to modify
/etc/autofs_ldap_auth.conf.

Signed-off-by: Christian Heimes <chei...@redhat.com>
---
 client/ipa-client-automount | 47 ++++++++++++++++++++++-----------------------
 1 file changed, 23 insertions(+), 24 deletions(-)

diff --git a/client/ipa-client-automount b/client/ipa-client-automount
index fc619d0..b4aa7e8 100755
--- a/client/ipa-client-automount
+++ b/client/ipa-client-automount
@@ -29,6 +29,11 @@ import time
 import tempfile
 import gssapi
 
+try:
+    from xml.etree import cElementTree as etree
+except ImportError:
+    from xml.etree import ElementTree as etree
+
 import SSSDConfig
 # pylint: disable=import-error
 from six.moves.urllib.parse import urlsplit
@@ -94,40 +99,34 @@ def wait_for_sssd():
         print("This may mean that sssd didn't re-start properly after the configuration changes.")
 
 def configure_xml(fstore):
-    from lxml import etree
-
-    fstore.backup_file(paths.AUTOFS_LDAP_AUTH_CONF)
+    authconf = paths.AUTOFS_LDAP_AUTH_CONF
+    fstore.backup_file(authconf)
 
     try:
-        f = open(paths.AUTOFS_LDAP_AUTH_CONF, 'r')
-        lines = f.read()
-        f.close()
-
-        saslconf = etree.fromstring(lines)
-        element = saslconf.xpath('//autofs_ldap_sasl_conf')
-        root = saslconf.getroottree()
+        tree = etree.parse(authconf)
     except IOError as e:
         root_logger.debug('Unable to open file %s' % e)
         root_logger.debug('Creating new from template')
-        element = [etree.Element('autofs_ldap_sasl_conf')]
-        root = element[0].getroottree()
+        tree = etree.ElementTree(
+            element=etree.Element('autofs_ldap_sasl_conf')
+        )
 
-    if len(element) != 1:
-        raise RuntimeError('Unable to parse %s' % paths.AUTOFS_LDAP_AUTH_CONF)
+    element = tree.getroot()
+    if element.tag != 'autofs_ldap_sasl_conf':
+        raise RuntimeError('Invalid XML root in file %s' % authconf)
 
-    element[0].set('usetls', 'no')
-    element[0].set('tlsrequired', 'no')
-    element[0].set('authrequired', 'yes')
-    element[0].set('authtype', 'GSSAPI')
-    element[0].set('clientprinc', 'host/%s@%s' % (api.env.host, api.env.realm))
+    element.set('usetls', 'no')
+    element.set('tlsrequired', 'no')
+    element.set('authrequired', 'yes')
+    element.set('authtype', 'GSSAPI')
+    element.set('clientprinc', 'host/%s@%s' % (api.env.host, api.env.realm))
 
-    newconf = open(paths.AUTOFS_LDAP_AUTH_CONF, 'w')
     try:
-        root.write(newconf, pretty_print=True, xml_declaration=True, encoding='UTF-8')
-        newconf.close()
+        tree.write(authconf, xml_declaration=True, encoding='UTF-8')
     except IOError as e:
-        print("Unable to write %s: %s" % (paths.AUTOFS_LDAP_AUTH_CONF, e))
-    print("Configured %s" % paths.AUTOFS_LDAP_AUTH_CONF)
+        print("Unable to write %s: %s" % (authconf, e))
+    else:
+        print("Configured %s" % authconf)
 
 def configure_nsswitch(fstore, options):
     """
-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to