Revision a6c43c02 lib/cmdlib/cluster.py

b/lib/cmdlib/cluster.py
21 21

  
22 22
"""Logical units dealing with the cluster."""
23 23

  
24
import OpenSSL
25

  
26 24
import copy
27 25
import itertools
28 26
import logging
......
1484 1482
  """
1485 1483

  
1486 1484
  ETYPE_FIELD = "code"
1487
  ETYPE_ERROR = "ERROR"
1488
  ETYPE_WARNING = "WARNING"
1485
  ETYPE_ERROR = constants.CV_ERROR
1486
  ETYPE_WARNING = constants.CV_WARNING
1489 1487

  
1490 1488
  def _Error(self, ecode, item, msg, *args, **kwargs):
1491 1489
    """Format an error message.
......
1529 1527
      self._Error(*args, **kwargs)
1530 1528

  
1531 1529

  
1532
def _VerifyCertificate(filename):
1533
  """Verifies a certificate for L{LUClusterVerifyConfig}.
1534

  
1535
  @type filename: string
1536
  @param filename: Path to PEM file
1537

  
1538
  """
1539
  try:
1540
    cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
1541
                                           utils.ReadFile(filename))
1542
  except Exception, err: # pylint: disable=W0703
1543
    return (LUClusterVerifyConfig.ETYPE_ERROR,
1544
            "Failed to load X509 certificate %s: %s" % (filename, err))
1545

  
1546
  (errcode, msg) = \
1547
    utils.VerifyX509Certificate(cert, constants.SSL_CERT_EXPIRATION_WARN,
1548
                                constants.SSL_CERT_EXPIRATION_ERROR)
1549

  
1550
  if msg:
1551
    fnamemsg = "While verifying %s: %s" % (filename, msg)
1552
  else:
1553
    fnamemsg = None
1554

  
1555
  if errcode is None:
1556
    return (None, fnamemsg)
1557
  elif errcode == utils.CERT_WARNING:
1558
    return (LUClusterVerifyConfig.ETYPE_WARNING, fnamemsg)
1559
  elif errcode == utils.CERT_ERROR:
1560
    return (LUClusterVerifyConfig.ETYPE_ERROR, fnamemsg)
1561

  
1562
  raise errors.ProgrammerError("Unhandled certificate error code %r" % errcode)
1563

  
1564

  
1565 1530
def _GetAllHypervisorParameters(cluster, instances):
1566 1531
  """Compute the set of all hypervisor parameters.
1567 1532

  
......
1642 1607
    feedback_fn("* Verifying cluster certificate files")
1643 1608

  
1644 1609
    for cert_filename in pathutils.ALL_CERT_FILES:
1645
      (errcode, msg) = _VerifyCertificate(cert_filename)
1610
      (errcode, msg) = utils.VerifyCertificate(cert_filename)
1646 1611
      self._ErrorIf(errcode, constants.CV_ECLUSTERCERT, None, msg, code=errcode)
1647 1612

  
1648 1613
    self._ErrorIf(not utils.CanRead(constants.LUXID_USER,
......
2328 2293
                      " should node %s fail (%dMiB needed, %dMiB available)",
2329 2294
                      self.cfg.GetNodeName(prinode), needed_mem, n_img.mfree)
2330 2295

  
2296
  def _VerifyClientCertificates(self, nodes, all_nvinfo):
2297
    """Verifies the consistency of the client certificates.
2298

  
2299
    This includes several aspects:
2300
      - the individual validation of all nodes' certificates
2301
      - the consistency of the master candidate certificate map
2302
      - the consistency of the master candidate certificate map with the
2303
        certificates that the master candidates are actually using.
2304

  
2305
    @param nodes: the list of nodes to consider in this verification
2306
    @param all_nvinfo: the map of results of the verify_node call to
2307
      all nodes
