_Fail("Hypervisor error: %s", err, exc=True)
-def InstanceShutdown(instance):
+def InstanceShutdown(instance, timeout):
"""Shut an instance down.
@note: this functions uses polling with a hardcoded timeout.
@type instance: L{objects.Instance}
@param instance: the instance object
+ @type timeout: integer
+ @param timeout: maximum timeout for soft shutdown
@rtype: None
"""
hv_name = instance.hypervisor
- running_instances = GetInstanceList([hv_name])
+ hyper = hypervisor.GetHypervisor(hv_name)
+ running_instances = hyper.ListInstances()
iname = instance.name
if iname not in running_instances:
logging.info("Instance %s not running, doing nothing", iname)
return
- hyper = hypervisor.GetHypervisor(hv_name)
- try:
- hyper.StopInstance(instance)
- except errors.HypervisorError, err:
- _Fail("Failed to stop instance %s: %s", iname, err)
-
- # test every 10secs for 2min
+ start = time.time()
+ end = start + timeout
+ sleep_time = 1
- time.sleep(1)
- for _ in range(11):
- if instance.name not in GetInstanceList([hv_name]):
+ tried_once = False
+ while not tried_once and time.time() < end:
+ try:
+ hyper.StopInstance(instance, retry=tried_once)
+ except errors.HypervisorError, err:
+ _Fail("Failed to stop instance %s: %s", iname, err)
+ tried_once = True
+ time.sleep(sleep_time)
+ if instance.name not in hyper.ListInstances():
break
- time.sleep(10)
+ if sleep_time < 5:
+ # 1.2 behaves particularly good for our case:
+ # it gives us 10 increasing steps and caps just slightly above 5 seconds
+ sleep_time *= 1.2
else:
# the shutdown did not succeed
- logging.error("Shutdown of '%s' unsuccessful, using destroy", iname)
+ logging.error("Shutdown of '%s' unsuccessful, forcing", iname)
try:
hyper.StopInstance(instance, force=True)
_RemoveBlockDevLinks(iname, instance.disks)
-def InstanceReboot(instance, reboot_type):
+def InstanceReboot(instance, reboot_type, shutdown_timeout):
"""Reboot an instance.
@type instance: L{objects.Instance}
not accepted here, since that mode is handled differently, in
cmdlib, and translates into full stop and start of the
instance (instead of a call_instance_reboot RPC)
+ @type timeout: integer
+ @param timeout: maximum timeout for soft shutdown
@rtype: None
"""
_Fail("Failed to soft reboot instance %s: %s", instance.name, err)
elif reboot_type == constants.INSTANCE_REBOOT_HARD:
try:
- InstanceShutdown(instance)
+ InstanceShutdown(instance, shutdown_timeout)
return StartInstance(instance)
except errors.HypervisorError, err:
_Fail("Failed to hard reboot instance %s: %s", instance.name, err)
search (if not given defaults to
L{constants.OS_SEARCH_PATH})
@rtype: list of L{objects.OS}
- @return: a list of tuples (name, path, status, diagnose)
+ @return: a list of tuples (name, path, status, diagnose, variants)
for all (potential) OSes under all search paths, where:
- name is the (potential) OS name
- path is the full path to the OS
- status True/False is the validity of the OS
- diagnose is the error message for an invalid OS, otherwise empty
+ - variants is a list of supported OS variants, if any
"""
if top_dirs is None:
status, os_inst = _TryOSFromDisk(name, base_dir=dir_name)
if status:
diagnose = ""
+ variants = os_inst.supported_variants
else:
diagnose = os_inst
- result.append((name, os_path, status, diagnose))
+ variants = []
+ result.append((name, os_path, status, diagnose, variants))
return result
# OS Files dictionary, we will populate it with the absolute path names
os_files = dict.fromkeys(constants.OS_SCRIPTS)
+ if max(api_versions) >= constants.OS_API_V15:
+ os_files[constants.OS_VARIANTS_FILE] = ''
+
for name in os_files:
os_files[name] = os.path.sep.join([os_dir, name])
return False, ("File '%s' under path '%s' is not executable" %
(name, os_dir))
+ variants = None
+ if constants.OS_VARIANTS_FILE in os_files:
+ variants_file = os_files[constants.OS_VARIANTS_FILE]
+ try:
+ variants = utils.ReadFile(variants_file).splitlines()
+ except EnvironmentError, err:
+ return False, ("Error while reading the OS variants file at %s: %s" %
+ (variants_file, _ErrnoOrStr(err)))
+ if not variants:
+ return False, ("No supported os variant found")
os_obj = objects.OS(name=name, path=os_dir,
create_script=os_files[constants.OS_SCRIPT_CREATE],
export_script=os_files[constants.OS_SCRIPT_EXPORT],
import_script=os_files[constants.OS_SCRIPT_IMPORT],
rename_script=os_files[constants.OS_SCRIPT_RENAME],
+ supported_variants=variants,
api_versions=api_versions)
return True, os_obj
@raise RPCFail: if we don't find a valid OS
"""
- status, payload = _TryOSFromDisk(name, base_dir)
+ name_only = name.split("+", 1)[0]
+ status, payload = _TryOSFromDisk(name_only, base_dir)
if not status:
_Fail(payload)
result['DISK_COUNT'] = '%d' % len(instance.disks)
result['NIC_COUNT'] = '%d' % len(instance.nics)
result['DEBUG_LEVEL'] = '%d' % debug
+ if api_version >= constants.OS_API_V15:
+ try:
+ variant = instance.os.split('+', 1)[1]
+ except IndexError:
+ variant = os.supported_variants[0]
+ result['OS_VARIANT'] = variant
for idx, disk in enumerate(instance.disks):
real_disk = _RecursiveFindBD(disk)
if real_disk is None: