Revision e71b9ef4
b/lib/cli.py | ||
---|---|---|
87 | 87 |
"MAINTAIN_NODE_HEALTH_OPT", |
88 | 88 |
"MASTER_NETDEV_OPT", |
89 | 89 |
"MC_OPT", |
90 |
"MIGRATION_TYPE_OPT", |
|
90 | 91 |
"NET_OPT", |
91 | 92 |
"NEW_CLUSTER_CERT_OPT", |
92 | 93 |
"NEW_CLUSTER_DOMAIN_SECRET_OPT", |
... | ... | |
698 | 699 |
" freeze the instance, save the state, transfer and" |
699 | 700 |
" only then resume running on the secondary node)") |
700 | 701 |
|
702 |
MIGRATION_TYPE_OPT = cli_option("--migration-type", dest="migration_type", |
|
703 |
default=None, |
|
704 |
choices=list(constants.HT_MIGRATION_TYPES), |
|
705 |
help="Override default migration type (choose" |
|
706 |
" either live or non-live") |
|
707 |
|
|
701 | 708 |
NODE_PLACEMENT_OPT = cli_option("-n", "--node", dest="node", |
702 | 709 |
help="Target node and optional secondary node", |
703 | 710 |
metavar="<pnode>[:<snode>]", |
b/lib/cmdlib.py | ||
---|---|---|
232 | 232 |
#: a required node name (for single-node LUs) |
233 | 233 |
_PNodeName = ("node_name", _NoDefault, _TNonEmptyString) |
234 | 234 |
|
235 |
#: the migration type (live/non-live) |
|
236 |
_PMigrationLive = ("live", None, _TOr(_TNone, |
|
237 |
_TElemOf(constants.HT_MIGRATION_TYPES))) |
|
238 |
|
|
235 | 239 |
|
236 | 240 |
# End types |
237 | 241 |
class LogicalUnit(object): |
... | ... | |
5486 | 5490 |
HTYPE = constants.HTYPE_INSTANCE |
5487 | 5491 |
_OP_PARAMS = [ |
5488 | 5492 |
_PInstanceName, |
5489 |
("live", True, _TBool),
|
|
5493 |
_PMigrationLive,
|
|
5490 | 5494 |
("cleanup", False, _TBool), |
5491 | 5495 |
] |
5492 | 5496 |
|
... | ... | |
5499 | 5503 |
self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE |
5500 | 5504 |
|
5501 | 5505 |
self._migrater = TLMigrateInstance(self, self.op.instance_name, |
5502 |
self.op.live, self.op.cleanup)
|
|
5506 |
self.op.cleanup) |
|
5503 | 5507 |
self.tasklets = [self._migrater] |
5504 | 5508 |
|
5505 | 5509 |
def DeclareLocks(self, level): |
... | ... | |
5717 | 5721 |
HTYPE = constants.HTYPE_NODE |
5718 | 5722 |
_OP_PARAMS = [ |
5719 | 5723 |
_PNodeName, |
5720 |
("live", False, _TBool),
|
|
5724 |
_PMigrationLive,
|
|
5721 | 5725 |
] |
5722 | 5726 |
REQ_BGL = False |
5723 | 5727 |
|
... | ... | |
5738 | 5742 |
logging.debug("Migrating instance %s", inst.name) |
5739 | 5743 |
names.append(inst.name) |
5740 | 5744 |
|
5741 |
tasklets.append(TLMigrateInstance(self, inst.name, self.op.live, False))
|
|
5745 |
tasklets.append(TLMigrateInstance(self, inst.name, False)) |
|
5742 | 5746 |
|
5743 | 5747 |
self.tasklets = tasklets |
5744 | 5748 |
|
... | ... | |
5765 | 5769 |
|
5766 | 5770 |
|
5767 | 5771 |
class TLMigrateInstance(Tasklet): |
5768 |
def __init__(self, lu, instance_name, live, cleanup):
|
|
5772 |
def __init__(self, lu, instance_name, cleanup): |
|
5769 | 5773 |
"""Initializes this class. |
5770 | 5774 |
|
5771 | 5775 |
""" |
... | ... | |
5773 | 5777 |
|
5774 | 5778 |
# Parameters |
5775 | 5779 |
self.instance_name = instance_name |
5776 |
self.live = live |
|
5777 | 5780 |
self.cleanup = cleanup |
5781 |
self.live = False # will be overridden later |
|
5778 | 5782 |
|
5779 | 5783 |
def CheckPrereq(self): |
5780 | 5784 |
"""Check prerequisites. |
... | ... | |
5815 | 5819 |
|
5816 | 5820 |
self.instance = instance |
5817 | 5821 |
|
5822 |
if self.lu.op.live is None: |
|
5823 |
# read the default value from the hypervisor |
|
5824 |
i_hv = self.cfg.GetClusterInfo().FillHV(instance, skip_globals=False) |
|
5825 |
self.lu.op.live = i_hv[constants.HV_MIGRATION_TYPE] |
|
5826 |
|
|
5827 |
self.live = self.lu.op.live == constants.HT_MIGRATION_LIVE |
|
5828 |
|
|
5818 | 5829 |
def _WaitUntilSync(self): |
5819 | 5830 |
"""Poll with custom rpc for disk sync. |
5820 | 5831 |
|
b/lib/constants.py | ||
---|---|---|
537 | 537 |
HV_MIGRATION_PORT = "migration_port" |
538 | 538 |
HV_MIGRATION_BANDWIDTH = "migration_bandwidth" |
539 | 539 |
HV_MIGRATION_DOWNTIME = "migration_downtime" |
540 |
HV_MIGRATION_TYPE = "migration_type" |
|
540 | 541 |
HV_USE_LOCALTIME = "use_localtime" |
541 | 542 |
HV_DISK_CACHE = "disk_cache" |
542 | 543 |
HV_SECURITY_MODEL = "security_model" |
... | ... | |
571 | 572 |
HV_MIGRATION_PORT: VTYPE_INT, |
572 | 573 |
HV_MIGRATION_BANDWIDTH: VTYPE_INT, |
573 | 574 |
HV_MIGRATION_DOWNTIME: VTYPE_INT, |
575 |
HV_MIGRATION_TYPE: VTYPE_STRING, |
|
574 | 576 |
HV_USE_LOCALTIME: VTYPE_BOOL, |
575 | 577 |
HV_DISK_CACHE: VTYPE_STRING, |
576 | 578 |
HV_SECURITY_MODEL: VTYPE_STRING, |
... | ... | |
717 | 719 |
|
718 | 720 |
HT_KVM_FLAG_VALUES = frozenset([HT_KVM_ENABLED, HT_KVM_DISABLED]) |
719 | 721 |
|
722 |
# Migration type |
|
723 |
HT_MIGRATION_LIVE = "live" |
|
724 |
HT_MIGRATION_NONLIVE = "non-live" |
|
725 |
HT_MIGRATION_TYPES = frozenset([HT_MIGRATION_LIVE, HT_MIGRATION_NONLIVE]) |
|
726 |
|
|
720 | 727 |
# Cluster Verify steps |
721 | 728 |
VERIFY_NPLUSONE_MEM = 'nplusone_mem' |
722 | 729 |
VERIFY_OPTIONAL_CHECKS = frozenset([VERIFY_NPLUSONE_MEM]) |
... | ... | |
859 | 866 |
HV_ROOT_PATH: '/dev/sda1', |
860 | 867 |
HV_KERNEL_ARGS: 'ro', |
861 | 868 |
HV_MIGRATION_PORT: 8002, |
869 |
HV_MIGRATION_TYPE: HT_MIGRATION_LIVE, |
|
862 | 870 |
}, |
863 | 871 |
HT_XEN_HVM: { |
864 | 872 |
HV_BOOT_ORDER: "cd", |
... | ... | |
872 | 880 |
HV_KERNEL_PATH: "/usr/lib/xen/boot/hvmloader", |
873 | 881 |
HV_DEVICE_MODEL: "/usr/lib/xen/bin/qemu-dm", |
874 | 882 |
HV_MIGRATION_PORT: 8002, |
883 |
HV_MIGRATION_TYPE: HT_MIGRATION_NONLIVE, |
|
875 | 884 |
HV_USE_LOCALTIME: False, |
876 | 885 |
}, |
877 | 886 |
HT_KVM: { |
... | ... | |
894 | 903 |
HV_MIGRATION_PORT: 8102, |
895 | 904 |
HV_MIGRATION_BANDWIDTH: 32, # MiB/s |
896 | 905 |
HV_MIGRATION_DOWNTIME: 30, # ms |
906 |
HV_MIGRATION_TYPE: HT_MIGRATION_LIVE, |
|
897 | 907 |
HV_USE_LOCALTIME: False, |
898 | 908 |
HV_DISK_CACHE: HT_CACHE_DEFAULT, |
899 | 909 |
HV_SECURITY_MODEL: HT_SM_NONE, |
... | ... | |
914 | 924 |
HVC_GLOBALS = frozenset([ |
915 | 925 |
HV_MIGRATION_PORT, |
916 | 926 |
HV_MIGRATION_BANDWIDTH, |
927 |
HV_MIGRATION_TYPE, |
|
917 | 928 |
]) |
918 | 929 |
|
919 | 930 |
BEC_DEFAULTS = { |
b/lib/hypervisor/hv_base.py | ||
---|---|---|
44 | 44 |
|
45 | 45 |
from ganeti import errors |
46 | 46 |
from ganeti import utils |
47 |
from ganeti import constants |
|
47 | 48 |
|
48 | 49 |
|
49 | 50 |
# Read the BaseHypervisor.PARAMETERS docstring for the syntax of the |
... | ... | |
71 | 72 |
# required, but no other checks |
72 | 73 |
REQUIRED_CHECK = (True, None, None, None, None) |
73 | 74 |
|
75 |
# migration type |
|
76 |
MIGRATION_TYPE_CHECK = (True, lambda x: x in constants.HT_MIGRATION_TYPES, |
|
77 |
"invalid migration type", None, None) |
|
78 |
|
|
74 | 79 |
|
75 | 80 |
def ParamInSet(required, my_set): |
76 | 81 |
"""Builds parameter checker for set membership. |
b/lib/hypervisor/hv_kvm.py | ||
---|---|---|
194 | 194 |
constants.HV_MIGRATION_PORT: hv_base.NET_PORT_CHECK, |
195 | 195 |
constants.HV_MIGRATION_BANDWIDTH: hv_base.NO_CHECK, |
196 | 196 |
constants.HV_MIGRATION_DOWNTIME: hv_base.NO_CHECK, |
197 |
constants.HV_MIGRATION_TYPE: hv_base.MIGRATION_TYPE_CHECK, |
|
197 | 198 |
constants.HV_USE_LOCALTIME: hv_base.NO_CHECK, |
198 | 199 |
constants.HV_DISK_CACHE: |
199 | 200 |
hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES), |
b/lib/hypervisor/hv_xen.py | ||
---|---|---|
458 | 458 |
constants.HV_ROOT_PATH: hv_base.REQUIRED_CHECK, |
459 | 459 |
constants.HV_KERNEL_ARGS: hv_base.NO_CHECK, |
460 | 460 |
constants.HV_MIGRATION_PORT: hv_base.NET_PORT_CHECK, |
461 |
constants.HV_MIGRATION_TYPE: hv_base.MIGRATION_TYPE_CHECK, |
|
461 | 462 |
} |
462 | 463 |
|
463 | 464 |
@classmethod |
... | ... | |
556 | 557 |
constants.HV_DEVICE_MODEL: hv_base.REQ_FILE_CHECK, |
557 | 558 |
constants.HV_VNC_PASSWORD_FILE: hv_base.REQ_FILE_CHECK, |
558 | 559 |
constants.HV_MIGRATION_PORT: hv_base.NET_PORT_CHECK, |
560 |
constants.HV_MIGRATION_TYPE: hv_base.MIGRATION_TYPE_CHECK, |
|
559 | 561 |
constants.HV_USE_LOCALTIME: hv_base.NO_CHECK, |
560 | 562 |
} |
561 | 563 |
|
b/man/gnt-instance.sgml | ||
---|---|---|
2389 | 2389 |
<command>migrate</command> |
2390 | 2390 |
<arg>-f</arg> |
2391 | 2391 |
<arg>--non-live</arg> |
2392 |
<arg>--migration-type=live|non-live</arg> |
|
2392 | 2393 |
<arg choice="req"><replaceable>instance</replaceable></arg> |
2393 | 2394 |
</cmdsynopsis> |
2394 | 2395 |
|
... | ... | |
2405 | 2406 |
</para> |
2406 | 2407 |
|
2407 | 2408 |
<para> |
2408 |
The <option>--non-live</option> option will switch (for the |
|
2409 |
hypervisors that support it) between a "fully live" |
|
2410 |
(i.e. the interruption is as minimal as possible) migration |
|
2411 |
and one in which the instance is frozen, its state saved and |
|
2412 |
transported to the remote node, and then resumed there. This |
|
2413 |
all depends on the hypervisor support for two different |
|
2414 |
methods. In any case, it is not an error to pass this |
|
2415 |
parameter (it will just be ignored if the hypervisor doesn't |
|
2416 |
support it). |
|
2409 |
The <option>--non-live</option> |
|
2410 |
and <option>--migration-type=non-live</option> options will |
|
2411 |
switch (for the hypervisors that support it) between a |
|
2412 |
"fully live" (i.e. the interruption is as minimal as |
|
2413 |
possible) migration and one in which the instance is frozen, |
|
2414 |
its state saved and transported to the remote node, and then |
|
2415 |
resumed there. This all depends on the hypervisor support |
|
2416 |
for two different methods. In any case, it is not an error |
|
2417 |
to pass this parameter (it will just be ignored if the |
|
2418 |
hypervisor doesn't support it). The |
|
2419 |
option <option>--migration-type=live</option> option will |
|
2420 |
request a fully-live migration. The default, when neither |
|
2421 |
option is passed, depends on the hypervisor parameters (and |
|
2422 |
can be viewed with the <command>gnt-cluster info</command> |
|
2423 |
command). |
|
2417 | 2424 |
</para> |
2418 | 2425 |
|
2419 | 2426 |
<para> |
b/man/gnt-node.sgml | ||
---|---|---|
571 | 571 |
<command>migrate</command> |
572 | 572 |
<arg>-f</arg> |
573 | 573 |
<arg>--non-live</arg> |
574 |
<arg>--migration-type=live|non-live</arg> |
|
574 | 575 |
<arg choice="req"><replaceable>node</replaceable></arg> |
575 | 576 |
</cmdsynopsis> |
576 | 577 |
|
... | ... | |
582 | 583 |
|
583 | 584 |
<para> |
584 | 585 |
As for the <command>gnt-instance migrate</command> command, |
585 |
the <option>--no-live</option> option can be given to do a |
|
586 |
non-live migration. |
|
586 |
the options <option>--no-live</option> |
|
587 |
and <option>--migration-type</option> can be given to |
|
588 |
influence the migration type. |
|
587 | 589 |
</para> |
588 | 590 |
|
589 | 591 |
<para> |
b/scripts/gnt-instance | ||
---|---|---|
897 | 897 |
if not AskUser(usertext): |
898 | 898 |
return 1 |
899 | 899 |
|
900 |
op = opcodes.OpMigrateInstance(instance_name=instance_name, live=opts.live, |
|
900 |
# this should be removed once --non-live is deprecated |
|
901 |
if not opts.live and opts.migration_type is not None: |
|
902 |
raise errors.OpPrereqError("Only one of the --non-live and " |
|
903 |
"--migration-type options can be passed", |
|
904 |
errors.ECODE_INVAL) |
|
905 |
if not opts.live: # --non-live passed |
|
906 |
live = constants.HT_MIGRATION_NONLIVE |
|
907 |
else: |
|
908 |
live = opts.migration_type |
|
909 |
|
|
910 |
op = opcodes.OpMigrateInstance(instance_name=instance_name, live=live, |
|
901 | 911 |
cleanup=opts.cleanup) |
902 | 912 |
SubmitOpCode(op, cl=cl, opts=opts) |
903 | 913 |
return 0 |
... | ... | |
1409 | 1419 |
" using the remote mirror (only for instances of type drbd)"), |
1410 | 1420 |
'migrate': ( |
1411 | 1421 |
MigrateInstance, ARGS_ONE_INSTANCE, |
1412 |
[FORCE_OPT, NONLIVE_OPT, CLEANUP_OPT], |
|
1422 |
[FORCE_OPT, NONLIVE_OPT, MIGRATION_TYPE_OPT, CLEANUP_OPT],
|
|
1413 | 1423 |
"[-f] <instance>", "Migrate instance to its secondary node" |
1414 | 1424 |
" (only for instances of type drbd)"), |
1415 | 1425 |
'move': ( |
b/scripts/gnt-node | ||
---|---|---|
360 | 360 |
(",".join("'%s'" % name for name in pinst))): |
361 | 361 |
return 2 |
362 | 362 |
|
363 |
op = opcodes.OpMigrateNode(node_name=args[0], live=opts.live) |
|
363 |
# this should be removed once --non-live is deprecated |
|
364 |
if not opts.live and opts.migration_type is not None: |
|
365 |
raise errors.OpPrereqError("Only one of the --non-live and " |
|
366 |
"--migration-type options can be passed", |
|
367 |
errors.ECODE_INVAL) |
|
368 |
if not opts.live: # --non-live passed |
|
369 |
live = constants.HT_MIGRATION_NONLIVE |
|
370 |
else: |
|
371 |
live = opts.migration_type |
|
372 |
op = opcodes.OpMigrateNode(node_name=args[0], live=live) |
|
364 | 373 |
SubmitOpCode(op, cl=cl, opts=opts) |
365 | 374 |
|
366 | 375 |
|
... | ... | |
652 | 661 |
"Stops the primary instances on a node and start them on their" |
653 | 662 |
" secondary node (only for instances with drbd disk template)"), |
654 | 663 |
'migrate': ( |
655 |
MigrateNode, ARGS_ONE_NODE, [FORCE_OPT, NONLIVE_OPT], |
|
664 |
MigrateNode, ARGS_ONE_NODE, [FORCE_OPT, NONLIVE_OPT, MIGRATION_TYPE_OPT],
|
|
656 | 665 |
"[-f] <node>", |
657 | 666 |
"Migrate all the primary instance on a node away from it" |
658 | 667 |
" (only for instances of type drbd)"), |
Also available in: Unified diff