2308

  
2309
    """
2310
    candidate_certs = self.cfg.GetClusterInfo().candidate_certs
2311
    if candidate_certs is None or len(candidate_certs) == 0:
2312
      self._ErrorIf(
2313
        True, constants.CV_ECLUSTERCLIENTCERT, None,
2314
        "The cluster's list of master candidate certificates is empty."
2315
        "If you just updated the cluster, please run"
2316
        " 'gnt-cluster renew-crypto --new-node-certificates'.")
2317
      return
2318

  
2319
    self._ErrorIf(
2320
      len(candidate_certs) != len(set(candidate_certs.values())),
2321
      constants.CV_ECLUSTERCLIENTCERT, None,
2322
      "There are at least two master candidates configured to use the same"
2323
      " certificate.")
2324

  
2325
    # collect the client certificate
2326
    for node in nodes:
2327
      if node.offline:
2328
        continue
2329

  
2330
      nresult = all_nvinfo[node.uuid]
2331
      if nresult.fail_msg or not nresult.payload:
2332
        continue
2333

  
2334
      (errcode, msg) = nresult.payload.get(constants.NV_CLIENT_CERT, None)
2335

  
2336
      self._ErrorIf(
2337
        errcode is not None, constants.CV_ECLUSTERCLIENTCERT, None,
2338
        "Client certificate of node '%s' failed validation: %s (code '%s')",
2339
        node.uuid, msg, errcode)
2340

  
2341
      if not errcode:
2342
        digest = msg
2343
        if node.master_candidate:
2344
          if node.uuid in candidate_certs:
2345
            self._ErrorIf(
2346
              digest != candidate_certs[node.uuid],
2347
              constants.CV_ECLUSTERCLIENTCERT, None,
2348
              "Client certificate digest of master candidate '%s' does not"
2349
              " match its entry in the cluster's map of master candidate"
2350
              " certificates. Expected: %s Got: %s", node.uuid,
2351
              digest, candidate_certs[node.uuid])
2352
          else:
2353
            self._ErrorIf(
2354
              True, constants.CV_ECLUSTERCLIENTCERT, None,
2355
              "The master candidate '%s' does not have an entry in the"
2356
              " map of candidate certificates.", node.uuid)
2357
            self._ErrorIf(
2358
              digest in candidate_certs.values(),
2359
              constants.CV_ECLUSTERCLIENTCERT, None,
2360
              "Master candidate '%s' is using a certificate of another node.",
2361
              node.uuid)
2362
        else:
2363
          self._ErrorIf(
2364
            node.uuid in candidate_certs,
2365
            constants.CV_ECLUSTERCLIENTCERT, None,
2366
            "Node '%s' is not a master candidate, but still listed in the"
2367
            " map of master candidate certificates.", node.uuid)
2368
          self._ErrorIf(
2369
            (node.uuid not in candidate_certs) and
2370
              (digest in candidate_certs.values()),
2371
            constants.CV_ECLUSTERCLIENTCERT, None,
2372
            "Node '%s' is not a master candidate and is incorrectly using a"
2373
            " certificate of another node which is master candidate.",
2374
            node.uuid)
2375

  
2331 2376
  def _VerifyFiles(self, nodes, master_node_uuid, all_nvinfo,
2332 2377
                   (files_all, files_opt, files_mc, files_vm)):
2333 2378
    """Verifies file checksums collected from all nodes.
......
2371 2416
      if nresult.fail_msg or not nresult.payload:
2372 2417
        node_files = None
2373 2418
      else:
2374
        fingerprints = nresult.payload.get(constants.NV_FILELIST, None)
2419
        fingerprints = nresult.payload.get(constants.NV_FILELIST, {})
2375 2420
        node_files = dict((vcluster.LocalizeVirtualPath(key), value)
2376 2421
                          for (key, value) in fingerprints.items())
2377 2422
        del fingerprints
......
3008 3053
      constants.NV_OSLIST: None,
3009 3054
      constants.NV_VMNODES: self.cfg.GetNonVmCapableNodeList(),
3010 3055
      constants.NV_USERSCRIPTS: user_scripts,
3056
      constants.NV_CLIENT_CERT: None,
3011 3057
      }
3012 3058

  
3013 3059
    if vg_name is not None:
......
3132 3178

  
3133 3179
    feedback_fn("* Verifying configuration file consistency")
3134 3180

  
3181
    self._VerifyClientCertificates(self.my_node_info.values(), all_nvinfo)
3135 3182
    # If not all nodes are being checked, we need to make sure the master node
3136 3183
    # and a non-checked vm_capable node are in the list.
3137 3184
    absent_node_uuids = set(self.all_node_info).difference(self.my_node_info)

Also available in: Unified diff