Revision 4a96f1d1 lib/cmdlib.py

b/lib/cmdlib.py
8903 8903
    self.remove_instance = getattr(self.op, "remove_instance", False)
8904 8904
    self.ignore_remove_failures = getattr(self.op, "ignore_remove_failures",
8905 8905
                                          False)
8906
    self.export_mode = getattr(self.op, "mode", constants.EXPORT_MODE_LOCAL)
8907
    self.x509_key_name = getattr(self.op, "x509_key_name", None)
8908
    self.dest_x509_ca_pem = getattr(self.op, "destination_x509_ca", None)
8906 8909

  
8907 8910
    if self.remove_instance and not self.op.shutdown:
8908 8911
      raise errors.OpPrereqError("Can not remove instance without shutting it"
8909 8912
                                 " down before")
8910 8913

  
8914
    if self.export_mode not in constants.EXPORT_MODES:
8915
      raise errors.OpPrereqError("Invalid export mode %r" % self.export_mode,
8916
                                 errors.ECODE_INVAL)
8917

  
8918
    if self.export_mode == constants.EXPORT_MODE_REMOTE:
8919
      if not self.x509_key_name:
8920
        raise errors.OpPrereqError("Missing X509 key name for encryption",
8921
                                   errors.ECODE_INVAL)
8922

  
8923
      if not self.dest_x509_ca_pem:
8924
        raise errors.OpPrereqError("Missing destination X509 CA",
8925
                                   errors.ECODE_INVAL)
8926

  
8911 8927
  def ExpandNames(self):
8912 8928
    self._ExpandAndLockInstance()
8913 8929

  
8914
    # FIXME: lock only instance primary and destination node
8915
    #
8916
    # Sad but true, for now we have do lock all nodes, as we don't know where
8917
    # the previous export might be, and and in this LU we search for it and
8918
    # remove it from its current node. In the future we could fix this by:
8919
    #  - making a tasklet to search (share-lock all), then create the new one,
8920
    #    then one to remove, after
8921
    #  - removing the removal operation altogether
8922
    self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
8930
    # Lock all nodes for local exports
8931
    if self.export_mode == constants.EXPORT_MODE_LOCAL:
8932
      # FIXME: lock only instance primary and destination node
8933
      #
8934
      # Sad but true, for now we have do lock all nodes, as we don't know where
8935
      # the previous export might be, and in this LU we search for it and
8936
      # remove it from its current node. In the future we could fix this by:
8937
      #  - making a tasklet to search (share-lock all), then create the new one,
8938
      #    then one to remove, after
8939
      #  - removing the removal operation altogether
8940
      self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
8923 8941

  
8924 8942
  def DeclareLocks(self, level):
8925 8943
    """Last minute lock declaration."""
......
8932 8950

  
8933 8951
    """
8934 8952
    env = {
8953
      "EXPORT_MODE": self.export_mode,
8935 8954
      "EXPORT_NODE": self.op.target_node,
8936 8955
      "EXPORT_DO_SHUTDOWN": self.op.shutdown,
8937 8956
      "SHUTDOWN_TIMEOUT": self.shutdown_timeout,
8938 8957
      # TODO: Generic function for boolean env variables
8939 8958
      "REMOVE_INSTANCE": str(bool(self.remove_instance)),
8940 8959
      }
8960

  
8941 8961
    env.update(_BuildInstanceHookEnvByObject(self, self.instance))
8942
    nl = [self.cfg.GetMasterNode(), self.instance.primary_node,
8943
          self.op.target_node]
8962

  
8963
    nl = [self.cfg.GetMasterNode(), self.instance.primary_node]
8964

  
8965
    if self.export_mode == constants.EXPORT_MODE_LOCAL:
8966
      nl.append(self.op.target_node)
8967

  
8944 8968
    return env, nl, nl
8945 8969

  
8946 8970
  def CheckPrereq(self):
......
8950 8974

  
8951 8975
    """
8952 8976
    instance_name = self.op.instance_name
8977

  
8953 8978
    self.instance = self.cfg.GetInstanceInfo(instance_name)
8954 8979
    assert self.instance is not None, \
8955 8980
          "Cannot retrieve locked instance %s" % self.op.instance_name
8956 8981
    _CheckNodeOnline(self, self.instance.primary_node)
8957 8982

  
8958
    self.op.target_node = _ExpandNodeName(self.cfg, self.op.target_node)
8959
    self.dst_node = self.cfg.GetNodeInfo(self.op.target_node)
8960
    assert self.dst_node is not None
8983
    if self.export_mode == constants.EXPORT_MODE_LOCAL:
8984
      self.op.target_node = _ExpandNodeName(self.cfg, self.op.target_node)
8985
      self.dst_node = self.cfg.GetNodeInfo(self.op.target_node)
8986
      assert self.dst_node is not None
8987

  
8988
      _CheckNodeOnline(self, self.dst_node.name)
