On Wed, Jul 01, 2015 at 10:49:22AM +0200, 'Helga Velroyen' via ganeti-devel 
wrote:
This patch will handle the downgrade of the SSL setup
from 2.12 to 2.11. Essentially, all client.pem and
ssconf_master_candidates_certs files will be deleted.
This will kick the cluster in a pre-2.11 mode wrt to
SSL and result in a nagging message to re-run
'gnt-cluster renew-crypto' when as output of 'gnt-cluster
verify'.

Signed-off-by: Helga Velroyen <[email protected]>
---
lib/client/gnt_cluster.py | 33 +++++++++++++++++++++++++++++++++
lib/tools/ssl_update.py   | 45 ++++++++++++++++++++++++++++++++++++++++++++-
src/Ganeti/Constants.hs   | 14 +++++++++++++-
tools/cfgupgrade          |  5 +++++
4 files changed, 95 insertions(+), 2 deletions(-)

diff --git a/lib/client/gnt_cluster.py b/lib/client/gnt_cluster.py
index a25c130..c56e2bb 100644
--- a/lib/client/gnt_cluster.py
+++ b/lib/client/gnt_cluster.py
@@ -1071,6 +1071,7 @@ def _RenewCrypto(new_cluster_cert, new_rapi_cert, # 
pylint: disable=R0911
        constants.NDS_NODE_DAEMON_CERTIFICATE:
          utils.ReadFile(pathutils.NODED_CERT_FILE),
        constants.NDS_NODE_NAME: node_name,
+        constants.NDS_ACTION: constants.CRYPTO_ACTION_CREATE,
        }

      bootstrap.RunNodeSetupCmd(
@@ -2068,6 +2069,38 @@ def _VersionSpecificDowngrade():
  @return: True upon success
  """
  ToStdout("Performing version-specific downgrade tasks.")
+
+  nodes = ssconf.SimpleStore().GetOnlineNodeList()
+  cluster_name = ssconf.SimpleStore().GetClusterName()
+  ssh_ports = ssconf.SimpleStore().GetSshPortMap()
+
+  for node in nodes:
+    data = {
+      constants.NDS_CLUSTER_NAME: cluster_name,
+      constants.NDS_NODE_DAEMON_CERTIFICATE:
+        utils.ReadFile(pathutils.NODED_CERT_FILE),
+      constants.NDS_NODE_NAME: node,
+      constants.NDS_ACTION: constants.CRYPTO_ACTION_DELETE,
+      }
+
+    try:
+      bootstrap.RunNodeSetupCmd(
+          cluster_name,
+          node,
+          pathutils.SSL_UPDATE,
+          True, # debug
+          True, # verbose,
+          True, # use cluster key
+          False, # ask key
+          True, # strict host check
+          ssh_ports[node],
+          data)
+    except Exception as e: # pylint: disable=W0703
+      # As downgrading can fail if a node is temporarily unreachable
+      # only output the error, but do not abort the entire operation.
+      ToStderr("Downgrading SSL setup of node '%s' failed: %s." %
+               (node, e))
+
  return True


diff --git a/lib/tools/ssl_update.py b/lib/tools/ssl_update.py
index 4d17d9d..88a24ee 100644
--- a/lib/tools/ssl_update.py
+++ b/lib/tools/ssl_update.py
@@ -42,6 +42,7 @@ from ganeti import constants
from ganeti import errors
from ganeti import utils
from ganeti import ht
+from ganeti import pathutils
from ganeti.tools import common


@@ -49,6 +50,7 @@ _DATA_CHECK = ht.TStrictDict(False, True, {
  constants.NDS_CLUSTER_NAME: ht.TNonEmptyString,
  constants.NDS_NODE_DAEMON_CERTIFICATE: ht.TNonEmptyString,
  constants.NDS_NODE_NAME: ht.TNonEmptyString,
+  constants.NDS_ACTION: ht.TNonEmptyString,
  })


@@ -75,6 +77,37 @@ def ParseOptions():
  return common.VerifyOptions(parser, opts, args)


+def DeleteClientCertificate():
+  """Deleting the client certificate. This is necessary for downgrades."""
+  if os.path.exists(pathutils.NODED_CLIENT_CERT_FILE):
+    os.remove(pathutils.NODED_CLIENT_CERT_FILE)
+  else:
+    logging.debug("Trying to delete the client certificate '%s' which did not"
+                  " exist.", pathutils.NODED_CLIENT_CERT_FILE)
+
+
+def ClearMasterCandidateSsconfList():
+  """Clear the ssconf list of master candidate certs.
+
+  This is necessary when deleting the client certificates for a downgrade,
+  because otherwise the master cannot distribute the configuration to the
+  nodes via RPC during a downgrade anymore.
+
+  """
+  ssconf_file = os.path.join(
+    pathutils.DATA_DIR,
+    "%s%s" % (constants.SSCONF_FILEPREFIX,
+              constants.SS_MASTER_CANDIDATES_CERTS))
+  if os.path.exists:
+    os.remove(ssconf_file)
+  else:
+    logging.debug("Trying to delete the ssconf file '%s' which does not"
+                  " exist.", ssconf_file)
+
+
+# pylint: disable=E1103
+# This pyling message complains about 'data' as 'bool' not having a get
+# member, but obviously the type is wrongly inferred.
def Main():
  """Main routine.

@@ -92,7 +125,17 @@ def Main():
    # is the same as on this node.
    common.VerifyCertificate(data, SslSetupError)

-    common.GenerateClientCertificate(data, SslSetupError)
+    action = data.get(constants.NDS_ACTION)
+    if not action:
+      raise SslSetupError("No Action specified.")
+
+    if action == constants.CRYPTO_ACTION_CREATE:
+      common.GenerateClientCertificate(data, SslSetupError)
+    elif action == constants.CRYPTO_ACTION_DELETE:
+      DeleteClientCertificate()
+      ClearMasterCandidateSsconfList()
+    else:
+      raise SslSetupError("Unsupported action: %s." % action)

  except Exception, err: # pylint: disable=W0703
    logging.debug("Caught unhandled exception", exc_info=True)
diff --git a/src/Ganeti/Constants.hs b/src/Ganeti/Constants.hs
index 305ffc6..f525d6e 100644
--- a/src/Ganeti/Constants.hs
+++ b/src/Ganeti/Constants.hs
@@ -4388,8 +4388,17 @@ cryptoTypes = ConstantUtils.mkSet [cryptoTypeSslDigest]
cryptoActionGet :: String
cryptoActionGet = "get"

+cryptoActionCreate :: String
+cryptoActionCreate = "create"
+
+cryptoActionDelete :: String
+cryptoActionDelete = "delete"
+
cryptoActions :: FrozenSet String
-cryptoActions = ConstantUtils.mkSet [cryptoActionGet]
+cryptoActions =
+  ConstantUtils.mkSet [ cryptoActionCreate
+                      , cryptoActionGet
+                      , cryptoActionDelete]

-- Key word for master candidate cert list for bootstrapping.

@@ -4479,6 +4488,9 @@ ndsStartNodeDaemon = "start_node_daemon"
ndsNodeName :: String
ndsNodeName = "node_name"

+ndsAction :: String
+ndsAction = "action"
+
-- * VCluster related constants

vClusterEtcHosts :: String
diff --git a/tools/cfgupgrade b/tools/cfgupgrade
index 9c2775d..9131fde 100755
--- a/tools/cfgupgrade
+++ b/tools/cfgupgrade
@@ -524,6 +524,11 @@ def DowngradeCluster(config_data):
  if "max_tracked_jobs" in cluster:
    del cluster["max_tracked_jobs"]

+  if "candidate_certs" in cluster:
+    # Clear the candidate certs to make people run 'gnt-cluster renew-crypto'
+    # after a downgrade from 2.12 to 2.11.
+    cluster["candidate_certs"] = {}
+

def DowngradeGroups(config_data):
  for group in config_data["nodegroups"].values():
--
2.4.3.573.g4eafbef


LGTM, thanks

Reply via email to