X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/de0417fa1d1f2ebedcedb57ea836179eeab50666..dc7d923e222361ed176abd841f47f62900d4ac65:/lib/cmdlib.py diff --git a/lib/cmdlib.py b/lib/cmdlib.py index 72a4994..7b6d571 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -138,13 +138,18 @@ class LogicalUnit(object): self.owned_locks = context.glm.list_owned self.context = context self.rpc = rpc_runner - # Dicts used to declare locking needs to mcpu + + # Dictionaries used to declare locking needs to mcpu self.needed_locks = None self.share_locks = dict.fromkeys(locking.LEVELS, 0) + self.opportunistic_locks = dict.fromkeys(locking.LEVELS, False) + self.add_locks = {} self.remove_locks = {} + # Used to force good behavior when calling helper functions self.recalculate_locks = {} + # logging self.Log = processor.Log # pylint: disable=C0103 self.LogWarning = processor.LogWarning # pylint: disable=C0103 @@ -959,7 +964,8 @@ def _RunPostHook(lu, node_name): try: hm.RunPhase(constants.HOOKS_PHASE_POST, nodes=[node_name]) except Exception, err: # pylint: disable=W0703 - lu.LogWarning("Errors occurred running hooks on %s: %s" % (node_name, err)) + lu.LogWarning("Errors occurred running hooks on %s: %s", + node_name, err) def _CheckOutputFields(static, dynamic, selected): @@ -1100,7 +1106,8 @@ def _CheckInstanceState(lu, instance, req_states, msg=None): """ if msg is None: - msg = "can't use instance from outside %s states" % ", ".join(req_states) + msg = ("can't use instance from outside %s states" % + utils.CommaJoin(req_states)) if instance.admin_state not in req_states: raise errors.OpPrereqError("Instance '%s' is marked to be %s, %s" % (instance.name, instance.admin_state, msg), @@ -1339,7 +1346,7 @@ def _BuildNetworkHookEnv(name, subnet, gateway, network6, gateway6, @param tags: the tags of the network """ - env = dict() + env = {} if name: env["NETWORK_NAME"] = name if subnet: @@ -2226,6 +2233,11 @@ class LUClusterVerifyGroup(LogicalUnit, _VerifyErrors): locking.LEVEL_INSTANCE: inst_names, locking.LEVEL_NODEGROUP: [self.group_uuid], locking.LEVEL_NODE: [], + + # This opcode is run by watcher every five minutes and acquires all nodes + # for a group. It doesn't run for a long time, so it's better to acquire + # the node allocation lock as well. + locking.LEVEL_NODE_ALLOC: locking.ALL_SET, } self.share_locks = _ShareAll() @@ -2550,7 +2562,8 @@ class LUClusterVerifyGroup(LogicalUnit, _VerifyErrors): ipolicy = ganeti.masterd.instance.CalculateGroupIPolicy(cluster, self.group_info) err = _ComputeIPolicyInstanceViolation(ipolicy, instanceconfig) - _ErrorIf(err, constants.CV_EINSTANCEPOLICY, instance, utils.CommaJoin(err)) + _ErrorIf(err, constants.CV_EINSTANCEPOLICY, instance, utils.CommaJoin(err), + code=self.ETYPE_WARNING) for node in node_vol_should: n_img = node_image[node] @@ -3672,6 +3685,12 @@ class LUGroupVerifyDisks(NoHooksLU): locking.LEVEL_INSTANCE: [], locking.LEVEL_NODEGROUP: [], locking.LEVEL_NODE: [], + + # This opcode is acquires all node locks in a group. LUClusterVerifyDisks + # starts one instance of this opcode for every group, which means all + # nodes will be locked for a short amount of time, so it's better to + # acquire the node allocation lock as well. + locking.LEVEL_NODE_ALLOC: locking.ALL_SET, } def DeclareLocks(self, level): @@ -3778,6 +3797,8 @@ class LUClusterRepairDiskSizes(NoHooksLU): def ExpandNames(self): if self.op.instances: self.wanted_names = _GetWantedInstances(self, self.op.instances) + # Not getting the node allocation lock as only a specific set of + # instances (and their nodes) is going to be acquired self.needed_locks = { locking.LEVEL_NODE_RES: [], locking.LEVEL_INSTANCE: self.wanted_names, @@ -3788,10 +3809,15 @@ class LUClusterRepairDiskSizes(NoHooksLU): self.needed_locks = { locking.LEVEL_NODE_RES: locking.ALL_SET, locking.LEVEL_INSTANCE: locking.ALL_SET, + + # This opcode is acquires the node locks for all instances + locking.LEVEL_NODE_ALLOC: locking.ALL_SET, } + self.share_locks = { locking.LEVEL_NODE_RES: 1, locking.LEVEL_INSTANCE: 0, + locking.LEVEL_NODE_ALLOC: 1, } def DeclareLocks(self, level): @@ -4033,16 +4059,15 @@ class LUClusterSetParams(LogicalUnit): def ExpandNames(self): # FIXME: in the future maybe other cluster params won't require checking on # all nodes to be modified. + # FIXME: This opcode changes cluster-wide settings. Is acquiring all + # resource locks the right thing, shouldn't it be the BGL instead? self.needed_locks = { locking.LEVEL_NODE: locking.ALL_SET, locking.LEVEL_INSTANCE: locking.ALL_SET, locking.LEVEL_NODEGROUP: locking.ALL_SET, + locking.LEVEL_NODE_ALLOC: locking.ALL_SET, } - self.share_locks = { - locking.LEVEL_NODE: 1, - locking.LEVEL_INSTANCE: 1, - locking.LEVEL_NODEGROUP: 1, - } + self.share_locks = _ShareAll() def BuildHooksEnv(self): """Build hooks env. @@ -4447,7 +4472,7 @@ def _UploadHelper(lu, nodes, fname): if msg: msg = ("Copy of file %s to node %s failed: %s" % (fname, to_node, msg)) - lu.proc.LogWarning(msg) + lu.LogWarning(msg) def _ComputeAncillaryFiles(cluster, redist): @@ -4589,8 +4614,9 @@ class LUClusterRedistConf(NoHooksLU): def ExpandNames(self): self.needed_locks = { locking.LEVEL_NODE: locking.ALL_SET, + locking.LEVEL_NODE_ALLOC: locking.ALL_SET, } - self.share_locks[locking.LEVEL_NODE] = 1 + self.share_locks = _ShareAll() def Exec(self, feedback_fn): """Redistribute the configuration. @@ -4640,7 +4666,7 @@ def _WaitForSync(lu, instance, disks=None, oneshot=False): disks = _ExpandCheckDisks(instance, disks) if not oneshot: - lu.proc.LogInfo("Waiting for instance %s to sync disks." % instance.name) + lu.LogInfo("Waiting for instance %s to sync disks", instance.name) node = instance.primary_node @@ -4683,8 +4709,8 @@ def _WaitForSync(lu, instance, disks=None, oneshot=False): max_time = mstat.estimated_time else: rem_time = "no time estimate" - lu.proc.LogInfo("- device %s: %5.2f%% done, %s" % - (disks[i].iv_name, mstat.sync_percent, rem_time)) + lu.LogInfo("- device %s: %5.2f%% done, %s", + disks[i].iv_name, mstat.sync_percent, rem_time) # if we're done but degraded, let's do a few small retries, to # make sure we see a stable and not transient situation; therefore @@ -4701,7 +4727,8 @@ def _WaitForSync(lu, instance, disks=None, oneshot=False): time.sleep(min(60, max_time)) if done: - lu.proc.LogInfo("Instance %s's disks are in sync." % instance.name) + lu.LogInfo("Instance %s's disks are in sync", instance.name) + return not cumul_degraded @@ -4787,6 +4814,11 @@ class LUOobCommand(NoHooksLU): locking.LEVEL_NODE: lock_names, } + if not self.op.node_names: + # Acquire node allocation lock only if all nodes are affected + self.needed_locks[locking.LEVEL_NODE_ALLOC] = locking.ALL_SET + self.share_locks[locking.LEVEL_NODE_ALLOC] = 1 + def CheckPrereq(self): """Check prerequisites. @@ -5219,6 +5251,7 @@ class _NodeQuery(_QueryBase): if self.do_locking: # If any non-static field is requested we need to lock the nodes lu.needed_locks[locking.LEVEL_NODE] = self.wanted + lu.needed_locks[locking.LEVEL_NODE_ALLOC] = locking.ALL_SET def DeclareLocks(self, lu, level): pass @@ -5313,13 +5346,16 @@ class LUNodeQueryvols(NoHooksLU): def ExpandNames(self): self.share_locks = _ShareAll() - self.needed_locks = {} - if not self.op.nodes: - self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET + if self.op.nodes: + self.needed_locks = { + locking.LEVEL_NODE: _GetWantedNodes(self, self.op.nodes), + } else: - self.needed_locks[locking.LEVEL_NODE] = \ - _GetWantedNodes(self, self.op.nodes) + self.needed_locks = { + locking.LEVEL_NODE: locking.ALL_SET, + locking.LEVEL_NODE_ALLOC: locking.ALL_SET, + } def Exec(self, feedback_fn): """Computes the list of nodes and their attributes. @@ -5382,13 +5418,16 @@ class LUNodeQueryStorage(NoHooksLU): def ExpandNames(self): self.share_locks = _ShareAll() - self.needed_locks = {} if self.op.nodes: - self.needed_locks[locking.LEVEL_NODE] = \ - _GetWantedNodes(self, self.op.nodes) + self.needed_locks = { + locking.LEVEL_NODE: _GetWantedNodes(self, self.op.nodes), + } else: - self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET + self.needed_locks = { + locking.LEVEL_NODE: locking.ALL_SET, + locking.LEVEL_NODE_ALLOC: locking.ALL_SET, + } def Exec(self, feedback_fn): """Computes the list of nodes and their attributes. @@ -6014,19 +6053,28 @@ class LUNodeSetParams(LogicalUnit): def ExpandNames(self): if self.lock_all: - self.needed_locks = {locking.LEVEL_NODE: locking.ALL_SET} + self.needed_locks = { + locking.LEVEL_NODE: locking.ALL_SET, + + # Block allocations when all nodes are locked + locking.LEVEL_NODE_ALLOC: locking.ALL_SET, + } else: - self.needed_locks = {locking.LEVEL_NODE: self.op.node_name} + self.needed_locks = { + locking.LEVEL_NODE: self.op.node_name, + } # Since modifying a node can have severe effects on currently running # operations the resource lock is at least acquired in shared mode self.needed_locks[locking.LEVEL_NODE_RES] = \ self.needed_locks[locking.LEVEL_NODE] - # Get node resource and instance locks in shared mode; they are not used - # for anything but read-only access - self.share_locks[locking.LEVEL_NODE_RES] = 1 - self.share_locks[locking.LEVEL_INSTANCE] = 1 + # Get all locks except nodes in shared mode; they are not used for anything + # but read-only access + self.share_locks = _ShareAll() + self.share_locks[locking.LEVEL_NODE] = 0 + self.share_locks[locking.LEVEL_NODE_RES] = 0 + self.share_locks[locking.LEVEL_NODE_ALLOC] = 0 if self.lock_instances: self.needed_locks[locking.LEVEL_INSTANCE] = \ @@ -6193,7 +6241,8 @@ class LUNodeSetParams(LogicalUnit): if master_singlehomed and self.op.secondary_ip != node.primary_ip: if self.op.force and node.name == master.name: self.LogWarning("Transitioning from single-homed to multi-homed" - " cluster. All nodes will require a secondary ip.") + " cluster; all nodes will require a secondary IP" + " address") else: raise errors.OpPrereqError("Changing the secondary ip on a" " single-homed cluster requires the" @@ -6203,7 +6252,8 @@ class LUNodeSetParams(LogicalUnit): elif not master_singlehomed and self.op.secondary_ip == node.primary_ip: if self.op.force and node.name == master.name: self.LogWarning("Transitioning from multi-homed to single-homed" - " cluster. Secondary IPs will have to be removed.") + " cluster; secondary IP addresses will have to be" + " removed") else: raise errors.OpPrereqError("Cannot set the secondary IP to be the" " same as the primary IP on a multi-homed" @@ -6581,9 +6631,9 @@ def _AssembleInstanceDisks(lu, instance, disks=None, ignore_secondaries=False, if msg: is_offline_secondary = (node in instance.secondary_nodes and result.offline) - lu.proc.LogWarning("Could not prepare block device %s on node %s" - " (is_primary=False, pass=1): %s", - inst_disk.iv_name, node, msg) + lu.LogWarning("Could not prepare block device %s on node %s" + " (is_primary=False, pass=1): %s", + inst_disk.iv_name, node, msg) if not (ignore_secondaries or is_offline_secondary): disks_ok = False @@ -6604,9 +6654,9 @@ def _AssembleInstanceDisks(lu, instance, disks=None, ignore_secondaries=False, True, idx) msg = result.fail_msg if msg: - lu.proc.LogWarning("Could not prepare block device %s on node %s" - " (is_primary=True, pass=2): %s", - inst_disk.iv_name, node, msg) + lu.LogWarning("Could not prepare block device %s on node %s" + " (is_primary=True, pass=2): %s", + inst_disk.iv_name, node, msg) disks_ok = False else: dev_path = result.payload @@ -6631,9 +6681,9 @@ def _StartInstanceDisks(lu, instance, force): if not disks_ok: _ShutdownInstanceDisks(lu, instance) if force is not None and not force: - lu.proc.LogWarning("", hint="If the message above refers to a" - " secondary node," - " you can retry the operation using '--force'.") + lu.LogWarning("", + hint=("If the message above refers to a secondary node," + " you can retry the operation using '--force'")) raise errors.OpExecError("Disk consistency error") @@ -6936,10 +6986,10 @@ class LUInstanceStartup(LogicalUnit): self.primary_offline = self.cfg.GetNodeInfo(instance.primary_node).offline if self.primary_offline and self.op.ignore_offline_nodes: - self.proc.LogWarning("Ignoring offline primary node") + self.LogWarning("Ignoring offline primary node") if self.op.hvparams or self.op.beparams: - self.proc.LogWarning("Overridden parameters are ignored") + self.LogWarning("Overridden parameters are ignored") else: _CheckNodeOnline(self, instance.primary_node) @@ -6971,7 +7021,7 @@ class LUInstanceStartup(LogicalUnit): if self.primary_offline: assert self.op.ignore_offline_nodes - self.proc.LogInfo("Primary node offline, marked instance as started") + self.LogInfo("Primary node offline, marked instance as started") else: node_current = instance.primary_node @@ -7126,7 +7176,7 @@ class LUInstanceShutdown(LogicalUnit): self.cfg.GetNodeInfo(self.instance.primary_node).offline if self.primary_offline and self.op.ignore_offline_nodes: - self.proc.LogWarning("Ignoring offline primary node") + self.LogWarning("Ignoring offline primary node") else: _CheckNodeOnline(self, self.instance.primary_node) @@ -7143,12 +7193,12 @@ class LUInstanceShutdown(LogicalUnit): if self.primary_offline: assert self.op.ignore_offline_nodes - self.proc.LogInfo("Primary node offline, marked instance as stopped") + self.LogInfo("Primary node offline, marked instance as stopped") else: result = self.rpc.call_instance_shutdown(node_current, instance, timeout) msg = result.fail_msg if msg: - self.proc.LogWarning("Could not shutdown instance: %s" % msg) + self.LogWarning("Could not shutdown instance: %s", msg) _ShutdownInstanceDisks(self, instance) @@ -7344,6 +7394,7 @@ class LUInstanceRecreateDisks(LogicalUnit): def ExpandNames(self): self._ExpandAndLockInstance() self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_APPEND + if self.op.nodes: self.op.nodes = [_ExpandNodeName(self.cfg, n) for n in self.op.nodes] self.needed_locks[locking.LEVEL_NODE] = list(self.op.nodes) @@ -7352,6 +7403,8 @@ class LUInstanceRecreateDisks(LogicalUnit): if self.op.iallocator: # iallocator will select a new node in the same group self.needed_locks[locking.LEVEL_NODEGROUP] = [] + self.needed_locks[locking.LEVEL_NODE_ALLOC] = locking.ALL_SET + self.needed_locks[locking.LEVEL_NODE_RES] = [] def DeclareLocks(self, level): @@ -7381,6 +7434,8 @@ class LUInstanceRecreateDisks(LogicalUnit): for group_uuid in self.owned_locks(locking.LEVEL_NODEGROUP): self.needed_locks[locking.LEVEL_NODE].extend( self.cfg.GetNodeGroup(group_uuid).members) + + assert locking.NAL in self.owned_locks(locking.LEVEL_NODE_ALLOC) elif not self.op.nodes: self._LockInstancesNodes(primary_only=False) elif level == locking.LEVEL_NODE_RES: @@ -7471,6 +7526,9 @@ class LUInstanceRecreateDisks(LogicalUnit): # Release unneeded node and node resource locks _ReleaseLocks(self, locking.LEVEL_NODE, keep=self.op.nodes) _ReleaseLocks(self, locking.LEVEL_NODE_RES, keep=self.op.nodes) + _ReleaseLocks(self, locking.LEVEL_NODE_ALLOC) + + assert not self.glm.is_owned(locking.LEVEL_NODE_ALLOC) def Exec(self, feedback_fn): """Recreate the disks. @@ -7614,6 +7672,7 @@ class LUInstanceRename(LogicalUnit): # Change the instance lock. This is definitely safe while we hold the BGL. # Otherwise the new lock would have to be added in acquired mode. assert self.REQ_BGL + assert locking.BGL in self.owned_locks(locking.LEVEL_CLUSTER) self.glm.remove(locking.LEVEL_INSTANCE, old_name) self.glm.add(locking.LEVEL_INSTANCE, self.op.new_name) @@ -7648,7 +7707,7 @@ class LUInstanceRename(LogicalUnit): msg = ("Could not run OS rename script for instance %s on node %s" " (but the instance has been renamed in Ganeti): %s" % (inst.name, inst.primary_node, msg)) - self.proc.LogWarning(msg) + self.LogWarning(msg) finally: _ShutdownInstanceDisks(self, inst) @@ -7791,6 +7850,10 @@ def _ExpandNamesForMigration(lu): lu.needed_locks[locking.LEVEL_NODE_RES] = [] lu.recalculate_locks[locking.LEVEL_NODE_RES] = constants.LOCKS_REPLACE + # The node allocation lock is actually only needed for replicated instances + # (e.g. DRBD8) and if an iallocator is used. + lu.needed_locks[locking.LEVEL_NODE_ALLOC] = [] + def _DeclareLocksForMigration(lu, level): """Declares locks for L{TLMigrateInstance}. @@ -7799,17 +7862,26 @@ def _DeclareLocksForMigration(lu, level): @param level: Lock level """ - if level == locking.LEVEL_NODE: + if level == locking.LEVEL_NODE_ALLOC: + assert lu.op.instance_name in lu.owned_locks(locking.LEVEL_INSTANCE) + instance = lu.cfg.GetInstanceInfo(lu.op.instance_name) + if instance.disk_template in constants.DTS_EXT_MIRROR: if lu.op.target_node is None: lu.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET + lu.needed_locks[locking.LEVEL_NODE_ALLOC] = locking.ALL_SET else: lu.needed_locks[locking.LEVEL_NODE] = [instance.primary_node, lu.op.target_node] del lu.recalculate_locks[locking.LEVEL_NODE] else: lu._LockInstancesNodes() # pylint: disable=W0212 + + elif level == locking.LEVEL_NODE: + # Node locks are declared together with the node allocation lock + assert lu.needed_locks[locking.LEVEL_NODE] + elif level == locking.LEVEL_NODE_RES: # Copy node locks lu.needed_locks[locking.LEVEL_NODE_RES] = \ @@ -8062,10 +8134,10 @@ class LUInstanceMove(LogicalUnit): msg = result.fail_msg if msg: if self.op.ignore_consistency: - self.proc.LogWarning("Could not shutdown instance %s on node %s." - " Proceeding anyway. Please make sure node" - " %s is down. Error details: %s", - instance.name, source_node, source_node, msg) + self.LogWarning("Could not shutdown instance %s on node %s." + " Proceeding anyway. Please make sure node" + " %s is down. Error details: %s", + instance.name, source_node, source_node, msg) else: raise errors.OpExecError("Could not shutdown instance %s on" " node %s: %s" % @@ -8283,6 +8355,8 @@ class TLMigrateInstance(Tasklet): errors.ECODE_STATE) if instance.disk_template in constants.DTS_EXT_MIRROR: + assert locking.NAL in self.lu.owned_locks(locking.LEVEL_NODE_ALLOC) + _CheckIAllocatorOrNode(self.lu, "iallocator", "target_node") if self.lu.op.iallocator: @@ -8314,8 +8388,11 @@ class TLMigrateInstance(Tasklet): # in the LU _ReleaseLocks(self.lu, locking.LEVEL_NODE, keep=[instance.primary_node, self.target_node]) + _ReleaseLocks(self.lu, locking.LEVEL_NODE_ALLOC) else: + assert not self.lu.glm.is_owned(locking.LEVEL_NODE_ALLOC) + secondary_nodes = instance.secondary_nodes if not secondary_nodes: raise errors.ConfigurationError("No secondary node but using" @@ -8417,6 +8494,8 @@ class TLMigrateInstance(Tasklet): """Run the allocator based on input opcode. """ + assert locking.NAL in self.lu.owned_locks(locking.LEVEL_NODE_ALLOC) + # FIXME: add a self.ignore_ipolicy option req = iallocator.IAReqRelocate(name=self.instance_name, relocate_from=[self.instance.primary_node]) @@ -9485,14 +9564,14 @@ def _CreateInstanceAllocRequest(op, disks, nics, beparams): hypervisor=op.hypervisor) -def _ComputeNics(op, cluster, default_ip, cfg, proc): +def _ComputeNics(op, cluster, default_ip, cfg, ec_id): """Computes the nics. @param op: The instance opcode @param cluster: Cluster configuration object @param default_ip: The default ip to assign @param cfg: An instance of the configuration object - @param proc: The executer instance + @param ec_id: Execution context ID @returns: The build up nics @@ -9552,7 +9631,7 @@ def _ComputeNics(op, cluster, default_ip, cfg, proc): try: # TODO: We need to factor this out - cfg.ReserveMAC(mac, proc.GetECId()) + cfg.ReserveMAC(mac, ec_id) except errors.ReservationError: raise errors.OpPrereqError("MAC address %s already in use" " in cluster" % mac, @@ -9815,7 +9894,7 @@ class LUInstanceCreate(LogicalUnit): # specifying a group on instance creation and then selecting nodes from # that group self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET - self.needed_locks[locking.LEVEL_NODE_RES] = locking.ALL_SET + self.needed_locks[locking.LEVEL_NODE_ALLOC] = locking.ALL_SET else: self.op.pnode = _ExpandNodeName(self.cfg, self.op.pnode) nodelist = [self.op.pnode] @@ -9823,9 +9902,6 @@ class LUInstanceCreate(LogicalUnit): self.op.snode = _ExpandNodeName(self.cfg, self.op.snode) nodelist.append(self.op.snode) self.needed_locks[locking.LEVEL_NODE] = nodelist - # Lock resources of instance's primary and secondary nodes (copy to - # prevent accidential modification) - self.needed_locks[locking.LEVEL_NODE_RES] = list(nodelist) # in case of import lock the source node too if self.op.mode == constants.INSTANCE_IMPORT: @@ -9837,6 +9913,7 @@ class LUInstanceCreate(LogicalUnit): if src_node is None: self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET + self.needed_locks[locking.LEVEL_NODE_ALLOC] = locking.ALL_SET self.op.src_node = None if os.path.isabs(src_path): raise errors.OpPrereqError("Importing an instance from a path" @@ -9850,6 +9927,9 @@ class LUInstanceCreate(LogicalUnit): self.op.src_path = src_path = \ utils.PathJoin(pathutils.EXPORT_DIR, src_path) + self.needed_locks[locking.LEVEL_NODE_RES] = \ + _CopyLockList(self.needed_locks[locking.LEVEL_NODE]) + def _RunAllocator(self): """Run the allocator based on input opcode. @@ -10167,7 +10247,7 @@ class LUInstanceCreate(LogicalUnit): # NIC buildup self.nics = _ComputeNics(self.op, cluster, self.hostname1.ip, self.cfg, - self.proc) + self.proc.GetECId()) # disk checks/pre-build default_vg = self.cfg.GetVGName() @@ -10220,12 +10300,14 @@ class LUInstanceCreate(LogicalUnit): self._RunAllocator() # Release all unneeded node locks - _ReleaseLocks(self, locking.LEVEL_NODE, - keep=filter(None, [self.op.pnode, self.op.snode, - self.op.src_node])) - _ReleaseLocks(self, locking.LEVEL_NODE_RES, - keep=filter(None, [self.op.pnode, self.op.snode, - self.op.src_node])) + keep_locks = filter(None, [self.op.pnode, self.op.snode, self.op.src_node]) + _ReleaseLocks(self, locking.LEVEL_NODE, keep=keep_locks) + _ReleaseLocks(self, locking.LEVEL_NODE_RES, keep=keep_locks) + _ReleaseLocks(self, locking.LEVEL_NODE_ALLOC) + + assert (self.owned_locks(locking.LEVEL_NODE) == + self.owned_locks(locking.LEVEL_NODE_RES)), \ + "Node locks differ from node resource locks" #### node related checks @@ -10383,7 +10465,7 @@ class LUInstanceCreate(LogicalUnit): if baddisks: raise errors.OpPrereqError("Device node(s) %s lie outside %s and" " cannot be adopted" % - (", ".join(baddisks), + (utils.CommaJoin(baddisks), constants.ADOPTABLE_BLOCKDEV_ROOT), errors.ECODE_INVAL) @@ -10450,6 +10532,7 @@ class LUInstanceCreate(LogicalUnit): assert not (self.owned_locks(locking.LEVEL_NODE_RES) - self.owned_locks(locking.LEVEL_NODE)), \ "Node locks differ from node resource locks" + assert not self.glm.is_owned(locking.LEVEL_NODE_ALLOC) ht_kind = self.op.hypervisor if ht_kind in constants.HTS_REQ_PORT: @@ -10728,7 +10811,11 @@ class LUInstanceMultiAlloc(NoHooksLU): """ self.share_locks = _ShareAll() - self.needed_locks = {} + self.needed_locks = { + # iallocator will select nodes and even if no iallocator is used, + # collisions with LUInstanceCreate should be avoided + locking.LEVEL_NODE_ALLOC: locking.ALL_SET, + } if self.op.iallocator: self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET @@ -10753,11 +10840,14 @@ class LUInstanceMultiAlloc(NoHooksLU): """ cluster = self.cfg.GetClusterInfo() default_vg = self.cfg.GetVGName() + ec_id = self.proc.GetECId() + insts = [_CreateInstanceAllocRequest(op, _ComputeDisks(op, default_vg), _ComputeNics(op, cluster, None, - self.cfg, self.proc), + self.cfg, ec_id), _ComputeFullBeParams(op, cluster)) for op in self.op.instances] + req = iallocator.IAReqMultiInstanceAlloc(instances=insts) ial = iallocator.IAllocator(self.cfg, self.rpc, req) @@ -10946,12 +11036,13 @@ class LUInstanceReplaceDisks(LogicalUnit): if self.op.iallocator is not None: # iallocator will select a new node in the same group self.needed_locks[locking.LEVEL_NODEGROUP] = [] + self.needed_locks[locking.LEVEL_NODE_ALLOC] = locking.ALL_SET self.needed_locks[locking.LEVEL_NODE_RES] = [] self.replacer = TLReplaceDisks(self, self.op.instance_name, self.op.mode, self.op.iallocator, self.op.remote_node, - self.op.disks, False, self.op.early_release, + self.op.disks, self.op.early_release, self.op.ignore_ipolicy) self.tasklets = [self.replacer] @@ -10972,6 +11063,7 @@ class LUInstanceReplaceDisks(LogicalUnit): if self.op.iallocator is not None: assert self.op.remote_node is None assert not self.needed_locks[locking.LEVEL_NODE] + assert locking.NAL in self.owned_locks(locking.LEVEL_NODE_ALLOC) # Lock member nodes of all locked groups self.needed_locks[locking.LEVEL_NODE] = \ @@ -10979,7 +11071,10 @@ class LUInstanceReplaceDisks(LogicalUnit): for group_uuid in self.owned_locks(locking.LEVEL_NODEGROUP) for node_name in self.cfg.GetNodeGroup(group_uuid).members] else: + assert not self.glm.is_owned(locking.LEVEL_NODE_ALLOC) + self._LockInstancesNodes() + elif level == locking.LEVEL_NODE_RES: # Reuse node locks self.needed_locks[locking.LEVEL_NODE_RES] = \ @@ -11035,7 +11130,7 @@ class TLReplaceDisks(Tasklet): """ def __init__(self, lu, instance_name, mode, iallocator_name, remote_node, - disks, delay_iallocator, early_release, ignore_ipolicy): + disks, early_release, ignore_ipolicy): """Initializes this class. """ @@ -11047,7 +11142,6 @@ class TLReplaceDisks(Tasklet): self.iallocator_name = iallocator_name self.remote_node = remote_node self.disks = disks - self.delay_iallocator = delay_iallocator self.early_release = early_release self.ignore_ipolicy = ignore_ipolicy @@ -11132,18 +11226,6 @@ 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] @@ -11264,10 +11346,10 @@ class TLReplaceDisks(Tasklet): # Release unneeded node and node resource locks _ReleaseLocks(self.lu, locking.LEVEL_NODE, keep=touched_nodes) _ReleaseLocks(self.lu, locking.LEVEL_NODE_RES, keep=touched_nodes) + _ReleaseLocks(self.lu, locking.LEVEL_NODE_ALLOC) # Release any owned node group - if self.lu.glm.is_owned(locking.LEVEL_NODEGROUP): - _ReleaseLocks(self.lu, locking.LEVEL_NODEGROUP) + _ReleaseLocks(self.lu, locking.LEVEL_NODEGROUP) # Check whether disks are valid for disk_idx in self.disks: @@ -11283,9 +11365,6 @@ class TLReplaceDisks(Tasklet): This dispatches the disk replacement to the appropriate handler. """ - if self.delay_iallocator: - self._CheckPrereq2() - if __debug__: # Verify owned locks before starting operation owned_nodes = self.lu.owned_locks(locking.LEVEL_NODE) @@ -11294,6 +11373,7 @@ class TLReplaceDisks(Tasklet): (owned_nodes, self.node_secondary_ip.keys())) assert (self.lu.owned_locks(locking.LEVEL_NODE) == self.lu.owned_locks(locking.LEVEL_NODE_RES)) + assert not self.lu.glm.is_owned(locking.LEVEL_NODE_ALLOC) owned_instances = self.lu.owned_locks(locking.LEVEL_INSTANCE) assert list(owned_instances) == [self.instance_name], \ @@ -11370,7 +11450,7 @@ class TLReplaceDisks(Tasklet): continue for node in nodes: - self.lu.LogInfo("Checking disk/%d on %s" % (idx, node)) + self.lu.LogInfo("Checking disk/%d on %s", idx, node) self.cfg.SetDiskID(dev, node) result = _BlockdevFind(self, node, dev, self.instance) @@ -11410,7 +11490,7 @@ class TLReplaceDisks(Tasklet): if idx not in self.disks: continue - self.lu.LogInfo("Adding storage on %s for disk/%d" % (node_name, idx)) + self.lu.LogInfo("Adding storage on %s for disk/%d", node_name, idx) self.cfg.SetDiskID(dev, node_name) @@ -11457,14 +11537,14 @@ class TLReplaceDisks(Tasklet): def _RemoveOldStorage(self, node_name, iv_names): for name, (_, old_lvs, _) in iv_names.iteritems(): - self.lu.LogInfo("Remove logical volumes for %s" % name) + self.lu.LogInfo("Remove logical volumes for %s", name) for lv in old_lvs: self.cfg.SetDiskID(lv, node_name) msg = self.rpc.call_blockdev_remove(node_name, lv).fail_msg if msg: - self.lu.LogWarning("Can't remove old LV: %s" % msg, + self.lu.LogWarning("Can't remove old LV: %s", msg, hint="remove unused LVs manually") def _ExecDrbd8DiskOnly(self, feedback_fn): # pylint: disable=W0613 @@ -11509,7 +11589,7 @@ class TLReplaceDisks(Tasklet): # Step: for each lv, detach+rename*2+attach self.lu.LogStep(4, steps_total, "Changing drbd configuration") for dev, old_lvs, new_lvs in iv_names.itervalues(): - self.lu.LogInfo("Detaching %s drbd from local storage" % dev.iv_name) + self.lu.LogInfo("Detaching %s drbd from local storage", dev.iv_name) result = self.rpc.call_blockdev_removechildren(self.target_node, dev, old_lvs) @@ -11563,7 +11643,7 @@ class TLReplaceDisks(Tasklet): self.cfg.SetDiskID(disk, self.target_node) # Now that the new lvs have the old name, we can add them to the device - self.lu.LogInfo("Adding new mirror component on %s" % self.target_node) + self.lu.LogInfo("Adding new mirror component on %s", self.target_node) result = self.rpc.call_blockdev_addchildren(self.target_node, (dev, self.instance), new_lvs) msg = result.fail_msg @@ -11701,7 +11781,7 @@ class TLReplaceDisks(Tasklet): # We have new devices, shutdown the drbd on the old secondary for idx, dev in enumerate(self.instance.disks): - self.lu.LogInfo("Shutting down drbd for disk/%d on old node" % idx) + self.lu.LogInfo("Shutting down drbd for disk/%d on old node", idx) self.cfg.SetDiskID(dev, self.target_node) msg = self.rpc.call_blockdev_shutdown(self.target_node, (dev, self.instance)).fail_msg @@ -11813,7 +11893,7 @@ class LURepairNodeStorage(NoHooksLU): errors.ECODE_STATE) except errors.OpPrereqError, err: if self.op.ignore_consistency: - self.proc.LogWarning(str(err.args[0])) + self.LogWarning(str(err.args[0])) else: raise @@ -12291,14 +12371,14 @@ class LUInstanceGrowDisk(LogicalUnit): if self.op.wait_for_sync: disk_abort = not _WaitForSync(self, instance, disks=[disk]) if disk_abort: - self.proc.LogWarning("Disk sync-ing has not returned a good" - " status; please check the instance") + self.LogWarning("Disk syncing has not returned a good status; check" + " the instance") if instance.admin_state != constants.ADMINST_UP: _SafeShutdownInstanceDisks(self, instance, disks=[disk]) elif instance.admin_state != constants.ADMINST_UP: - self.proc.LogWarning("Not shutting down the disk even if the instance is" - " not supposed to be running because no wait for" - " sync mode was requested") + self.LogWarning("Not shutting down the disk even if the instance is" + " not supposed to be running because no wait for" + " sync mode was requested") assert self.owned_locks(locking.LEVEL_NODE_RES) assert set([instance.name]) == self.owned_locks(locking.LEVEL_INSTANCE) @@ -12856,7 +12936,7 @@ class LUInstanceSetParams(LogicalUnit): This runs on the master, primary and secondaries. """ - args = dict() + args = {} if constants.BE_MINMEM in self.be_new: args["minmem"] = self.be_new[constants.BE_MINMEM] if constants.BE_MAXMEM in self.be_new: @@ -12907,7 +12987,7 @@ class LUInstanceSetParams(LogicalUnit): netparams = self.cfg.GetGroupNetParams(new_net, pnode) if netparams is None: raise errors.OpPrereqError("No netparams found for the network" - " %s, propably not connected." % new_net, + " %s, probably not connected" % new_net, errors.ECODE_INVAL) new_params = dict(netparams) else: @@ -13010,7 +13090,7 @@ class LUInstanceSetParams(LogicalUnit): elif (old_net is not None and (req_link is not None or req_mode is not None)): raise errors.OpPrereqError("Not allowed to change link or mode of" - " a NIC that is connected to a network.", + " a NIC that is connected to a network", errors.ECODE_INVAL) private.params = new_params @@ -13291,7 +13371,7 @@ class LUInstanceSetParams(LogicalUnit): errors.ECODE_STATE) disk_sizes = [disk.size for disk in instance.disks] disk_sizes.extend(params["size"] for (op, idx, params, private) in - self.diskmod) + self.diskmod if op == constants.DDM_ADD) ispec[constants.ISPEC_DISK_COUNT] = len(disk_sizes) ispec[constants.ISPEC_DISK_SIZE] = disk_sizes @@ -13684,9 +13764,11 @@ class LUInstanceChangeGroup(LogicalUnit): def ExpandNames(self): self.share_locks = _ShareAll() + self.needed_locks = { locking.LEVEL_NODEGROUP: [], locking.LEVEL_NODE: [], + locking.LEVEL_NODE_ALLOC: locking.ALL_SET, } self._ExpandAndLockInstance() @@ -14252,11 +14334,19 @@ class LUBackupRemove(NoHooksLU): REQ_BGL = False def ExpandNames(self): - self.needed_locks = {} - # We need all nodes to be locked in order for RemoveExport to work, but we - # don't need to lock the instance itself, as nothing will happen to it (and - # we can remove exports also for a removed instance) - self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET + self.needed_locks = { + # We need all nodes to be locked in order for RemoveExport to work, but + # we don't need to lock the instance itself, as nothing will happen to it + # (and we can remove exports also for a removed instance) + locking.LEVEL_NODE: locking.ALL_SET, + + # Removing backups is quick, so blocking allocations is justified + locking.LEVEL_NODE_ALLOC: locking.ALL_SET, + } + + # Allocations should be stopped while this LU runs with node locks, but it + # doesn't have to be exclusive + self.share_locks[locking.LEVEL_NODE_ALLOC] = 1 def Exec(self, feedback_fn): """Remove any export. @@ -15295,7 +15385,7 @@ class LUTestDelay(NoHooksLU): else: top_value = self.op.repeat - 1 for i in range(self.op.repeat): - self.LogInfo("Test delay iteration %d/%d" % (i, top_value)) + self.LogInfo("Test delay iteration %d/%d", i, top_value) self._TestDelay() @@ -15536,7 +15626,7 @@ class LUTestAllocator(NoHooksLU): self.op.mode, errors.ECODE_INVAL) if self.op.direction == constants.IALLOCATOR_DIR_OUT: - if self.op.allocator is None: + if self.op.iallocator is None: raise errors.OpPrereqError("Missing allocator name", errors.ECODE_INVAL) elif self.op.direction != constants.IALLOCATOR_DIR_IN: @@ -15589,12 +15679,11 @@ class LUTestAllocator(NoHooksLU): if self.op.direction == constants.IALLOCATOR_DIR_IN: result = ial.in_text else: - ial.Run(self.op.allocator, validate=False) + ial.Run(self.op.iallocator, validate=False) result = ial.out_text return result -# Network LUs class LUNetworkAdd(LogicalUnit): """Logical unit for creating networks. @@ -15610,18 +15699,25 @@ class LUNetworkAdd(LogicalUnit): mn = self.cfg.GetMasterNode() return ([mn], [mn]) + def CheckArguments(self): + if self.op.mac_prefix: + self.op.mac_prefix = \ + utils.NormalizeAndValidateThreeOctetMacPrefix(self.op.mac_prefix) + def ExpandNames(self): self.network_uuid = self.cfg.GenerateUniqueID(self.proc.GetECId()) - self.needed_locks = {} - self.add_locks[locking.LEVEL_NETWORK] = self.network_uuid - def CheckPrereq(self): - """Check prerequisites. + if self.op.conflicts_check: + self.share_locks[locking.LEVEL_NODE] = 1 + self.needed_locks = { + locking.LEVEL_NODE: locking.ALL_SET, + } + else: + self.needed_locks = {} - This checks that the given group name is not an existing node group - already. + self.add_locks[locking.LEVEL_NETWORK] = self.network_uuid - """ + def CheckPrereq(self): if self.op.network is None: raise errors.OpPrereqError("Network must be given", errors.ECODE_INVAL) @@ -15632,9 +15728,6 @@ class LUNetworkAdd(LogicalUnit): raise errors.OpPrereqError("Network '%s' already defined" % self.op.network, errors.ECODE_EXISTS) - if self.op.mac_prefix: - utils.NormalizeAndValidateMac(self.op.mac_prefix + ":00:00:00") - # Check tag validity for tag in self.op.tags: objects.TaggableObject.ValidateTag(tag) @@ -15667,7 +15760,7 @@ class LUNetworkAdd(LogicalUnit): mac_prefix=self.op.mac_prefix, network_type=self.op.network_type, uuid=self.network_uuid, - family=4) + family=constants.IP4_VERSION) # Initialize the associated address pool try: pool = network.AddressPool.InitializeNetwork(nobj) @@ -15677,21 +15770,26 @@ class LUNetworkAdd(LogicalUnit): # Check if we need to reserve the nodes and the cluster master IP # These may not be allocated to any instances in routed mode, as # they wouldn't function anyway. - for node in self.cfg.GetAllNodesInfo().values(): - for ip in [node.primary_ip, node.secondary_ip]: - try: - pool.Reserve(ip) - self.LogInfo("Reserved node %s's IP (%s)", node.name, ip) - - except errors.AddressPoolError: - pass + if self.op.conflicts_check: + for node in self.cfg.GetAllNodesInfo().values(): + for ip in [node.primary_ip, node.secondary_ip]: + try: + if pool.Contains(ip): + pool.Reserve(ip) + self.LogInfo("Reserved IP address of node '%s' (%s)", + node.name, ip) + except errors.AddressPoolError: + self.LogWarning("Cannot reserve IP address of node '%s' (%s)", + node.name, ip) - master_ip = self.cfg.GetClusterInfo().master_ip - try: - pool.Reserve(master_ip) - self.LogInfo("Reserved cluster master IP (%s)", master_ip) - except errors.AddressPoolError: - pass + master_ip = self.cfg.GetClusterInfo().master_ip + try: + if pool.Contains(master_ip): + pool.Reserve(master_ip) + self.LogInfo("Reserved cluster master IP address (%s)", master_ip) + except errors.AddressPoolError: + self.LogWarning("Cannot reserve cluster master IP address (%s)", + master_ip) if self.op.add_reserved_ips: for ip in self.op.add_reserved_ips: @@ -15717,10 +15815,14 @@ class LUNetworkRemove(LogicalUnit): self.network_uuid = self.cfg.LookupNetwork(self.op.network_name) if not self.network_uuid: - raise errors.OpPrereqError("Network %s not found" % self.op.network_name, + raise errors.OpPrereqError(("Network '%s' not found" % + self.op.network_name), errors.ECODE_INVAL) + + self.share_locks[locking.LEVEL_NODEGROUP] = 1 self.needed_locks = { locking.LEVEL_NETWORK: [self.network_uuid], + locking.LEVEL_NODEGROUP: locking.ALL_SET, } def CheckPrereq(self): @@ -15731,19 +15833,17 @@ class LUNetworkRemove(LogicalUnit): cluster. """ - # Verify that the network is not conncted. node_groups = [group.name for group in self.cfg.GetAllNodeGroupsInfo().values() - for net in group.networks.keys() - if net == self.network_uuid] + if self.network_uuid in group.networks] if node_groups: - self.LogWarning("Nework '%s' is connected to the following" - " node groups: %s" % (self.op.network_name, - utils.CommaJoin(utils.NiceSort(node_groups)))) - raise errors.OpPrereqError("Network still connected", - errors.ECODE_STATE) + self.LogWarning("Network '%s' is connected to the following" + " node groups: %s" % + (self.op.network_name, + utils.CommaJoin(utils.NiceSort(node_groups)))) + raise errors.OpPrereqError("Network still connected", errors.ECODE_STATE) def BuildHooksEnv(self): """Build hooks env. @@ -15787,11 +15887,11 @@ class LUNetworkSetParams(LogicalUnit): def ExpandNames(self): self.network_uuid = self.cfg.LookupNetwork(self.op.network_name) - self.network = self.cfg.GetNetwork(self.network_uuid) - if self.network is None: - raise errors.OpPrereqError("Could not retrieve network '%s' (UUID: %s)" % - (self.op.network_name, self.network_uuid), + if self.network_uuid is None: + raise errors.OpPrereqError(("Network '%s' not found" % + self.op.network_name), errors.ECODE_INVAL) + self.needed_locks = { locking.LEVEL_NETWORK: [self.network_uuid], } @@ -15800,6 +15900,7 @@ class LUNetworkSetParams(LogicalUnit): """Check prerequisites. """ + self.network = self.cfg.GetNetwork(self.network_uuid) self.gateway = self.network.gateway self.network_type = self.network.network_type self.mac_prefix = self.network.mac_prefix @@ -15828,8 +15929,8 @@ class LUNetworkSetParams(LogicalUnit): if self.op.mac_prefix == constants.VALUE_NONE: self.mac_prefix = None else: - utils.NormalizeAndValidateMac(self.op.mac_prefix + ":00:00:00") - self.mac_prefix = self.op.mac_prefix + self.mac_prefix = \ + utils.NormalizeAndValidateThreeOctetMacPrefix(self.op.mac_prefix) if self.op.gateway6: if self.op.gateway6 == constants.VALUE_NONE: @@ -15874,7 +15975,7 @@ class LUNetworkSetParams(LogicalUnit): # extend cfg.ReserveIp/ReleaseIp with the external flag if self.op.gateway: if self.gateway == self.network.gateway: - self.LogWarning("Gateway is already %s" % self.gateway) + self.LogWarning("Gateway is already %s", self.gateway) else: if self.gateway: self.pool.Reserve(self.gateway, external=True) @@ -15886,11 +15987,11 @@ class LUNetworkSetParams(LogicalUnit): for ip in self.op.add_reserved_ips: try: if self.pool.IsReserved(ip): - self.LogWarning("IP %s is already reserved" % ip) + self.LogWarning("IP address %s is already reserved", ip) else: self.pool.Reserve(ip, external=True) - except errors.AddressPoolError, e: - self.LogWarning("Cannot reserve ip %s. %s" % (ip, e)) + except errors.AddressPoolError, err: + self.LogWarning("Cannot reserve IP address %s: %s", ip, err) if self.op.remove_reserved_ips: for ip in self.op.remove_reserved_ips: @@ -15899,11 +16000,11 @@ class LUNetworkSetParams(LogicalUnit): continue try: if not self.pool.IsReserved(ip): - self.LogWarning("IP %s is already unreserved" % ip) + self.LogWarning("IP address %s is already unreserved", ip) else: self.pool.Release(ip, external=True) - except errors.AddressPoolError, e: - self.LogWarning("Cannot release ip %s. %s" % (ip, e)) + except errors.AddressPoolError, err: + self.LogWarning("Cannot release IP address %s: %s", ip, err) if self.op.mac_prefix: self.network.mac_prefix = self.mac_prefix @@ -15989,7 +16090,7 @@ class _NetworkQuery(_QueryBase): netparams = group.networks[net_uuid] mode = netparams[constants.NIC_MODE] link = netparams[constants.NIC_LINK] - info = group.name + '(' + mode + ', ' + link + ')' + info = group.name + "(" + mode + ", " + link + ")" network_to_groups[net_uuid].append(info) if do_instances: @@ -16008,7 +16109,8 @@ class _NetworkQuery(_QueryBase): "free_count": pool.GetFreeCount(), "reserved_count": pool.GetReservedCount(), "map": pool.GetMap(), - "external_reservations": ", ".join(pool.GetExternalReservations()), + "external_reservations": + utils.CommaJoin(pool.GetExternalReservations()), } return query.NetworkQueryData([self._all_networks[uuid] @@ -16050,14 +16152,12 @@ class LUNetworkConnect(LogicalUnit): self.network_link = self.op.network_link self.network_uuid = self.cfg.LookupNetwork(self.network_name) - self.network = self.cfg.GetNetwork(self.network_uuid) - if self.network is None: + if self.network_uuid is None: raise errors.OpPrereqError("Network %s does not exist" % self.network_name, errors.ECODE_INVAL) self.group_uuid = self.cfg.LookupNodeGroup(self.group_name) - self.group = self.cfg.GetNodeGroup(self.group_uuid) - if self.group is None: + if self.group_uuid is None: raise errors.OpPrereqError("Group %s does not exist" % self.group_name, errors.ECODE_INVAL) @@ -16067,21 +16167,26 @@ class LUNetworkConnect(LogicalUnit): } self.share_locks[locking.LEVEL_INSTANCE] = 1 + if self.op.conflicts_check: + self.needed_locks[locking.LEVEL_NETWORK] = [self.network_uuid] + self.share_locks[locking.LEVEL_NETWORK] = 1 + def DeclareLocks(self, level): if level == locking.LEVEL_INSTANCE: assert not self.needed_locks[locking.LEVEL_INSTANCE] # Lock instances optimistically, needs verification once group lock has # been acquired - self.needed_locks[locking.LEVEL_INSTANCE] = \ - self.cfg.GetNodeGroupInstances(self.group_uuid) + if self.op.conflicts_check: + self.needed_locks[locking.LEVEL_INSTANCE] = \ + self.cfg.GetNodeGroupInstances(self.group_uuid) def BuildHooksEnv(self): - ret = dict() - ret["GROUP_NAME"] = self.group_name - ret["GROUP_NETWORK_MODE"] = self.network_mode - ret["GROUP_NETWORK_LINK"] = self.network_link - ret.update(_BuildNetworkHookEnvByObject(self.network)) + ret = { + "GROUP_NAME": self.group_name, + "GROUP_NETWORK_MODE": self.network_mode, + "GROUP_NETWORK_LINK": self.network_link, + } return ret def BuildHooksNodes(self): @@ -16089,14 +16194,20 @@ class LUNetworkConnect(LogicalUnit): return (nodes, nodes) def CheckPrereq(self): - l = lambda value: ", ".join("%s: %s/%s" % (i[0], i[1], i[2]) - for i in value) + owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP)) + + assert self.group_uuid in owned_groups + + l = lambda value: utils.CommaJoin("%s: %s/%s" % (i[0], i[1], i[2]) + for i in value) - self.netparams = dict() - self.netparams[constants.NIC_MODE] = self.network_mode - self.netparams[constants.NIC_LINK] = self.network_link + self.netparams = { + constants.NIC_MODE: self.network_mode, + constants.NIC_LINK: self.network_link, + } objects.NIC.CheckParameterSyntax(self.netparams) + self.group = self.cfg.GetNodeGroup(self.group_uuid) #if self.network_mode == constants.NIC_MODE_BRIDGED: # _CheckNodeGroupBridgesExist(self, self.network_link, self.group_uuid) self.connected = False @@ -16106,20 +16217,25 @@ class LUNetworkConnect(LogicalUnit): self.connected = True return - pool = network.AddressPool(self.network) if self.op.conflicts_check: - groupinstances = [] - for n in self.cfg.GetNodeGroupInstances(self.group_uuid): - groupinstances.append(self.cfg.GetInstanceInfo(n)) - instances = [(instance.name, idx, nic.ip) - for instance in groupinstances - for idx, nic in enumerate(instance.nics) - if (not nic.network and pool.Contains(nic.ip))] - if instances: + # Check if locked instances are still correct + owned_instances = frozenset(self.owned_locks(locking.LEVEL_INSTANCE)) + _CheckNodeGroupInstances(self.cfg, self.group_uuid, owned_instances) + + nobj = self.cfg.GetNetwork(self.network_uuid) + pool = network.AddressPool(nobj) + conflicting_instances = [] + + for (_, instance) in self.cfg.GetMultiInstanceInfo(owned_instances): + for idx, nic in enumerate(instance.nics): + if pool.Contains(nic.ip): + conflicting_instances.append((instance.name, idx, nic.ip)) + + if conflicting_instances: self.LogWarning("Following occurences use IPs from network %s" " that is about to connect to nodegroup %s: %s" % (self.network_name, self.group.name, - l(instances))) + l(conflicting_instances))) raise errors.OpPrereqError("Conflicting IPs found." " Please remove/modify" " corresponding NICs", @@ -16146,14 +16262,12 @@ class LUNetworkDisconnect(LogicalUnit): self.group_name = self.op.group_name self.network_uuid = self.cfg.LookupNetwork(self.network_name) - self.network = self.cfg.GetNetwork(self.network_uuid) - if self.network is None: + if self.network_uuid is None: raise errors.OpPrereqError("Network %s does not exist" % self.network_name, errors.ECODE_INVAL) self.group_uuid = self.cfg.LookupNodeGroup(self.group_name) - self.group = self.cfg.GetNodeGroup(self.group_uuid) - if self.group is None: + if self.group_uuid is None: raise errors.OpPrereqError("Group %s does not exist" % self.group_name, errors.ECODE_INVAL) @@ -16169,13 +16283,14 @@ class LUNetworkDisconnect(LogicalUnit): # Lock instances optimistically, needs verification once group lock has # been acquired - self.needed_locks[locking.LEVEL_INSTANCE] = \ + if self.op.conflicts_check: + self.needed_locks[locking.LEVEL_INSTANCE] = \ self.cfg.GetNodeGroupInstances(self.group_uuid) def BuildHooksEnv(self): - ret = dict() - ret["GROUP_NAME"] = self.group_name - ret.update(_BuildNetworkHookEnvByObject(self.network)) + ret = { + "GROUP_NAME": self.group_name, + } return ret def BuildHooksNodes(self): @@ -16183,31 +16298,39 @@ class LUNetworkDisconnect(LogicalUnit): return (nodes, nodes) def CheckPrereq(self): - l = lambda value: ", ".join("%s: %s/%s" % (i[0], i[1], i[2]) - for i in value) + owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP)) + + assert self.group_uuid in owned_groups + + l = lambda value: utils.CommaJoin("%s: %s/%s" % (i[0], i[1], i[2]) + for i in value) + self.group = self.cfg.GetNodeGroup(self.group_uuid) self.connected = True if self.network_uuid not in self.group.networks: - self.LogWarning("Network '%s' is" - " not mapped to group '%s'" % - (self.network_name, self.group.name)) + self.LogWarning("Network '%s' is not mapped to group '%s'", + self.network_name, self.group.name) self.connected = False return if self.op.conflicts_check: - groupinstances = [] - for n in self.cfg.GetNodeGroupInstances(self.group_uuid): - groupinstances.append(self.cfg.GetInstanceInfo(n)) - instances = [(instance.name, idx, nic.ip) - for instance in groupinstances - for idx, nic in enumerate(instance.nics) - if nic.network == self.network_name] - if instances: + # Check if locked instances are still correct + owned_instances = frozenset(self.owned_locks(locking.LEVEL_INSTANCE)) + _CheckNodeGroupInstances(self.cfg, self.group_uuid, owned_instances) + + conflicting_instances = [] + + for (_, instance) in self.cfg.GetMultiInstanceInfo(owned_instances): + for idx, nic in enumerate(instance.nics): + if nic.network == self.network_name: + conflicting_instances.append((instance.name, idx, nic.ip)) + + if conflicting_instances: self.LogWarning("Following occurences use IPs from network %s" " that is about to disconnected from the nodegroup" " %s: %s" % (self.network_name, self.group.name, - l(instances))) + l(conflicting_instances))) raise errors.OpPrereqError("Conflicting IPs." " Please remove/modify" " corresponding NICS",