URL: https://github.com/freeipa/freeipa/pull/764
Author: rcritten
 Title: #764: Basic uninstaller for the CA
Action: opened

PR body:
"""
This in response to watching users flounder with repeated failed replica 
installations and ipa-ca-install attempts that require a complete uninstall. 
Review it with whatever priority you desire.

This is meant ONLY to be able to re-try an installation if the
CA cloning fails for some reason. It is not intended to be used
to remove the CA as a service on a given master.

This is to avoid having to stand up a whole new master just
because the CA installation failed.

https://pagure.io/freeipa/issue/6595
"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/764/head:pr764
git checkout pr764
From da470e73eb3100777e983cc31a3566390e66efc2 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcrit...@redhat.com>
Date: Thu, 4 May 2017 14:45:49 -0400
Subject: [PATCH] Basic uninstaller for the CA

This is meant ONLY to be able to re-try an installation if the
CA cloning fails for some reason. It is not intended to be used
to remove the CA as a service on a given master.

This is to avoid having to stand up a whole new master just
because the CA installation failed.

https://pagure.io/freeipa/issue/6595
---
 install/tools/ipa-ca-install    | 72 ++++++++++++++++++++++++++++++++++++++++-
 ipaserver/install/cainstance.py | 10 ++++--
 2 files changed, 79 insertions(+), 3 deletions(-)

diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install
index 60261aa..97e9959 100755
--- a/install/tools/ipa-ca-install
+++ b/install/tools/ipa-ca-install
@@ -24,6 +24,7 @@ import shutil
 import tempfile
 
 from ipalib.install.kinit import kinit_keytab
+from ipapython.dn import DN
 from ipapython import ipautil
 
 from ipaserver.install import installutils
@@ -31,12 +32,14 @@ from ipaserver.install.installutils import create_replica_config
 from ipaserver.install.installutils import check_creds, ReplicaConfig
 from ipaserver.install import dsinstance, ca
 from ipaserver.install import cainstance, service
+from ipaserver.install import krainstance
 from ipapython import version
-from ipalib import api
+from ipalib import api, errors
 from ipalib.constants import DOMAIN_LEVEL_0
 from ipapython.config import IPAOptionParser
 from ipapython.ipa_log_manager import root_logger, standard_logging_setup
 from ipaplatform.paths import paths
+from ipaplatform import services
 
 log_file_name = paths.IPAREPLICA_CA_INSTALL_LOG
 REPLICA_INFO_TOP_DIR = None
@@ -44,6 +47,8 @@ REPLICA_INFO_TOP_DIR = None
 def parse_options():
     usage = "%prog [options] REPLICA_FILE"
     parser = IPAOptionParser(usage=usage, version=version.VERSION)
+    parser.add_option("--uninstall", dest="uninstall", action="store_true",
+                      default=False, help="uninstall the CA")
     parser.add_option("-d", "--debug", dest="debug", action="store_true",
                       default=False, help="gather extra debugging information")
     parser.add_option("-p", "--password", dest="password", sensitive=True,
@@ -254,6 +259,67 @@ def install(safe_options, options, filename):
                 pass
 
 
+def uninstall(options):
+    # Uninstaller meant only for blown replica installations.
+
+    # Does NOT remove replication agreements or the ipaca backend.
+
+    ca_instance = cainstance.CAInstance(api.env.realm)
+
+    if not cainstance.is_ca_installed_locally():
+        ca_instance.print_msg(
+            "CA does not appear to be installed on this host."
+        )
+
+    kra = krainstance.KRAInstance(api.env.realm)
+    if kra.is_installed():
+        sys.exit("Cannot deal with KRA at this time.")
+
+    if options.unattended:
+        ca_instance.print_msg(
+            "Ignoring unattended uninstall request.\n"
+        )
+    ca_instance.print_msg(
+        "This is for failed installs only, do not use otherwise."
+    )
+    if not ipautil.user_input("Are you sure you want to continue with the "
+                      "uninstall procedure?", False):
+        ca_instance.print_msg("Aborting uninstall operation.")
+        sys.exit(0)
+
+    # Note that I'm completely ignoring the replication agreement so it
+    # doesn't matter what domain level this is. This is based on the
+    # (bad) assumption that this is only being executed to fix a blown
+    # install and not to remove the CA as a component.
+
+    # TODO: Figure out what is going on with serial # ranges
+
+    ca_instance.print_msg("Shutting down CA")
+    ca_instance.stop_instance()
+
+    try:
+        ca.uninstall()
+    except Exception as e:
+        root_logger.debug("CA uninstall failed with %s", e)
+
+    # certmonger is stopped as a side-effect of unintalling the CA
+    cmonger = services.knownservices.certmonger
+    cmonger.start()
+
+    ca_instance.print_msg("Removing CA from list of services")
+    dn = DN(('cn', 'CA'), ('cn', api.env.host), ('cn', 'masters'),
+            ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
+    try:
+        api.Backend.ldap2.delete(dn)
+    except errors.NotFound:
+        pass
+
+    # Remove the old services list file so pki-tomcatd isn't managed
+    installutils.remove_file(paths.SVC_LIST_FILE)
+
+    sys.exit(0)
+
+
 def promote(safe_options, options, filename):
     options.promote = True
 
@@ -282,6 +348,7 @@ def main():
         sys.exit("IPA server is not configured on this system.\n")
 
     if (not options.external_cert_files and
+            not options.uninstall and
             cainstance.is_ca_installed_locally()):
         sys.exit("CA is already installed on this host.")
 
@@ -299,6 +366,9 @@ def main():
     api.finalize()
     api.Backend.ldap2.connect()
 
+    if options.uninstall:
+        uninstall(options)
+
     domain_level = dsinstance.get_domain_level(api)
     if domain_level > DOMAIN_LEVEL_0:
         promote(safe_options, options, filename)
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index d72feb8..169f566 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -1160,7 +1160,10 @@ def __create_ds_db(self):
         )
         entry['nsslapd-state'] = ['Backend']
         entry['nsslapd-backend'] = [backend]
-        api.Backend.ldap2.add_entry(entry)
+        try:
+            api.Backend.ldap2.add_entry(entry)
+        except errors.DuplicateEntry:
+            pass
 
         # database
         dn = DN(('cn', 'ipaca'), ('cn', 'ldbm database'), ('cn', 'plugins'),
@@ -1171,7 +1174,10 @@ def __create_ds_db(self):
             cn=[backend],
         )
         entry['nsslapd-suffix'] = [suffix]
-        api.Backend.ldap2.add_entry(entry)
+        try:
+            api.Backend.ldap2.add_entry(entry)
+        except errors.DuplicateEntry:
+            pass
 
     def __setup_replication(self):
 
-- 
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