Add tool to clean up node
authorMichael Hanselmann <hansmi@google.com>
Wed, 5 Dec 2012 15:02:11 +0000 (16:02 +0100)
committerMichael Hanselmann <hansmi@google.com>
Thu, 6 Dec 2012 15:07:21 +0000 (16:07 +0100)
Sometimes a node is not removed properly from a cluster (especially
during development). This new tool stops all daemons and removes (after
making copies) the most critical files.

Signed-off-by: Michael Hanselmann <hansmi@google.com>
Reviewed-by: Iustin Pop <iustin@google.com>

.gitignore
Makefile.am
NEWS
lib/tools/node_cleanup.py [new file with mode: 0644]
man/gnt-node.rst

index 3a65514..e9b9404 100644 (file)
@@ -95,6 +95,7 @@
 /tools/kvm-ifup
 /tools/ensure-dirs
 /tools/vcluster-setup
+/tools/node-cleanup
 /tools/node-daemon-setup
 /tools/prepare-node-join
 
index 67f469f..6c2275b 100644 (file)
@@ -332,6 +332,7 @@ server_PYTHON = \
 pytools_PYTHON = \
        lib/tools/__init__.py \
        lib/tools/ensure_dirs.py \
+       lib/tools/node_cleanup.py \
        lib/tools/node_daemon_setup.py \
        lib/tools/prepare_node_join.py
 
@@ -617,6 +618,7 @@ PYTHON_BOOTSTRAP_SBIN = \
 PYTHON_BOOTSTRAP = \
        $(PYTHON_BOOTSTRAP_SBIN) \
        tools/ensure-dirs \
+       tools/node-cleanup \
        tools/node-daemon-setup \
        tools/prepare-node-join
 
@@ -720,7 +722,11 @@ dist_tools_SCRIPTS = \
        tools/master-ip-setup \
        tools/xen-console-wrapper
 
+nodist_tools_python_scripts = \
+       tools/node-cleanup
+
 nodist_tools_SCRIPTS = \
+       $(nodist_tools_python_scripts) \
        tools/vcluster-setup
 
 pkglib_python_scripts = \
@@ -1034,6 +1040,7 @@ all_python_code = \
        $(python_scripts) \
        $(pkglib_python_scripts) \
        $(nodist_pkglib_python_scripts) \
+       $(nodist_tools_python_scripts) \
        $(python_tests) \
        $(pkgpython_PYTHON) \
        $(client_PYTHON) \
@@ -1379,6 +1386,7 @@ scripts/%: MODULE = ganeti.client.$(subst -,_,$(notdir $@))
 tools/ensure-dirs: MODULE = ganeti.tools.ensure_dirs
 tools/node-daemon-setup: MODULE = ganeti.tools.node_daemon_setup
 tools/prepare-node-join: MODULE = ganeti.tools.prepare_node_join
+tools/node-cleanup: MODULE = ganeti.tools.node_cleanup
 $(HS_BUILT_TEST_HELPERS): TESTROLE = $(patsubst htest/%,%,$@)
 
 $(PYTHON_BOOTSTRAP): Makefile | stamp-directories
diff --git a/NEWS b/NEWS
index 0e4fa66..5f07284 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -33,6 +33,10 @@ Version 2.7.0 beta1
   for RAPI users. It allows granting permissions to query for
   information to a specific user without giving
   :pyeval:`rapi.RAPI_ACCESS_WRITE` permissions.
+- A new tool named ``node-cleanup`` has been added. It cleans remains of
+  a cluster from a machine by stopping all daemons, removing
+  certificates and ssconf files. Unless the ``--no-backup`` option is
+  given, copies of the certificates are made.
 
 
 Version 2.6.1
diff --git a/lib/tools/node_cleanup.py b/lib/tools/node_cleanup.py
new file mode 100644 (file)
index 0000000..f4aa245
--- /dev/null
@@ -0,0 +1,119 @@
+#
+#
+
+# Copyright (C) 2012 Google Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+"""Script to configure the node daemon.
+
+"""
+
+import os
+import os.path
+import optparse
+import sys
+import logging
+
+from ganeti import cli
+from ganeti import constants
+from ganeti import pathutils
+from ganeti import ssconf
+from ganeti import utils
+
+
+def ParseOptions():
+  """Parses the options passed to the program.
+
+  @return: Options and arguments
+
+  """
+  parser = optparse.OptionParser(usage="%prog [--no-backup]",
+                                 prog=os.path.basename(sys.argv[0]))
+  parser.add_option(cli.DEBUG_OPT)
+  parser.add_option(cli.VERBOSE_OPT)
+  parser.add_option(cli.YES_DOIT_OPT)
+  parser.add_option("--no-backup", dest="backup", default=True,
+                    action="store_false",
+                    help="Whether to create backup copies of deleted files")
+
+  (opts, args) = parser.parse_args()
+
+  return VerifyOptions(parser, opts, args)
+
+
+def VerifyOptions(parser, opts, args):
+  """Verifies options and arguments for correctness.
+
+  """
+  if args:
+    parser.error("No arguments are expected")
+
+  return opts
+
+
+def Main():
+  """Main routine.
+
+  """
+  opts = ParseOptions()
+
+  utils.SetupToolLogging(opts.debug, opts.verbose)
+
+  try:
+    # List of files to delete. Contains tuples consisting of the absolute path
+    # and a boolean denoting whether a backup copy should be created before
+    # deleting.
+    clean_files = [
+      (pathutils.CONFD_HMAC_KEY, True),
+      (pathutils.CLUSTER_CONF_FILE, True),
+      (pathutils.CLUSTER_DOMAIN_SECRET_FILE, True),
+      ]
+    clean_files.extend(map(lambda s: (s, True), pathutils.ALL_CERT_FILES))
+    clean_files.extend(map(lambda s: (s, False),
+                           ssconf.SimpleStore().GetFileList()))
+
+    if not opts.yes_do_it:
+      cli.ToStderr("Cleaning a node is irreversible. If you really want to"
+                   " clean this node, supply the --yes-do-it option.")
+      return constants.EXIT_FAILURE
+
+    logging.info("Stopping daemons")
+    result = utils.RunCmd([pathutils.DAEMON_UTIL, "stop-all"],
+                          interactive=True)
+    if result.failed:
+      raise Exception("Could not stop daemons, command '%s' failed: %s" %
+                      (result.cmd, result.fail_reason))
+
+    for (filename, backup) in clean_files:
+      if os.path.exists(filename):
+        if opts.backup and backup:
+          logging.info("Backing up %s", filename)
+          utils.CreateBackup(filename)
+
+        logging.info("Removing %s", filename)
+        utils.RemoveFile(filename)
+
+    logging.info("Node successfully cleaned")
+  except Exception, err: # pylint: disable=W0703
+    logging.debug("Caught unhandled exception", exc_info=True)
+
+    (retcode, message) = cli.FormatError(err)
+    logging.error(message)
+
+    return retcode
+  else:
+    return constants.EXIT_SUCCESS
index d3c4052..fc423b5 100644 (file)
@@ -67,6 +67,10 @@ command fails at a later stage, it doesn't undo such changes.  This
 should not be a problem, as a successful run of ``gnt-node add`` will
 bring everything back in sync.
 
+If the node was previously part of another cluster and still has daemons
+running, the ``node-cleanup`` tool can be run on the machine to be added
+to clean remains of the previous cluster from the node.
+
 Example::
 
     # gnt-node add node5.example.com