Hi,
0001 is pretty straightforward, I need it for 0002.
0002 introduces a new class DnsBackup that makes sure that any records
that we might want to potentially remove (SRV and NS right now) are
properly saved using sysrestore. It also takes care of removing them
during the uninstallation.
0003 makes 0002 useful by allowing the user to input the admin password
to ipa-server-install --uninstall and connecting to ldap.

I've tested these quite a lot so hopefully there won't be any major
problems with them.

Thanks
Martin
>From 656dbf1e7531c2c2a42914c7018e8dd5399478a4 Mon Sep 17 00:00:00 2001
From: Martin Nagy <mn...@redhat.com>
Date: Thu, 15 Apr 2010 11:59:16 +0200
Subject: [PATCH 1/3] Accept unicode for sysrestore

---
 ipapython/sysrestore.py |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/ipapython/sysrestore.py b/ipapython/sysrestore.py
index 78c9b62..ddc3ee0 100644
--- a/ipapython/sysrestore.py
+++ b/ipapython/sysrestore.py
@@ -282,8 +282,8 @@ class StateFile:
         by the string @key and with the value @value. @value may be
         a string or boolean.
         """
-        if not (isinstance(value, str) or isinstance(value, bool)):
-            raise ValueError("Only strings or booleans supported")
+        if not isinstance(value, (str, bool, unicode)):
+            raise ValueError("Only strings, booleans or unicode strings are supported")
 
         if not self.modules.has_key(module):
             self.modules[module] = {}
-- 
1.6.2.5

>From 0b9db95440940429a802b1fcb00666e6490841c0 Mon Sep 17 00:00:00 2001
From: Martin Nagy <mn...@redhat.com>
Date: Wed, 25 Nov 2009 00:49:40 +0100
Subject: [PATCH 2/3] Delete old SRV records during uninstallation

---
 ipaserver/install/bindinstance.py |   79 +++++++++++++++++++++++++++++++-----
 1 files changed, 68 insertions(+), 11 deletions(-)

diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
index e728911..016d46f 100644
--- a/ipaserver/install/bindinstance.py
+++ b/ipaserver/install/bindinstance.py
@@ -87,7 +87,7 @@ def get_reverse_zone(ip_address):
 
     return zone, name
 
-def add_zone(name, update_policy=None):
+def add_zone(name, update_policy=None, dns_backup=None):
     if not update_policy:
         update_policy = "grant %s krb5-self * A;" % api.env.realm
 
@@ -99,11 +99,11 @@ def add_zone(name, update_policy=None):
     except (errors.DuplicateEntry, errors.EmptyModlist):
         pass
 
-    add_rr(name, "@", "NS", api.env.host+".")
+    add_rr(name, "@", "NS", api.env.host+".", dns_backup)
 
     return name
 
-def add_reverze_zone(ip_address, update_policy=None):
+def add_reverze_zone(ip_address, update_policy=None, dns_backup=None):
     zone, name = get_reverse_zone(ip_address)
     if not update_policy:
         update_policy = "grant %s krb5-subdomain %s. PTR;" % (api.env.realm, zone)
@@ -115,24 +115,75 @@ def add_reverze_zone(ip_address, update_policy=None):
     except (errors.DuplicateEntry, errors.EmptyModlist):
         pass
 
-    add_rr(zone, "@", "NS", api.env.host)
+    add_rr(zone, "@", "NS", api.env.host, dns_backup)
 
     return zone
 
-def add_rr(zone, name, type, rdata):
+def add_rr(zone, name, type, rdata, dns_backup=None):
     try:
         api.Command.dns_add_rr(unicode(zone), unicode(name),
                                unicode(type), unicode(rdata))
     except (errors.DuplicateEntry, errors.EmptyModlist):
         pass
+    if dns_backup:
+        dns_backup.add(zone, type, name, rdata)
 
-def add_ptr_rr(ip_address, fqdn):
+def add_ptr_rr(ip_address, fqdn, dns_backup=None):
     zone, name = get_reverse_zone(ip_address)
-    add_rr(zone, name, "PTR", fqdn+".")
+    add_rr(zone, name, "PTR", fqdn+".", dns_backup)
+
+
+class DnsBackup(object):
+    def __init__(self, service):
+        self.service = service
+        self.zones = {}
+
+    def add(self, zone, record_type, host, rdata):
+        """
+        Backup a DNS record in the file store so it can later be removed.
+        """
+        if zone not in self.zones:
+            zone_id = len(self.zones)
+            self.zones[zone] = (zone_id, 0)
+            self.service.backup_state("dns_zone_%s" % zone_id, zone)
+
+        (zone_id, record_id) = self.zones[zone]
+        self.service.backup_state("dns_record_%s_%s" % (zone_id, record_id),
+                                  "%s %s %s" % (record_type, host, rdata))
+        self.zones[zone] = (zone_id, record_id + 1)
+
+    def clear_records(self, have_ldap):
+        """
+        Remove all records from the file store. If we are connected to
+        ldap, we will also remove them there.
+        """
+        i = 0
+        while True:
+            zone = self.service.restore_state("dns_zone_%s" % i)
+            if not zone:
+                return
+
+            j = 0
+            while True:
+                dns_record = self.service.restore_state("dns_record_%s_%s" % (i, j))
+                if not dns_record:
+                    break
+                if have_ldap:
+                    type, host, rdata = dns_record.split(" ", 2)
+                    try:
+                        api.Command.dns_del_rr(unicode(zone), unicode(host),
+                                               unicode(type), unicode(rdata))
+                    except:
+                        pass
+                j += 1
+
+            i += 1
+
 
 class BindInstance(service.Service):
     def __init__(self, fstore=None, dm_password=None):
         service.Service.__init__(self, "named", dm_password=dm_password)
+        self.dns_backup = DnsBackup(self)
         self.named_user = None
         self.fqdn = None
         self.domain = None
@@ -246,14 +297,18 @@ class BindInstance(service.Service):
             ("_kpasswd._udp", "SRV", "0 100 464 %s" % self.host),
         )
 
-        zone = add_zone(self.domain)
+        zone = add_zone(self.domain, dns_backup=self.dns_backup)
+
         for (host, type, rdata) in resource_records:
-            add_rr(zone, host, type, rdata)
+            if type == "SRV":
+                add_rr(zone, host, type, rdata, self.dns_backup)
+            else:
+                add_rr(zone, host, type, rdata)
         if self.ntp:
-            add_rr(zone, "_ntp._udp", "SRV", "0 100 123 "+self.host)
+            add_rr(zone, "_ntp._udp", "SRV", "0 100 123 %s" % self.host)
 
     def __setup_reverse_zone(self):
-        add_reverze_zone(self.ip_address)
+        add_reverze_zone(self.ip_address, dns_backup=self.dns_backup)
         add_ptr_rr(self.ip_address, self.fqdn)
 
     def __setup_principal(self):
@@ -325,6 +380,8 @@ class BindInstance(service.Service):
         running = self.restore_state("running")
         enabled = self.restore_state("enabled")
 
+        self.dns_backup.clear_records(api.Backend.ldap2.isconnected())
+
         if not running is None:
             self.stop()
 
-- 
1.6.2.5

>From 3b21badd52d6edd3151350799a414664993ec34e Mon Sep 17 00:00:00 2001
From: Martin Nagy <mn...@redhat.com>
Date: Thu, 15 Apr 2010 11:08:48 +0200
Subject: [PATCH 3/3] Connect to the ldap during the uninstallation

We need to ask the user for a password and connect to the ldap so the
bind uninstallation procedure can remove old records. This is of course
only helpful if one has more than one IPA server configured.
---
 install/tools/ipa-server-install |   36 ++++++++++++++++++++++++++++--------
 1 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install
index 314adf1..e577092 100755
--- a/install/tools/ipa-server-install
+++ b/install/tools/ipa-server-install
@@ -134,9 +134,8 @@ def parse_options():
 
     if options.uninstall:
         if (options.ds_user or options.realm_name or
-            options.dm_password or options.admin_password or
-            options.master_password):
-            parser.error("In uninstall mode, -u, r, -p and -P options are not allowed")
+            options.admin_password or options.master_password):
+            parser.error("In uninstall mode, -u, r and -P options are not allowed")
     elif options.unattended:
         if (not options.ds_user or not options.realm_name or
             not options.dm_password or not options.admin_password):
@@ -368,7 +367,10 @@ def check_dirsrv(unattended):
             print "\t636"
         sys.exit(1)
 
-def uninstall(ca = False):
+def uninstall(ca=False, dm_password=None):
+    if dm_password:
+        api.Backend.ldap2.connect(bind_dn="cn=Directory Manager", bind_pw=dm_password)
+
     try:
         run(["/usr/sbin/ipa-client-install", "--on-master", "--unattended", "--uninstall"])
     except Exception, e:
@@ -458,16 +460,34 @@ def main():
     )
 
     if options.uninstall:
+        dm_password = options.dm_password
+
+        # We will need at least api.env, finalize api now. This system is
+        # already installed, so the configuration file is there.
+        api.bootstrap(**cfg)
+        api.finalize()
+
         if not options.unattended:
             print "\nThis is a NON REVERSIBLE operation and will delete all data and configuration!\n"
             if not user_input("Are you sure you want to continue with the uninstall procedure?", False):
                 print ""
                 print "Aborting uninstall operation."
                 sys.exit(1)
-
-        api.bootstrap(**cfg)
-        api.finalize()
-        return uninstall(not certs.ipa_self_signed())
+            if not dm_password:
+                if user_input("Do you want to remove old SRV and NS records?", False):
+                    dm_password = read_password("Directory Manager", confirm=False, validate=False)
+                    # Try out the password
+                    try:
+                        conn = ipaldap.IPAdmin(api.env.host)
+                        conn.do_simple_bind(bindpw=dm_password)
+                        conn.unbind()
+                    except (ldap.CONNECT_ERROR, ldap.SERVER_DOWN), e:
+                        sys.exit("\nUnable to connect to LDAP server %s" % api.env.host)
+                    except ldap.INVALID_CREDENTIALS, e :
+                        sys.exit("\nThe password provided is incorrect for LDAP server %s" % api.env.host)
+
+
+        return uninstall(not certs.ipa_self_signed(), dm_password)
 
     # This will override any settings passed in on the cmdline
     options._update_loose(read_cache())
-- 
1.6.2.5

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to