diff --git a/lib/cmdlib.py b/lib/cmdlib.py index 3e7e6bda98bb68e6840be308ca065307893ba834..15a99fbc7c8d8e53388057d4f894eefdf68ac2c2 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -1340,7 +1340,7 @@ def _BuildInstanceHookEnv(name, primary_node, secondary_nodes, os_type, status, @type vcpus: string @param vcpus: the count of VCPUs the instance has @type nics: list - @param nics: list of tuples (ip, mac, mode, link) representing + @param nics: list of tuples (ip, mac, mode, link, network) representing the NICs the instance has @type disk_template: string @param disk_template: the disk template of the instance @@ -1375,13 +1375,14 @@ def _BuildInstanceHookEnv(name, primary_node, secondary_nodes, os_type, status, } if nics: nic_count = len(nics) - for idx, (ip, mac, mode, link) in enumerate(nics): + for idx, (ip, mac, mode, link, network) in enumerate(nics): if ip is None: ip = "" env["INSTANCE_NIC%d_IP" % idx] = ip env["INSTANCE_NIC%d_MAC" % idx] = mac env["INSTANCE_NIC%d_MODE" % idx] = mode env["INSTANCE_NIC%d_LINK" % idx] = link + env["INSTANCE_NIC%d_NETWORK" % idx] = network if mode == constants.NIC_MODE_BRIDGED: env["INSTANCE_NIC%d_BRIDGE" % idx] = link else: @@ -1431,7 +1432,8 @@ def _NICListToTuple(lu, nics): filled_params = cluster.SimpleFillNIC(nic.nicparams) mode = filled_params[constants.NIC_MODE] link = filled_params[constants.NIC_LINK] - hooks_nics.append((ip, mac, mode, link)) + network = nic.network + hooks_nics.append((ip, mac, mode, link, network)) return hooks_nics @@ -9411,14 +9413,19 @@ def _ComputeNics(op, cluster, default_ip, cfg, proc): if nic_mode is None or nic_mode == constants.VALUE_AUTO: nic_mode = cluster.nicparams[constants.PP_DEFAULT][constants.NIC_MODE] - # in routed mode, for the first nic, the default ip is 'auto' - if nic_mode == constants.NIC_MODE_ROUTED and idx == 0: - default_ip_mode = constants.VALUE_AUTO + net = nic.get(constants.INIC_NETWORK, None) + link = nic.get(constants.NIC_LINK, None) + ip = nic.get(constants.INIC_IP, None) + + if net is None or net.lower() == constants.VALUE_NONE: + net = None else: - default_ip_mode = constants.VALUE_NONE + if nic_mode_req is not None or link is not None: + raise errors.OpPrereqError("If network is given, no mode or link" + " is allowed to be passed", + errors.ECODE_INVAL) # ip validity checks - ip = nic.get(constants.INIC_IP, default_ip_mode) if ip is None or ip.lower() == constants.VALUE_NONE: nic_ip = None elif ip.lower() == constants.VALUE_AUTO: @@ -9428,9 +9435,18 @@ def _ComputeNics(op, cluster, default_ip, cfg, proc): errors.ECODE_INVAL) nic_ip = default_ip else: - if not netutils.IPAddress.IsValid(ip): + # We defer pool operations until later, so that the iallocator has + # filled in the instance's node(s) dimara + if ip.lower() == constants.NIC_IP_POOL: + if net is None: + raise errors.OpPrereqError("if ip=pool, parameter network" + " must be passed too", + errors.ECODE_INVAL) + + elif not netutils.IPAddress.IsValid(ip): raise errors.OpPrereqError("Invalid IP address '%s'" % ip, errors.ECODE_INVAL) + nic_ip = ip # TODO: check the ip address for uniqueness @@ -9452,9 +9468,6 @@ def _ComputeNics(op, cluster, default_ip, cfg, proc): errors.ECODE_NOTUNIQUE) # Build nic parameters - link = nic.get(constants.INIC_LINK, None) - if link == constants.VALUE_AUTO: - link = cluster.nicparams[constants.PP_DEFAULT][constants.NIC_LINK] nicparams = {} if nic_mode_req: nicparams[constants.NIC_MODE] = nic_mode @@ -9749,6 +9762,8 @@ class LUInstanceCreate(LogicalUnit): """Run the allocator based on input opcode. """ + #TODO Export network to iallocator so that it chooses a pnode + # in a nodegroup that has the desired network connected to req = _CreateInstanceAllocRequest(self.op, self.disks, self.nics, self.be_full) ial = iallocator.IAllocator(self.cfg, self.rpc, req) @@ -10138,6 +10153,45 @@ class LUInstanceCreate(LogicalUnit): self.secondaries = [] + # Fill in any IPs from IP pools. This must happen here, because we need to + # know the nic's primary node, as specified by the iallocator + for idx, nic in enumerate(self.nics): + net = nic.network + if net is not None: + netparams = self.cfg.GetGroupNetParams(net, self.pnode.name) + if netparams is None: + raise errors.OpPrereqError("No netparams found for network" + " %s. Propably not connected to" + " node's %s nodegroup" % + (net, self.pnode.name), + errors.ECODE_INVAL) + self.LogInfo("NIC/%d inherits netparams %s" % + (idx, netparams.values())) + nic.nicparams = dict(netparams) + if nic.ip is not None: + filled_params = cluster.SimpleFillNIC(nic.nicparams) + if nic.ip.lower() == constants.NIC_IP_POOL: + try: + nic.ip = self.cfg.GenerateIp(net, self.proc.GetECId()) + except errors.ReservationError: + raise errors.OpPrereqError("Unable to get a free IP for NIC %d" + " from the address pool" % idx, + errors.ECODE_STATE) + self.LogInfo("Chose IP %s from network %s", nic.ip, net) + else: + try: + self.cfg.ReserveIp(net, nic.ip, self.proc.GetECId()) + except errors.ReservationError: + raise errors.OpPrereqError("IP address %s already in use" + " or does not belong to network %s" % + (nic.ip, net), + errors.ECODE_NOTUNIQUE) + else: + # net is None, ip None or given + if self.op.conflicts_check: + _CheckForConflictingIp(self, nic.ip, self.pnode.name) + + # mirror node verification if self.op.disk_template in constants.DTS_INT_MIRROR: if self.op.snode == pnode.name: @@ -15943,3 +15997,20 @@ def _GetQueryImplementation(name): except KeyError: raise errors.OpPrereqError("Unknown query resource '%s'" % name, errors.ECODE_INVAL) + +def _CheckForConflictingIp(lu, ip, node): + """In case of conflicting ip raise error. + + @type ip: string + @param ip: ip address + @type node: string + @param node: node name + + """ + (conf_net, conf_netparams) = lu.cfg.CheckIPInNodeGroup(ip, node) + if conf_net is not None: + raise errors.OpPrereqError("Conflicting IP found:" + " %s <> %s." % (ip, conf_net), + errors.ECODE_INVAL) + + return (None, None) diff --git a/lib/config.py b/lib/config.py index b97414c03f90c7f0a23937f17b19e1cb6460b5ac..cca0bf695bbc82984a467fcbaf3c3ce6f4c355c0 100644 --- a/lib/config.py +++ b/lib/config.py @@ -1359,6 +1359,7 @@ class ConfigWriter: self._config_data.instances[instance.name] = instance self._config_data.cluster.serial_no += 1 self._UnlockedReleaseDRBDMinors(instance.name) + self._UnlockedCommitTemporaryIps(ec_id) self._WriteConfig() def _EnsureUUID(self, item, ec_id):