return output
+def GetInstanceMigratable(instance):
+ """Gives whether an instance can be migrated.
+
+ @type instance: L{objects.Instance}
+ @param instance: object representing the instance to be checked.
+
+ @rtype: tuple
+ @return: tuple of (result, description) where:
+ - result: whether the instance can be migrated or not
+ - description: a description of the issue, if relevant
+
+ """
+ hyper = hypervisor.GetHypervisor(instance.hypervisor)
+ if instance.name not in hyper.ListInstances():
+ return (False, 'not running')
+
+ for idx in range(len(instance.disks)):
+ link_name = _GetBlockDevSymlinkPath(instance.name, idx)
+ if not os.path.islink(link_name):
+ return (False, 'not restarted since ganeti 1.2.5')
+
+ return (True, '')
+
+
def GetAllInstancesInfo(hypervisor_list):
"""Gather data about all instances.
return retdic
-def _SymlinkBlockDev(instance_name, device_path, device_name):
+def _GetBlockDevSymlinkPath(instance_name, idx):
+ return os.path.join(constants.DISK_LINKS_DIR,
+ "%s:%d" % (instance_name, idx))
+
+
+def _SymlinkBlockDev(instance_name, device_path, idx):
"""Set up symlinks to a instance's block device.
This is an auxiliary function run when an instance is start (on the primary
node) or when an instance is migrated (on the target node).
- Args:
- instance_name: the name of the target instance
- device_path: path of the physical block device, on the node
- device_name: 'virtual' name of the device
- Returns:
- absolute path to the disk's symlink
+ @param instance_name: the name of the target instance
+ @param device_path: path of the physical block device, on the node
+ @param idx: the disk index
+ @return: absolute path to the disk's symlink
"""
- link_basename = "%s-%s" % (instance_name, device_name)
- link_name = os.path.join(constants.DISK_LINKS_DIR, link_basename)
+ link_name = _GetBlockDevSymlinkPath(instance_name, idx)
try:
os.symlink(device_path, link_name)
- except OSError, e:
- if e.errno == errno.EEXIST:
+ except OSError, err:
+ if err.errno == errno.EEXIST:
if (not os.path.islink(link_name) or
os.readlink(link_name) != device_path):
os.remove(link_name)
return link_name
+def _RemoveBlockDevLinks(instance_name, disks):
+ """Remove the block device symlinks belonging to the given instance.
+
+ """
+ for idx, disk in enumerate(disks):
+ link_name = _GetBlockDevSymlinkPath(instance_name, idx)
+ if os.path.islink(link_name):
+ try:
+ os.remove(link_name)
+ except OSError:
+ logging.exception("Can't remove symlink '%s'", link_name)
+
+
def _GatherAndLinkBlockDevs(instance):
"""Set up an instance's block device(s).
str(disk))
device.Open()
try:
- link_name = _SymlinkBlockDev(instance.name, device.dev_path,
- "disk%d" % idx)
+ link_name = _SymlinkBlockDev(instance.name, device.dev_path, idx)
except OSError, e:
raise errors.BlockDeviceError("Cannot create block device symlink: %s" %
e.strerror)
return False
except errors.HypervisorError, err:
logging.exception("Failed to start instance")
+ _RemoveBlockDevLinks(instance.name, instance.disks)
return False
return True
instance.name)
return False
+ _RemoveBlockDevLinks(instance.name, instance.disks)
+
return True
return True
-def CloseBlockDevices(disks):
+def CloseBlockDevices(instance_name, disks):
"""Closes the given block devices.
This means they will be switched to secondary mode (in case of
DRBD).
+ @param instance_name: if the argument is not empty, the symlinks
+ of this instance will be removed
@type disks: list of L{objects.Disk}
@param disks: the list of disks to be closed
@rtype: tuple (success, message)
if msg:
return (False, "Can't make devices secondary: %s" % ",".join(msg))
else:
+ if instance_name:
+ _RemoveBlockDevLinks(instance_name, disks)
return (True, "All devices secondary")