"MAINTAIN_NODE_HEALTH_OPT",
"MASTER_NETDEV_OPT",
"MC_OPT",
+ "MIGRATION_TYPE_OPT",
"NET_OPT",
"NEW_CLUSTER_CERT_OPT",
"NEW_CLUSTER_DOMAIN_SECRET_OPT",
" freeze the instance, save the state, transfer and"
" only then resume running on the secondary node)")
+MIGRATION_TYPE_OPT = cli_option("--migration-type", dest="migration_type",
+ default=None,
+ choices=list(constants.HT_MIGRATION_TYPES),
+ help="Override default migration type (choose"
+ " either live or non-live")
+
NODE_PLACEMENT_OPT = cli_option("-n", "--node", dest="node",
help="Target node and optional secondary node",
metavar="<pnode>[:<snode>]",
#: a required node name (for single-node LUs)
_PNodeName = ("node_name", _NoDefault, _TNonEmptyString)
+#: the migration type (live/non-live)
+_PMigrationLive = ("live", None, _TOr(_TNone,
+ _TElemOf(constants.HT_MIGRATION_TYPES)))
+
# End types
class LogicalUnit(object):
HTYPE = constants.HTYPE_INSTANCE
_OP_PARAMS = [
_PInstanceName,
- ("live", True, _TBool),
+ _PMigrationLive,
("cleanup", False, _TBool),
]
self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
self._migrater = TLMigrateInstance(self, self.op.instance_name,
- self.op.live, self.op.cleanup)
+ self.op.cleanup)
self.tasklets = [self._migrater]
def DeclareLocks(self, level):
HTYPE = constants.HTYPE_NODE
_OP_PARAMS = [
_PNodeName,
- ("live", False, _TBool),
+ _PMigrationLive,
]
REQ_BGL = False
logging.debug("Migrating instance %s", inst.name)
names.append(inst.name)
- tasklets.append(TLMigrateInstance(self, inst.name, self.op.live, False))
+ tasklets.append(TLMigrateInstance(self, inst.name, False))
self.tasklets = tasklets
class TLMigrateInstance(Tasklet):
- def __init__(self, lu, instance_name, live, cleanup):
+ def __init__(self, lu, instance_name, cleanup):
"""Initializes this class.
"""
# Parameters
self.instance_name = instance_name
- self.live = live
self.cleanup = cleanup
+ self.live = False # will be overridden later
def CheckPrereq(self):
"""Check prerequisites.
self.instance = instance
+ if self.lu.op.live is None:
+ # read the default value from the hypervisor
+ i_hv = self.cfg.GetClusterInfo().FillHV(instance, skip_globals=False)
+ self.lu.op.live = i_hv[constants.HV_MIGRATION_TYPE]
+
+ self.live = self.lu.op.live == constants.HT_MIGRATION_LIVE
+
def _WaitUntilSync(self):
"""Poll with custom rpc for disk sync.
HV_MIGRATION_PORT = "migration_port"
HV_MIGRATION_BANDWIDTH = "migration_bandwidth"
HV_MIGRATION_DOWNTIME = "migration_downtime"
+HV_MIGRATION_TYPE = "migration_type"
HV_USE_LOCALTIME = "use_localtime"
HV_DISK_CACHE = "disk_cache"
HV_SECURITY_MODEL = "security_model"
HV_MIGRATION_PORT: VTYPE_INT,
HV_MIGRATION_BANDWIDTH: VTYPE_INT,
HV_MIGRATION_DOWNTIME: VTYPE_INT,
+ HV_MIGRATION_TYPE: VTYPE_STRING,
HV_USE_LOCALTIME: VTYPE_BOOL,
HV_DISK_CACHE: VTYPE_STRING,
HV_SECURITY_MODEL: VTYPE_STRING,
HT_KVM_FLAG_VALUES = frozenset([HT_KVM_ENABLED, HT_KVM_DISABLED])
+# Migration type
+HT_MIGRATION_LIVE = "live"
+HT_MIGRATION_NONLIVE = "non-live"
+HT_MIGRATION_TYPES = frozenset([HT_MIGRATION_LIVE, HT_MIGRATION_NONLIVE])
+
# Cluster Verify steps
VERIFY_NPLUSONE_MEM = 'nplusone_mem'
VERIFY_OPTIONAL_CHECKS = frozenset([VERIFY_NPLUSONE_MEM])
HV_ROOT_PATH: '/dev/sda1',
HV_KERNEL_ARGS: 'ro',
HV_MIGRATION_PORT: 8002,
+ HV_MIGRATION_TYPE: HT_MIGRATION_LIVE,
},
HT_XEN_HVM: {
HV_BOOT_ORDER: "cd",
HV_KERNEL_PATH: "/usr/lib/xen/boot/hvmloader",
HV_DEVICE_MODEL: "/usr/lib/xen/bin/qemu-dm",
HV_MIGRATION_PORT: 8002,
+ HV_MIGRATION_TYPE: HT_MIGRATION_NONLIVE,
HV_USE_LOCALTIME: False,
},
HT_KVM: {
HV_MIGRATION_PORT: 8102,
HV_MIGRATION_BANDWIDTH: 32, # MiB/s
HV_MIGRATION_DOWNTIME: 30, # ms
+ HV_MIGRATION_TYPE: HT_MIGRATION_LIVE,
HV_USE_LOCALTIME: False,
HV_DISK_CACHE: HT_CACHE_DEFAULT,
HV_SECURITY_MODEL: HT_SM_NONE,
HVC_GLOBALS = frozenset([
HV_MIGRATION_PORT,
HV_MIGRATION_BANDWIDTH,
+ HV_MIGRATION_TYPE,
])
BEC_DEFAULTS = {
from ganeti import errors
from ganeti import utils
+from ganeti import constants
# Read the BaseHypervisor.PARAMETERS docstring for the syntax of the
# required, but no other checks
REQUIRED_CHECK = (True, None, None, None, None)
+# migration type
+MIGRATION_TYPE_CHECK = (True, lambda x: x in constants.HT_MIGRATION_TYPES,
+ "invalid migration type", None, None)
+
def ParamInSet(required, my_set):
"""Builds parameter checker for set membership.
constants.HV_MIGRATION_PORT: hv_base.NET_PORT_CHECK,
constants.HV_MIGRATION_BANDWIDTH: hv_base.NO_CHECK,
constants.HV_MIGRATION_DOWNTIME: hv_base.NO_CHECK,
+ constants.HV_MIGRATION_TYPE: hv_base.MIGRATION_TYPE_CHECK,
constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
constants.HV_DISK_CACHE:
hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
constants.HV_ROOT_PATH: hv_base.REQUIRED_CHECK,
constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
constants.HV_MIGRATION_PORT: hv_base.NET_PORT_CHECK,
+ constants.HV_MIGRATION_TYPE: hv_base.MIGRATION_TYPE_CHECK,
}
@classmethod
constants.HV_DEVICE_MODEL: hv_base.REQ_FILE_CHECK,
constants.HV_VNC_PASSWORD_FILE: hv_base.REQ_FILE_CHECK,
constants.HV_MIGRATION_PORT: hv_base.NET_PORT_CHECK,
+ constants.HV_MIGRATION_TYPE: hv_base.MIGRATION_TYPE_CHECK,
constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
}
<command>migrate</command>
<arg>-f</arg>
<arg>--non-live</arg>
+ <arg>--migration-type=live|non-live</arg>
<arg choice="req"><replaceable>instance</replaceable></arg>
</cmdsynopsis>
</para>
<para>
- The <option>--non-live</option> option will switch (for the
- hypervisors that support it) between a "fully live"
- (i.e. the interruption is as minimal as possible) migration
- and one in which the instance is frozen, its state saved and
- transported to the remote node, and then resumed there. This
- all depends on the hypervisor support for two different
- methods. In any case, it is not an error to pass this
- parameter (it will just be ignored if the hypervisor doesn't
- support it).
+ The <option>--non-live</option>
+ and <option>--migration-type=non-live</option> options will
+ switch (for the hypervisors that support it) between a
+ "fully live" (i.e. the interruption is as minimal as
+ possible) migration and one in which the instance is frozen,
+ its state saved and transported to the remote node, and then
+ resumed there. This all depends on the hypervisor support
+ for two different methods. In any case, it is not an error
+ to pass this parameter (it will just be ignored if the
+ hypervisor doesn't support it). The
+ option <option>--migration-type=live</option> option will
+ request a fully-live migration. The default, when neither
+ option is passed, depends on the hypervisor parameters (and
+ can be viewed with the <command>gnt-cluster info</command>
+ command).
</para>
<para>
<command>migrate</command>
<arg>-f</arg>
<arg>--non-live</arg>
+ <arg>--migration-type=live|non-live</arg>
<arg choice="req"><replaceable>node</replaceable></arg>
</cmdsynopsis>
<para>
As for the <command>gnt-instance migrate</command> command,
- the <option>--no-live</option> option can be given to do a
- non-live migration.
+ the options <option>--no-live</option>
+ and <option>--migration-type</option> can be given to
+ influence the migration type.
</para>
<para>
if not AskUser(usertext):
return 1
- op = opcodes.OpMigrateInstance(instance_name=instance_name, live=opts.live,
+ # this should be removed once --non-live is deprecated
+ if not opts.live and opts.migration_type is not None:
+ raise errors.OpPrereqError("Only one of the --non-live and "
+ "--migration-type options can be passed",
+ errors.ECODE_INVAL)
+ if not opts.live: # --non-live passed
+ live = constants.HT_MIGRATION_NONLIVE
+ else:
+ live = opts.migration_type
+
+ op = opcodes.OpMigrateInstance(instance_name=instance_name, live=live,
cleanup=opts.cleanup)
SubmitOpCode(op, cl=cl, opts=opts)
return 0
" using the remote mirror (only for instances of type drbd)"),
'migrate': (
MigrateInstance, ARGS_ONE_INSTANCE,
- [FORCE_OPT, NONLIVE_OPT, CLEANUP_OPT],
+ [FORCE_OPT, NONLIVE_OPT, MIGRATION_TYPE_OPT, CLEANUP_OPT],
"[-f] <instance>", "Migrate instance to its secondary node"
" (only for instances of type drbd)"),
'move': (
(",".join("'%s'" % name for name in pinst))):
return 2
- op = opcodes.OpMigrateNode(node_name=args[0], live=opts.live)
+ # this should be removed once --non-live is deprecated
+ if not opts.live and opts.migration_type is not None:
+ raise errors.OpPrereqError("Only one of the --non-live and "
+ "--migration-type options can be passed",
+ errors.ECODE_INVAL)
+ if not opts.live: # --non-live passed
+ live = constants.HT_MIGRATION_NONLIVE
+ else:
+ live = opts.migration_type
+ op = opcodes.OpMigrateNode(node_name=args[0], live=live)
SubmitOpCode(op, cl=cl, opts=opts)
"Stops the primary instances on a node and start them on their"
" secondary node (only for instances with drbd disk template)"),
'migrate': (
- MigrateNode, ARGS_ONE_NODE, [FORCE_OPT, NONLIVE_OPT],
+ MigrateNode, ARGS_ONE_NODE, [FORCE_OPT, NONLIVE_OPT, MIGRATION_TYPE_OPT],
"[-f] <node>",
"Migrate all the primary instance on a node away from it"
" (only for instances of type drbd)"),