diff --git a/daemons/ganeti-noded b/daemons/ganeti-noded index 7b030a6ee680e1f3a59b2c3fd25ea67a2de59267..30087f126e93efff77be7ee2610ee7d621aeeb0a 100755 --- a/daemons/ganeti-noded +++ b/daemons/ganeti-noded @@ -345,8 +345,9 @@ class NodeHttpServer(http.server.HttpServer): instance = objects.Instance.FromDict(params[2]) cluster_name = params[3] dev_idx = params[4] + debug = params[5] return backend.ExportSnapshot(disk, dest_node, instance, - cluster_name, dev_idx) + cluster_name, dev_idx, debug) @staticmethod def perspective_finalize_export(params): @@ -451,26 +452,27 @@ class NodeHttpServer(http.server.HttpServer): inst_s = params[0] inst = objects.Instance.FromDict(inst_s) reinstall = params[1] - return backend.InstanceOsAdd(inst, reinstall) + debug = params[2] + return backend.InstanceOsAdd(inst, reinstall, debug) @staticmethod def perspective_instance_run_rename(params): """Runs the OS rename script for an instance. """ - inst_s, old_name = params + inst_s, old_name, debug = params inst = objects.Instance.FromDict(inst_s) - return backend.RunRenameInstance(inst, old_name) + return backend.RunRenameInstance(inst, old_name, debug) @staticmethod def perspective_instance_os_import(params): """Run the import function of an OS onto a given instance. """ - inst_s, src_node, src_images, cluster_name = params + inst_s, src_node, src_images, cluster_name, debug = params inst = objects.Instance.FromDict(inst_s) return backend.ImportOSIntoInstance(inst, src_node, src_images, - cluster_name) + cluster_name, debug) @staticmethod def perspective_instance_shutdown(params): diff --git a/lib/backend.py b/lib/backend.py index 711d7bca939826106e85a6a8e19a6a9053c2b16e..3b2538e38129d57e9f15434b3ae415d1c7e605d6 100644 --- a/lib/backend.py +++ b/lib/backend.py @@ -789,19 +789,21 @@ def GetAllInstancesInfo(hypervisor_list): return output -def InstanceOsAdd(instance, reinstall): +def InstanceOsAdd(instance, reinstall, debug): """Add an OS to an instance. @type instance: L{objects.Instance} @param instance: Instance whose OS is to be installed @type reinstall: boolean @param reinstall: whether this is an instance reinstall + @type debug: integer + @param debug: debug level, passed to the OS scripts @rtype: None """ inst_os = OSFromDisk(instance.os) - create_env = OSEnvironment(instance, inst_os) + create_env = OSEnvironment(instance, inst_os, debug) if reinstall: create_env['INSTANCE_REINSTALL'] = "1" @@ -820,20 +822,22 @@ def InstanceOsAdd(instance, reinstall): " log file:\n%s", result.fail_reason, "\n".join(lines), log=False) -def RunRenameInstance(instance, old_name): +def RunRenameInstance(instance, old_name, debug): """Run the OS rename script for an instance. @type instance: L{objects.Instance} @param instance: Instance whose OS is to be installed @type old_name: string @param old_name: previous instance name + @type debug: integer + @param debug: debug level, passed to the OS scripts @rtype: boolean @return: the success of the operation """ inst_os = OSFromDisk(instance.os) - rename_env = OSEnvironment(instance, inst_os) + rename_env = OSEnvironment(instance, inst_os, debug) rename_env['OLD_INSTANCE_NAME'] = old_name logfile = "%s/rename-%s-%s-%s-%d.log" % (constants.LOG_OS_DIR, instance.os, @@ -1944,7 +1948,7 @@ def BlockdevSnapshot(disk): disk.unique_id, disk.dev_type) -def ExportSnapshot(disk, dest_node, instance, cluster_name, idx): +def ExportSnapshot(disk, dest_node, instance, cluster_name, idx, debug): """Export a block device snapshot to a remote node. @type disk: L{objects.Disk} @@ -1958,11 +1962,13 @@ def ExportSnapshot(disk, dest_node, instance, cluster_name, idx): @type idx: int @param idx: the index of the disk in the instance's disk list, used to export to the OS scripts environment + @type debug: integer + @param debug: debug level, passed to the OS scripts @rtype: None """ inst_os = OSFromDisk(instance.os) - export_env = OSEnvironment(instance, inst_os) + export_env = OSEnvironment(instance, inst_os, debug) export_script = inst_os.export_script @@ -2092,7 +2098,7 @@ def ExportInfo(dest): return config.Dumps() -def ImportOSIntoInstance(instance, src_node, src_images, cluster_name): +def ImportOSIntoInstance(instance, src_node, src_images, cluster_name, debug): """Import an os image into an instance. @type instance: L{objects.Instance} @@ -2101,12 +2107,14 @@ def ImportOSIntoInstance(instance, src_node, src_images, cluster_name): @param src_node: source node for the disk images @type src_images: list of string @param src_images: absolute paths of the disk images + @type debug: integer + @param debug: debug level, passed to the OS scripts @rtype: list of boolean @return: each boolean represent the success of importing the n-th disk """ inst_os = OSFromDisk(instance.os) - import_env = OSEnvironment(instance, inst_os) + import_env = OSEnvironment(instance, inst_os, debug) import_script = inst_os.import_script logfile = "%s/import-%s-%s-%s.log" % (constants.LOG_OS_DIR, instance.os, diff --git a/lib/cmdlib.py b/lib/cmdlib.py index 7dffa465b88af4f31f43ee12e0d855d72a8c7147..cb922eb0dbe87164c2391b334d06dcc349641379 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -1603,7 +1603,8 @@ class LUVerifyCluster(LogicalUnit): test = msg and not res.offline self._ErrorIf(test, self.ENODEHOOKS, node_name, "Communication failure in hooks execution: %s", msg) - if test: + if res.offline or msg: + # No need to investigate payload if node is offline or gave an error. # override manually lu_result here as _ErrorIf only # overrides self.bad lu_result = 1 @@ -3992,7 +3993,8 @@ class LUReinstallInstance(LogicalUnit): _StartInstanceDisks(self, inst, None) try: feedback_fn("Running the instance OS create scripts...") - result = self.rpc.call_instance_os_add(inst.primary_node, inst, True) + # FIXME: pass debug option from opcode to backend + result = self.rpc.call_instance_os_add(inst.primary_node, inst, True, 0) result.Raise("Could not install OS for instance %s on node %s" % (inst.name, inst.primary_node)) finally: @@ -4176,7 +4178,7 @@ class LURenameInstance(LogicalUnit): _StartInstanceDisks(self, inst, None) try: result = self.rpc.call_instance_run_rename(inst.primary_node, inst, - old_name) + old_name, 0) msg = result.fail_msg if msg: msg = ("Could not run OS rename script for instance %s on node %s" @@ -6229,7 +6231,8 @@ class LUCreateInstance(LogicalUnit): if iobj.disk_template != constants.DT_DISKLESS: if self.op.mode == constants.INSTANCE_CREATE: feedback_fn("* running the instance OS create scripts...") - result = self.rpc.call_instance_os_add(pnode_name, iobj, False) + # FIXME: pass debug option from opcode to backend + result = self.rpc.call_instance_os_add(pnode_name, iobj, False, 0) result.Raise("Could not add os for instance %s" " on node %s" % (instance, pnode_name)) @@ -6238,9 +6241,10 @@ class LUCreateInstance(LogicalUnit): src_node = self.op.src_node src_images = self.src_images cluster_name = self.cfg.GetClusterName() + # FIXME: pass debug option from opcode to backend import_result = self.rpc.call_instance_os_import(pnode_name, iobj, src_node, src_images, - cluster_name) + cluster_name, 0) msg = import_result.fail_msg if msg: self.LogWarning("Error while importing the disk images for instance" @@ -6359,7 +6363,7 @@ class LUReplaceDisks(LogicalUnit): self.replacer = TLReplaceDisks(self, self.op.instance_name, self.op.mode, self.op.iallocator, self.op.remote_node, - self.op.disks) + self.op.disks, False) self.tasklets = [self.replacer] @@ -6451,7 +6455,8 @@ class LUEvacuateNode(LogicalUnit): names.append(inst.name) replacer = TLReplaceDisks(self, inst.name, constants.REPLACE_DISK_CHG, - self.op.iallocator, self.op.remote_node, []) + self.op.iallocator, self.op.remote_node, [], + True) tasklets.append(replacer) self.tasklets = tasklets @@ -6493,7 +6498,7 @@ class TLReplaceDisks(Tasklet): """ def __init__(self, lu, instance_name, mode, iallocator_name, remote_node, - disks): + disks, delay_iallocator): """Initializes this class. """ @@ -6505,6 +6510,7 @@ class TLReplaceDisks(Tasklet): self.iallocator_name = iallocator_name self.remote_node = remote_node self.disks = disks + self.delay_iallocator = delay_iallocator # Runtime data self.instance = None @@ -6591,6 +6597,19 @@ class TLReplaceDisks(Tasklet): len(instance.secondary_nodes), errors.ECODE_FAULT) + if not self.delay_iallocator: + self._CheckPrereq2() + + def _CheckPrereq2(self): + """Check prerequisites, second part. + + This function should always be part of CheckPrereq. It was separated and is + now called from Exec because during node evacuation iallocator was only + called with an unmodified cluster model, not taking planned changes into + account. + + """ + instance = self.instance secondary_node = instance.secondary_nodes[0] if self.iallocator_name is None: @@ -6694,6 +6713,9 @@ class TLReplaceDisks(Tasklet): This dispatches the disk replacement to the appropriate handler. """ + if self.delay_iallocator: + self._CheckPrereq2() + if not self.disks: feedback_fn("No disks need replacement") return @@ -8148,8 +8170,10 @@ class LUExportInstance(LogicalUnit): feedback_fn("Exporting snapshot %s from %s to %s" % (idx, src_node, dst_node.name)) if dev: + # FIXME: pass debug from opcode to backend result = self.rpc.call_snapshot_export(src_node, dev, dst_node.name, - instance, cluster_name, idx) + instance, cluster_name, + idx, 0) msg = result.fail_msg if msg: self.LogWarning("Could not export disk/%s from node %s to" diff --git a/lib/constants.py b/lib/constants.py index f91ea78503820cf24cb628999af80138fc973e9c..3f71443dc689688d9131788ae683194550566322 100644 --- a/lib/constants.py +++ b/lib/constants.py @@ -26,7 +26,7 @@ import re from ganeti import _autoconf # various versions -PROTOCOL_VERSION = 20 +PROTOCOL_VERSION = 30 RELEASE_VERSION = _autoconf.PACKAGE_VERSION OS_API_V10 = 10 OS_API_V15 = 15 diff --git a/lib/rpc.py b/lib/rpc.py index 69e692cea4f74b9b0ae77175538bbc3ea3cba878..d9114f1b17713e11f32d681170a47b9c21b4ca8c 100644 --- a/lib/rpc.py +++ b/lib/rpc.py @@ -576,23 +576,23 @@ class RpcRunner(object): [self._InstDict(inst), reboot_type, shutdown_timeout]) - def call_instance_os_add(self, node, inst, reinstall): + def call_instance_os_add(self, node, inst, reinstall, debug): """Installs an OS on the given instance. This is a single-node call. """ return self._SingleNodeCall(node, "instance_os_add", - [self._InstDict(inst), reinstall]) + [self._InstDict(inst), reinstall, debug]) - def call_instance_run_rename(self, node, inst, old_name): + def call_instance_run_rename(self, node, inst, old_name, debug): """Run the OS rename script for an instance. This is a single-node call. """ return self._SingleNodeCall(node, "instance_run_rename", - [self._InstDict(inst), old_name]) + [self._InstDict(inst), old_name, debug]) def call_instance_info(self, node, instance, hname): """Returns information about a single instance. @@ -988,7 +988,7 @@ class RpcRunner(object): return self._SingleNodeCall(node, "blockdev_snapshot", [cf_bdev.ToDict()]) def call_snapshot_export(self, node, snap_bdev, dest_node, instance, - cluster_name, idx): + cluster_name, idx, debug): """Request the export of a given snapshot. This is a single-node call. @@ -996,7 +996,8 @@ class RpcRunner(object): """ return self._SingleNodeCall(node, "snapshot_export", [snap_bdev.ToDict(), dest_node, - self._InstDict(instance), cluster_name, idx]) + self._InstDict(instance), cluster_name, + idx, debug]) def call_finalize_export(self, node, instance, snap_disks): """Request the completion of an export operation. @@ -1025,7 +1026,7 @@ class RpcRunner(object): return self._SingleNodeCall(node, "export_info", [path]) def call_instance_os_import(self, node, inst, src_node, src_images, - cluster_name): + cluster_name, debug): """Request the import of a backup into an instance. This is a single-node call. @@ -1033,7 +1034,7 @@ class RpcRunner(object): """ return self._SingleNodeCall(node, "instance_os_import", [self._InstDict(inst), src_node, src_images, - cluster_name]) + cluster_name, debug]) def call_export_list(self, node_list): """Gets the stored exports list. diff --git a/lib/utils.py b/lib/utils.py index 438a1203578ac8aaf4b4f9a43766dbebb4f91baf..45f0ecdb5b3978f379f68d41523681290843285c 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -2172,7 +2172,7 @@ class _RetryDelayCalculator(object): # Update for next run if self._limit is None or self._next < self._limit: - self._next = max(self._limit, self._next * self._factor) + self._next = min(self._limit, self._next * self._factor) return current