8989
      _CheckNodeNotDrained(self, self.dst_node.name)
8990

  
8991
      self._cds = None
8992
      self.dest_x509_ca = None
8993

  
8994
    elif self.export_mode == constants.EXPORT_MODE_REMOTE:
8995
      self.dst_node = None
8996

  
8997
      if len(self.op.target_node) != len(self.instance.disks):
8998
        raise errors.OpPrereqError(("Received destination information for %s"
8999
                                    " disks, but instance %s has %s disks") %
9000
                                   (len(self.op.target_node), instance_name,
9001
                                    len(self.instance.disks)),
9002
                                   errors.ECODE_INVAL)
9003

  
9004
      cds = _GetClusterDomainSecret()
9005

  
9006
      # Check X509 key name
9007
      try:
9008
        (key_name, hmac_digest, hmac_salt) = self.x509_key_name
9009
      except (TypeError, ValueError), err:
9010
        raise errors.OpPrereqError("Invalid data for X509 key name: %s" % err)
8961 9011

  
8962
    _CheckNodeOnline(self, self.dst_node.name)
8963
    _CheckNodeNotDrained(self, self.dst_node.name)
9012
      if not utils.VerifySha1Hmac(cds, key_name, hmac_digest, salt=hmac_salt):
9013
        raise errors.OpPrereqError("HMAC for X509 key name is wrong",
9014
                                   errors.ECODE_INVAL)
9015

  
9016
      # Load and verify CA
9017
      try:
9018
        (cert, _) = utils.LoadSignedX509Certificate(self.dest_x509_ca_pem, cds)
9019
      except OpenSSL.crypto.Error, err:
9020
        raise errors.OpPrereqError("Unable to load destination X509 CA (%s)" %
9021
                                   (err, ), errors.ECODE_INVAL)
9022

  
9023
      (errcode, msg) = utils.VerifyX509Certificate(cert, None, None)
9024
      if errcode is not None:
9025
        raise errors.OpPrereqError("Invalid destination X509 CA (%s)" % (msg, ),
9026
                                   errors.ECODE_INVAL)
9027

  
9028
      self.dest_x509_ca = cert
9029

  
9030
      # Verify target information
9031
      for idx, disk_data in enumerate(self.op.target_node):
9032
        try:
9033
          masterd.instance.CheckRemoteExportDiskInfo(cds, idx, disk_data)
9034
        except errors.GenericError, err:
9035
          raise errors.OpPrereqError("Target info for disk %s: %s" % (idx, err),
9036
                                     errors.ECODE_INVAL)
9037

  
9038
    else:
9039
      raise errors.ProgrammerError("Unhandled export mode %r" %
9040
                                   self.export_mode)
8964 9041

  
8965 9042
    # instance disk type verification
8966 9043
    # TODO: Implement export support for file-based disks
......
8976 9053
    exports will be removed from the nodes A, B and D.
8977 9054

  
8978 9055
    """
9056
    assert self.export_mode != constants.EXPORT_MODE_REMOTE
9057

  
8979 9058
    nodelist = self.cfg.GetNodeList()
8980 9059
    nodelist.remove(self.dst_node.name)
8981 9060

  
......
8999 9078
    """Export an instance to an image in the cluster.
9000 9079

  
9001 9080
    """
9081
    assert self.export_mode in constants.EXPORT_MODES
9082

  
9002 9083
    instance = self.instance
9003 9084
    src_node = instance.primary_node
9004 9085

  
......
9029 9110

  
9030 9111
      helper.CreateSnapshots()
9031 9112
      try:
9032
        (fin_resu, dresults) = helper.LocalExport(self.dst_node)
9113
        if self.export_mode == constants.EXPORT_MODE_LOCAL:
9114
          (fin_resu, dresults) = helper.LocalExport(self.dst_node)
9115
        elif self.export_mode == constants.EXPORT_MODE_REMOTE:
9116
          connect_timeout = constants.RIE_CONNECT_TIMEOUT
9117
          timeouts = masterd.instance.ImportExportTimeouts(connect_timeout)
9118

  
9119
          (key_name, _, _) = self.x509_key_name
9120
          (fin_resu, dresults) = helper.RemoteExport(key_name,
9121
                                                     self.dest_x509_ca,
9122
                                                     self.op.target_node,
9123
                                                     timeouts)
9033 9124
      finally:
9034 9125
        helper.Cleanup()
9035 9126

  
......
9053 9144
        _RemoveInstance(self, feedback_fn, instance,
9054 9145
                        self.ignore_remove_failures)
9055 9146

  
9056
    self._CleanupExports(feedback_fn)
9147
    if self.export_mode == constants.EXPORT_MODE_LOCAL:
9148
      self._CleanupExports(feedback_fn)
9057 9149

  
9058 9150
    return fin_resu, dresults
9059 9151

  

Also available in: Unified diff