LUNetwork* and associated helper functions are extracted to network.py.
Signed-off-by: Thomas Thrainer <[email protected]>
---
Makefile.am | 3 +-
lib/cmdlib/__init__.py | 714 +-----------------------------------------------
lib/cmdlib/common.py | 25 ++
lib/cmdlib/network.py | 718 +++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 749 insertions(+), 711 deletions(-)
create mode 100644 lib/cmdlib/network.py
diff --git a/Makefile.am b/Makefile.am
index 35d1e5d..58b1869 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -311,7 +311,8 @@ cmdlib_PYTHON = \
lib/cmdlib/__init__.py \
lib/cmdlib/common.py \
lib/cmdlib/base.py \
- lib/cmdlib/tags.py
+ lib/cmdlib/tags.py \
+ lib/cmdlib/network.py
hypervisor_PYTHON = \
lib/hypervisor/__init__.py \
diff --git a/lib/cmdlib/__init__.py b/lib/cmdlib/__init__.py
index c3148af..88aa001 100644
--- a/lib/cmdlib/__init__.py
+++ b/lib/cmdlib/__init__.py
@@ -66,8 +66,11 @@ from ganeti.masterd import iallocator
from ganeti.cmdlib.base import ResultWithJobs, LogicalUnit, NoHooksLU, \
Tasklet, _QueryBase
from ganeti.cmdlib.common import _ExpandInstanceName, _ExpandItemName, \
- _ExpandNodeName, _ShareAll
+ _ExpandNodeName, _ShareAll, _CheckNodeGroupInstances
from ganeti.cmdlib.tags import LUTagsGet, LUTagsSearch, LUTagsSet, LUTagsDel
+from ganeti.cmdlib.network import LUNetworkAdd, LUNetworkRemove, \
+ LUNetworkSetParams, _NetworkQuery, LUNetworkQuery, LUNetworkConnect, \
+ LUNetworkDisconnect
import ganeti.masterd.instance # pylint: disable=W0611
@@ -153,30 +156,6 @@ def _CheckInstanceNodeGroups(cfg, instance_name,
owned_groups,
return inst_groups
-def _CheckNodeGroupInstances(cfg, group_uuid, owned_instances):
- """Checks if the instances in a node group are still correct.
-
- @type cfg: L{config.ConfigWriter}
- @param cfg: The cluster configuration
- @type group_uuid: string
- @param group_uuid: Node group UUID
- @type owned_instances: set or frozenset
- @param owned_instances: List of currently owned instances
-
- """
- wanted_instances = cfg.GetNodeGroupInstances(group_uuid)
- if owned_instances != wanted_instances:
- raise errors.OpPrereqError("Instances in node group '%s' changed since"
- " locks were acquired, wanted '%s', have '%s';"
- " retry the operation" %
- (group_uuid,
- utils.CommaJoin(wanted_instances),
- utils.CommaJoin(owned_instances)),
- errors.ECODE_STATE)
-
- return wanted_instances
-
-
def _SupportsOob(cfg, node):
"""Tells if node supports OOB.
@@ -898,47 +877,6 @@ def _ComputeNewInstanceViolations(old_ipolicy,
new_ipolicy, instances, cfg):
_ComputeViolatingInstances(old_ipolicy, instances, cfg))
-def _BuildNetworkHookEnv(name, subnet, gateway, network6, gateway6,
- mac_prefix, tags):
- """Builds network related env variables for hooks
-
- This builds the hook environment from individual variables.
-
- @type name: string
- @param name: the name of the network
- @type subnet: string
- @param subnet: the ipv4 subnet
- @type gateway: string
- @param gateway: the ipv4 gateway
- @type network6: string
- @param network6: the ipv6 subnet
- @type gateway6: string
- @param gateway6: the ipv6 gateway
- @type mac_prefix: string
- @param mac_prefix: the mac_prefix
- @type tags: list
- @param tags: the tags of the network
-
- """
- env = {}
- if name:
- env["NETWORK_NAME"] = name
- if subnet:
- env["NETWORK_SUBNET"] = subnet
- if gateway:
- env["NETWORK_GATEWAY"] = gateway
- if network6:
- env["NETWORK_SUBNET6"] = network6
- if gateway6:
- env["NETWORK_GATEWAY6"] = gateway6
- if mac_prefix:
- env["NETWORK_MAC_PREFIX"] = mac_prefix
- if tags:
- env["NETWORK_TAGS"] = " ".join(tags)
-
- return env
-
-
def _BuildInstanceHookEnv(name, primary_node, secondary_nodes, os_type, status,
minmem, maxmem, vcpus, nics, disk_template, disks,
bep, hvp, hypervisor_name, tags):
@@ -15715,650 +15653,6 @@ class LUTestAllocator(NoHooksLU):
return result
-class LUNetworkAdd(LogicalUnit):
- """Logical unit for creating networks.
-
- """
- HPATH = "network-add"
- HTYPE = constants.HTYPE_NETWORK
- REQ_BGL = False
-
- def BuildHooksNodes(self):
- """Build hooks nodes.
-
- """
- 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())
-
- if self.op.conflicts_check:
- self.share_locks[locking.LEVEL_NODE] = 1
- self.share_locks[locking.LEVEL_NODE_ALLOC] = 1
- self.needed_locks = {
- locking.LEVEL_NODE: locking.ALL_SET,
- locking.LEVEL_NODE_ALLOC: locking.ALL_SET,
- }
- else:
- self.needed_locks = {}
-
- 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)
-
- try:
- existing_uuid = self.cfg.LookupNetwork(self.op.network_name)
- except errors.OpPrereqError:
- pass
- else:
- raise errors.OpPrereqError("Desired network name '%s' already exists as
a"
- " network (UUID: %s)" %
- (self.op.network_name, existing_uuid),
- errors.ECODE_EXISTS)
-
- # Check tag validity
- for tag in self.op.tags:
- objects.TaggableObject.ValidateTag(tag)
-
- def BuildHooksEnv(self):
- """Build hooks env.
-
- """
- args = {
- "name": self.op.network_name,
- "subnet": self.op.network,
- "gateway": self.op.gateway,
- "network6": self.op.network6,
- "gateway6": self.op.gateway6,
- "mac_prefix": self.op.mac_prefix,
- "tags": self.op.tags,
- }
- return _BuildNetworkHookEnv(**args) # pylint: disable=W0142
-
- def Exec(self, feedback_fn):
- """Add the ip pool to the cluster.
-
- """
- nobj = objects.Network(name=self.op.network_name,
- network=self.op.network,
- gateway=self.op.gateway,
- network6=self.op.network6,
- gateway6=self.op.gateway6,
- mac_prefix=self.op.mac_prefix,
- uuid=self.network_uuid)
- # Initialize the associated address pool
- try:
- pool = network.AddressPool.InitializeNetwork(nobj)
- except errors.AddressPoolError, err:
- raise errors.OpExecError("Cannot create IP address pool for network"
- " '%s': %s" % (self.op.network_name, err))
-
- # 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.
- 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, err:
- self.LogWarning("Cannot reserve IP address '%s' of node '%s': %s",
- ip, node.name, err)
-
- 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, err:
- self.LogWarning("Cannot reserve cluster master IP address (%s): %s",
- master_ip, err)
-
- if self.op.add_reserved_ips:
- for ip in self.op.add_reserved_ips:
- try:
- pool.Reserve(ip, external=True)
- except errors.AddressPoolError, err:
- raise errors.OpExecError("Cannot reserve IP address '%s': %s" %
- (ip, err))
-
- if self.op.tags:
- for tag in self.op.tags:
- nobj.AddTag(tag)
-
- self.cfg.AddNetwork(nobj, self.proc.GetECId(), check_uuid=False)
- del self.remove_locks[locking.LEVEL_NETWORK]
-
-
-class LUNetworkRemove(LogicalUnit):
- HPATH = "network-remove"
- HTYPE = constants.HTYPE_NETWORK
- REQ_BGL = False
-
- def ExpandNames(self):
- self.network_uuid = self.cfg.LookupNetwork(self.op.network_name)
-
- 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):
- """Check prerequisites.
-
- This checks that the given network name exists as a network, that is
- empty (i.e., contains no nodes), and that is not the last group of the
- cluster.
-
- """
- # Verify that the network is not conncted.
- node_groups = [group.name
- for group in self.cfg.GetAllNodeGroupsInfo().values()
- if self.network_uuid in group.networks]
-
- if node_groups:
- 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.
-
- """
- return {
- "NETWORK_NAME": self.op.network_name,
- }
-
- def BuildHooksNodes(self):
- """Build hooks nodes.
-
- """
- mn = self.cfg.GetMasterNode()
- return ([mn], [mn])
-
- def Exec(self, feedback_fn):
- """Remove the network.
-
- """
- try:
- self.cfg.RemoveNetwork(self.network_uuid)
- except errors.ConfigurationError:
- raise errors.OpExecError("Network '%s' with UUID %s disappeared" %
- (self.op.network_name, self.network_uuid))
-
-
-class LUNetworkSetParams(LogicalUnit):
- """Modifies the parameters of a network.
-
- """
- HPATH = "network-modify"
- HTYPE = constants.HTYPE_NETWORK
- REQ_BGL = False
-
- def CheckArguments(self):
- if (self.op.gateway and
- (self.op.add_reserved_ips or self.op.remove_reserved_ips)):
- raise errors.OpPrereqError("Cannot modify gateway and reserved ips"
- " at once", errors.ECODE_INVAL)
-
- def ExpandNames(self):
- self.network_uuid = self.cfg.LookupNetwork(self.op.network_name)
-
- self.needed_locks = {
- locking.LEVEL_NETWORK: [self.network_uuid],
- }
-
- def CheckPrereq(self):
- """Check prerequisites.
-
- """
- self.network = self.cfg.GetNetwork(self.network_uuid)
- self.gateway = self.network.gateway
- self.mac_prefix = self.network.mac_prefix
- self.network6 = self.network.network6
- self.gateway6 = self.network.gateway6
- self.tags = self.network.tags
-
- self.pool = network.AddressPool(self.network)
-
- if self.op.gateway:
- if self.op.gateway == constants.VALUE_NONE:
- self.gateway = None
- else:
- self.gateway = self.op.gateway
- if self.pool.IsReserved(self.gateway):
- raise errors.OpPrereqError("Gateway IP address '%s' is already"
- " reserved" % self.gateway,
- errors.ECODE_STATE)
-
- if self.op.mac_prefix:
- if self.op.mac_prefix == constants.VALUE_NONE:
- self.mac_prefix = None
- else:
- self.mac_prefix = \
- utils.NormalizeAndValidateThreeOctetMacPrefix(self.op.mac_prefix)
-
- if self.op.gateway6:
- if self.op.gateway6 == constants.VALUE_NONE:
- self.gateway6 = None
- else:
- self.gateway6 = self.op.gateway6
-
- if self.op.network6:
- if self.op.network6 == constants.VALUE_NONE:
- self.network6 = None
- else:
- self.network6 = self.op.network6
-
- def BuildHooksEnv(self):
- """Build hooks env.
-
- """
- args = {
- "name": self.op.network_name,
- "subnet": self.network.network,
- "gateway": self.gateway,
- "network6": self.network6,
- "gateway6": self.gateway6,
- "mac_prefix": self.mac_prefix,
- "tags": self.tags,
- }
- return _BuildNetworkHookEnv(**args) # pylint: disable=W0142
-
- def BuildHooksNodes(self):
- """Build hooks nodes.
-
- """
- mn = self.cfg.GetMasterNode()
- return ([mn], [mn])
-
- def Exec(self, feedback_fn):
- """Modifies the network.
-
- """
- #TODO: reserve/release via temporary reservation manager
- # 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)
- else:
- if self.gateway:
- self.pool.Reserve(self.gateway, external=True)
- if self.network.gateway:
- self.pool.Release(self.network.gateway, external=True)
- self.network.gateway = self.gateway
-
- if self.op.add_reserved_ips:
- for ip in self.op.add_reserved_ips:
- try:
- if self.pool.IsReserved(ip):
- self.LogWarning("IP address %s is already reserved", ip)
- else:
- self.pool.Reserve(ip, external=True)
- 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:
- if ip == self.network.gateway:
- self.LogWarning("Cannot unreserve Gateway's IP")
- continue
- try:
- if not self.pool.IsReserved(ip):
- self.LogWarning("IP address %s is already unreserved", ip)
- else:
- self.pool.Release(ip, external=True)
- 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
-
- if self.op.network6:
- self.network.network6 = self.network6
-
- if self.op.gateway6:
- self.network.gateway6 = self.gateway6
-
- self.pool.Validate()
-
- self.cfg.Update(self.network, feedback_fn)
-
-
-class _NetworkQuery(_QueryBase):
- FIELDS = query.NETWORK_FIELDS
-
- def ExpandNames(self, lu):
- lu.needed_locks = {}
- lu.share_locks = _ShareAll()
-
- self.do_locking = self.use_locking
-
- all_networks = lu.cfg.GetAllNetworksInfo()
- name_to_uuid = dict((n.name, n.uuid) for n in all_networks.values())
-
- if self.names:
- missing = []
- self.wanted = []
-
- for name in self.names:
- if name in name_to_uuid:
- self.wanted.append(name_to_uuid[name])
- else:
- missing.append(name)
-
- if missing:
- raise errors.OpPrereqError("Some networks do not exist: %s" % missing,
- errors.ECODE_NOENT)
- else:
- self.wanted = locking.ALL_SET
-
- if self.do_locking:
- lu.needed_locks[locking.LEVEL_NETWORK] = self.wanted
- if query.NETQ_INST in self.requested_data:
- lu.needed_locks[locking.LEVEL_INSTANCE] = locking.ALL_SET
- if query.NETQ_GROUP in self.requested_data:
- lu.needed_locks[locking.LEVEL_NODEGROUP] = locking.ALL_SET
-
- def DeclareLocks(self, lu, level):
- pass
-
- def _GetQueryData(self, lu):
- """Computes the list of networks and their attributes.
-
- """
- all_networks = lu.cfg.GetAllNetworksInfo()
-
- network_uuids = self._GetNames(lu, all_networks.keys(),
- locking.LEVEL_NETWORK)
-
- do_instances = query.NETQ_INST in self.requested_data
- do_groups = query.NETQ_GROUP in self.requested_data
-
- network_to_instances = None
- network_to_groups = None
-
- # For NETQ_GROUP, we need to map network->[groups]
- if do_groups:
- all_groups = lu.cfg.GetAllNodeGroupsInfo()
- network_to_groups = dict((uuid, []) for uuid in network_uuids)
- for _, group in all_groups.iteritems():
- for net_uuid in network_uuids:
- netparams = group.networks.get(net_uuid, None)
- if netparams:
- info = (group.name, netparams[constants.NIC_MODE],
- netparams[constants.NIC_LINK])
-
- network_to_groups[net_uuid].append(info)
-
- if do_instances:
- all_instances = lu.cfg.GetAllInstancesInfo()
- network_to_instances = dict((uuid, []) for uuid in network_uuids)
- for instance in all_instances.values():
- for nic in instance.nics:
- if nic.network in network_uuids:
- network_to_instances[nic.network].append(instance.name)
- break
-
- if query.NETQ_STATS in self.requested_data:
- stats = \
- dict((uuid,
- self._GetStats(network.AddressPool(all_networks[uuid])))
- for uuid in network_uuids)
- else:
- stats = None
-
- return query.NetworkQueryData([all_networks[uuid]
- for uuid in network_uuids],
- network_to_groups,
- network_to_instances,
- stats)
-
- @staticmethod
- def _GetStats(pool):
- """Returns statistics for a network address pool.
-
- """
- return {
- "free_count": pool.GetFreeCount(),
- "reserved_count": pool.GetReservedCount(),
- "map": pool.GetMap(),
- "external_reservations":
- utils.CommaJoin(pool.GetExternalReservations()),
- }
-
-
-class LUNetworkQuery(NoHooksLU):
- """Logical unit for querying networks.
-
- """
- REQ_BGL = False
-
- def CheckArguments(self):
- self.nq = _NetworkQuery(qlang.MakeSimpleFilter("name", self.op.names),
- self.op.output_fields, self.op.use_locking)
-
- def ExpandNames(self):
- self.nq.ExpandNames(self)
-
- def Exec(self, feedback_fn):
- return self.nq.OldStyleQuery(self)
-
-
-class LUNetworkConnect(LogicalUnit):
- """Connect a network to a nodegroup
-
- """
- HPATH = "network-connect"
- HTYPE = constants.HTYPE_NETWORK
- REQ_BGL = False
-
- def ExpandNames(self):
- self.network_name = self.op.network_name
- self.group_name = self.op.group_name
- self.network_mode = self.op.network_mode
- self.network_link = self.op.network_link
-
- self.network_uuid = self.cfg.LookupNetwork(self.network_name)
- self.group_uuid = self.cfg.LookupNodeGroup(self.group_name)
-
- self.needed_locks = {
- locking.LEVEL_INSTANCE: [],
- locking.LEVEL_NODEGROUP: [self.group_uuid],
- }
- 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
- if self.op.conflicts_check:
- self.needed_locks[locking.LEVEL_INSTANCE] = \
- self.cfg.GetNodeGroupInstances(self.group_uuid)
-
- def BuildHooksEnv(self):
- ret = {
- "GROUP_NAME": self.group_name,
- "GROUP_NETWORK_MODE": self.network_mode,
- "GROUP_NETWORK_LINK": self.network_link,
- }
- return ret
-
- def BuildHooksNodes(self):
- nodes = self.cfg.GetNodeGroup(self.group_uuid).members
- return (nodes, nodes)
-
- def CheckPrereq(self):
- owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP))
-
- assert self.group_uuid in owned_groups
-
- # Check if locked instances are still correct
- owned_instances = frozenset(self.owned_locks(locking.LEVEL_INSTANCE))
- if self.op.conflicts_check:
- _CheckNodeGroupInstances(self.cfg, self.group_uuid, owned_instances)
-
- 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
- if self.network_uuid in self.group.networks:
- self.LogWarning("Network '%s' is already mapped to group '%s'" %
- (self.network_name, self.group.name))
- self.connected = True
-
- # check only if not already connected
- elif self.op.conflicts_check:
- pool = network.AddressPool(self.cfg.GetNetwork(self.network_uuid))
-
- _NetworkConflictCheck(self, lambda nic: pool.Contains(nic.ip),
- "connect to", owned_instances)
-
- def Exec(self, feedback_fn):
- # Connect the network and update the group only if not already connected
- if not self.connected:
- self.group.networks[self.network_uuid] = self.netparams
- self.cfg.Update(self.group, feedback_fn)
-
-
-def _NetworkConflictCheck(lu, check_fn, action, instances):
- """Checks for network interface conflicts with a network.
-
- @type lu: L{LogicalUnit}
- @type check_fn: callable receiving one parameter (L{objects.NIC}) and
- returning boolean
- @param check_fn: Function checking for conflict
- @type action: string
- @param action: Part of error message (see code)
- @raise errors.OpPrereqError: If conflicting IP addresses are found.
-
- """
- conflicts = []
-
- for (_, instance) in lu.cfg.GetMultiInstanceInfo(instances):
- instconflicts = [(idx, nic.ip)
- for (idx, nic) in enumerate(instance.nics)
- if check_fn(nic)]
-
- if instconflicts:
- conflicts.append((instance.name, instconflicts))
-
- if conflicts:
- lu.LogWarning("IP addresses from network '%s', which is about to %s"
- " node group '%s', are in use: %s" %
- (lu.network_name, action, lu.group.name,
- utils.CommaJoin(("%s: %s" %
- (name, _FmtNetworkConflict(details)))
- for (name, details) in conflicts)))
-
- raise errors.OpPrereqError("Conflicting IP addresses found; "
- " remove/modify the corresponding network"
- " interfaces", errors.ECODE_STATE)
-
-
-def _FmtNetworkConflict(details):
- """Utility for L{_NetworkConflictCheck}.
-
- """
- return utils.CommaJoin("nic%s/%s" % (idx, ipaddr)
- for (idx, ipaddr) in details)
-
-
-class LUNetworkDisconnect(LogicalUnit):
- """Disconnect a network to a nodegroup
-
- """
- HPATH = "network-disconnect"
- HTYPE = constants.HTYPE_NETWORK
- REQ_BGL = False
-
- def ExpandNames(self):
- self.network_name = self.op.network_name
- self.group_name = self.op.group_name
-
- self.network_uuid = self.cfg.LookupNetwork(self.network_name)
- self.group_uuid = self.cfg.LookupNodeGroup(self.group_name)
-
- self.needed_locks = {
- locking.LEVEL_INSTANCE: [],
- locking.LEVEL_NODEGROUP: [self.group_uuid],
- }
- self.share_locks[locking.LEVEL_INSTANCE] = 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)
-
- def BuildHooksEnv(self):
- ret = {
- "GROUP_NAME": self.group_name,
- }
- return ret
-
- def BuildHooksNodes(self):
- nodes = self.cfg.GetNodeGroup(self.group_uuid).members
- return (nodes, nodes)
-
- def CheckPrereq(self):
- owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP))
-
- assert self.group_uuid in owned_groups
-
- # Check if locked instances are still correct
- owned_instances = frozenset(self.owned_locks(locking.LEVEL_INSTANCE))
- _CheckNodeGroupInstances(self.cfg, self.group_uuid, owned_instances)
-
- 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.connected = False
-
- # We need this check only if network is not already connected
- else:
- _NetworkConflictCheck(self, lambda nic: nic.network == self.network_uuid,
- "disconnect from", owned_instances)
-
- def Exec(self, feedback_fn):
- # Disconnect the network and update the group only if network is connected
- if self.connected:
- del self.group.networks[self.network_uuid]
- self.cfg.Update(self.group, feedback_fn)
-
-
#: Query type implementations
_QUERY_IMPL = {
constants.QR_CLUSTER: _ClusterQuery,
diff --git a/lib/cmdlib/common.py b/lib/cmdlib/common.py
index 60d5fe5..f3bd9e4 100644
--- a/lib/cmdlib/common.py
+++ b/lib/cmdlib/common.py
@@ -23,6 +23,7 @@
from ganeti import errors
from ganeti import locking
+from ganeti import utils
def _ExpandItemName(fn, name, kind):
@@ -57,3 +58,27 @@ def _ShareAll():
"""
return dict.fromkeys(locking.LEVELS, 1)
+
+
+def _CheckNodeGroupInstances(cfg, group_uuid, owned_instances):
+ """Checks if the instances in a node group are still correct.
+
+ @type cfg: L{config.ConfigWriter}
+ @param cfg: The cluster configuration
+ @type group_uuid: string
+ @param group_uuid: Node group UUID
+ @type owned_instances: set or frozenset
+ @param owned_instances: List of currently owned instances
+
+ """
+ wanted_instances = cfg.GetNodeGroupInstances(group_uuid)
+ if owned_instances != wanted_instances:
+ raise errors.OpPrereqError("Instances in node group '%s' changed since"
+ " locks were acquired, wanted '%s', have '%s';"
+ " retry the operation" %
+ (group_uuid,
+ utils.CommaJoin(wanted_instances),
+ utils.CommaJoin(owned_instances)),
+ errors.ECODE_STATE)
+
+ return wanted_instances
diff --git a/lib/cmdlib/network.py b/lib/cmdlib/network.py
new file mode 100644
index 0000000..0488ceb
--- /dev/null
+++ b/lib/cmdlib/network.py
@@ -0,0 +1,718 @@
+#
+#
+
+# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+
+"""Logical units dealing with networks."""
+
+from ganeti import constants
+from ganeti import errors
+from ganeti import locking
+from ganeti import network
+from ganeti import objects
+from ganeti import qlang
+from ganeti import query
+from ganeti import utils
+from ganeti.cmdlib.base import LogicalUnit, NoHooksLU, _QueryBase
+from ganeti.cmdlib.common import _ShareAll, _CheckNodeGroupInstances
+
+
+def _BuildNetworkHookEnv(name, subnet, gateway, network6, gateway6,
+ mac_prefix, tags):
+ """Builds network related env variables for hooks
+
+ This builds the hook environment from individual variables.
+
+ @type name: string
+ @param name: the name of the network
+ @type subnet: string
+ @param subnet: the ipv4 subnet
+ @type gateway: string
+ @param gateway: the ipv4 gateway
+ @type network6: string
+ @param network6: the ipv6 subnet
+ @type gateway6: string
+ @param gateway6: the ipv6 gateway
+ @type mac_prefix: string
+ @param mac_prefix: the mac_prefix
+ @type tags: list
+ @param tags: the tags of the network
+
+ """
+ env = {}
+ if name:
+ env["NETWORK_NAME"] = name
+ if subnet:
+ env["NETWORK_SUBNET"] = subnet
+ if gateway:
+ env["NETWORK_GATEWAY"] = gateway
+ if network6:
+ env["NETWORK_SUBNET6"] = network6
+ if gateway6:
+ env["NETWORK_GATEWAY6"] = gateway6
+ if mac_prefix:
+ env["NETWORK_MAC_PREFIX"] = mac_prefix
+ if tags:
+ env["NETWORK_TAGS"] = " ".join(tags)
+
+ return env
+
+
+class LUNetworkAdd(LogicalUnit):
+ """Logical unit for creating networks.
+
+ """
+ HPATH = "network-add"
+ HTYPE = constants.HTYPE_NETWORK
+ REQ_BGL = False
+
+ def BuildHooksNodes(self):
+ """Build hooks nodes.
+
+ """
+ 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())
+
+ if self.op.conflicts_check:
+ self.share_locks[locking.LEVEL_NODE] = 1
+ self.share_locks[locking.LEVEL_NODE_ALLOC] = 1
+ self.needed_locks = {
+ locking.LEVEL_NODE: locking.ALL_SET,
+ locking.LEVEL_NODE_ALLOC: locking.ALL_SET,
+ }
+ else:
+ self.needed_locks = {}
+
+ 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)
+
+ try:
+ existing_uuid = self.cfg.LookupNetwork(self.op.network_name)
+ except errors.OpPrereqError:
+ pass
+ else:
+ raise errors.OpPrereqError("Desired network name '%s' already exists as
a"
+ " network (UUID: %s)" %
+ (self.op.network_name, existing_uuid),
+ errors.ECODE_EXISTS)
+
+ # Check tag validity
+ for tag in self.op.tags:
+ objects.TaggableObject.ValidateTag(tag)
+
+ def BuildHooksEnv(self):
+ """Build hooks env.
+
+ """
+ args = {
+ "name": self.op.network_name,
+ "subnet": self.op.network,
+ "gateway": self.op.gateway,
+ "network6": self.op.network6,
+ "gateway6": self.op.gateway6,
+ "mac_prefix": self.op.mac_prefix,
+ "tags": self.op.tags,
+ }
+ return _BuildNetworkHookEnv(**args) # pylint: disable=W0142
+
+ def Exec(self, feedback_fn):
+ """Add the ip pool to the cluster.
+
+ """
+ nobj = objects.Network(name=self.op.network_name,
+ network=self.op.network,
+ gateway=self.op.gateway,
+ network6=self.op.network6,
+ gateway6=self.op.gateway6,
+ mac_prefix=self.op.mac_prefix,
+ uuid=self.network_uuid)
+ # Initialize the associated address pool
+ try:
+ pool = network.AddressPool.InitializeNetwork(nobj)
+ except errors.AddressPoolError, err:
+ raise errors.OpExecError("Cannot create IP address pool for network"
+ " '%s': %s" % (self.op.network_name, err))
+
+ # 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.
+ 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, err:
+ self.LogWarning("Cannot reserve IP address '%s' of node '%s': %s",
+ ip, node.name, err)
+
+ 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, err:
+ self.LogWarning("Cannot reserve cluster master IP address (%s): %s",
+ master_ip, err)
+
+ if self.op.add_reserved_ips:
+ for ip in self.op.add_reserved_ips:
+ try:
+ pool.Reserve(ip, external=True)
+ except errors.AddressPoolError, err:
+ raise errors.OpExecError("Cannot reserve IP address '%s': %s" %
+ (ip, err))
+
+ if self.op.tags:
+ for tag in self.op.tags:
+ nobj.AddTag(tag)
+
+ self.cfg.AddNetwork(nobj, self.proc.GetECId(), check_uuid=False)
+ del self.remove_locks[locking.LEVEL_NETWORK]
+
+
+class LUNetworkRemove(LogicalUnit):
+ HPATH = "network-remove"
+ HTYPE = constants.HTYPE_NETWORK
+ REQ_BGL = False
+
+ def ExpandNames(self):
+ self.network_uuid = self.cfg.LookupNetwork(self.op.network_name)
+
+ 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):
+ """Check prerequisites.
+
+ This checks that the given network name exists as a network, that is
+ empty (i.e., contains no nodes), and that is not the last group of the
+ cluster.
+
+ """
+ # Verify that the network is not conncted.
+ node_groups = [group.name
+ for group in self.cfg.GetAllNodeGroupsInfo().values()
+ if self.network_uuid in group.networks]
+
+ if node_groups:
+ 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.
+
+ """
+ return {
+ "NETWORK_NAME": self.op.network_name,
+ }
+
+ def BuildHooksNodes(self):
+ """Build hooks nodes.
+
+ """
+ mn = self.cfg.GetMasterNode()
+ return ([mn], [mn])
+
+ def Exec(self, feedback_fn):
+ """Remove the network.
+
+ """
+ try:
+ self.cfg.RemoveNetwork(self.network_uuid)
+ except errors.ConfigurationError:
+ raise errors.OpExecError("Network '%s' with UUID %s disappeared" %
+ (self.op.network_name, self.network_uuid))
+
+
+class LUNetworkSetParams(LogicalUnit):
+ """Modifies the parameters of a network.
+
+ """
+ HPATH = "network-modify"
+ HTYPE = constants.HTYPE_NETWORK
+ REQ_BGL = False
+
+ def CheckArguments(self):
+ if (self.op.gateway and
+ (self.op.add_reserved_ips or self.op.remove_reserved_ips)):
+ raise errors.OpPrereqError("Cannot modify gateway and reserved ips"
+ " at once", errors.ECODE_INVAL)
+
+ def ExpandNames(self):
+ self.network_uuid = self.cfg.LookupNetwork(self.op.network_name)
+
+ self.needed_locks = {
+ locking.LEVEL_NETWORK: [self.network_uuid],
+ }
+
+ def CheckPrereq(self):
+ """Check prerequisites.
+
+ """
+ self.network = self.cfg.GetNetwork(self.network_uuid)
+ self.gateway = self.network.gateway
+ self.mac_prefix = self.network.mac_prefix
+ self.network6 = self.network.network6
+ self.gateway6 = self.network.gateway6
+ self.tags = self.network.tags
+
+ self.pool = network.AddressPool(self.network)
+
+ if self.op.gateway:
+ if self.op.gateway == constants.VALUE_NONE:
+ self.gateway = None
+ else:
+ self.gateway = self.op.gateway
+ if self.pool.IsReserved(self.gateway):
+ raise errors.OpPrereqError("Gateway IP address '%s' is already"
+ " reserved" % self.gateway,
+ errors.ECODE_STATE)
+
+ if self.op.mac_prefix:
+ if self.op.mac_prefix == constants.VALUE_NONE:
+ self.mac_prefix = None
+ else:
+ self.mac_prefix = \
+ utils.NormalizeAndValidateThreeOctetMacPrefix(self.op.mac_prefix)
+
+ if self.op.gateway6:
+ if self.op.gateway6 == constants.VALUE_NONE:
+ self.gateway6 = None
+ else:
+ self.gateway6 = self.op.gateway6
+
+ if self.op.network6:
+ if self.op.network6 == constants.VALUE_NONE:
+ self.network6 = None
+ else:
+ self.network6 = self.op.network6
+
+ def BuildHooksEnv(self):
+ """Build hooks env.
+
+ """
+ args = {
+ "name": self.op.network_name,
+ "subnet": self.network.network,
+ "gateway": self.gateway,
+ "network6": self.network6,
+ "gateway6": self.gateway6,
+ "mac_prefix": self.mac_prefix,
+ "tags": self.tags,
+ }
+ return _BuildNetworkHookEnv(**args) # pylint: disable=W0142
+
+ def BuildHooksNodes(self):
+ """Build hooks nodes.
+
+ """
+ mn = self.cfg.GetMasterNode()
+ return ([mn], [mn])
+
+ def Exec(self, feedback_fn):
+ """Modifies the network.
+
+ """
+ #TODO: reserve/release via temporary reservation manager
+ # 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)
+ else:
+ if self.gateway:
+ self.pool.Reserve(self.gateway, external=True)
+ if self.network.gateway:
+ self.pool.Release(self.network.gateway, external=True)
+ self.network.gateway = self.gateway
+
+ if self.op.add_reserved_ips:
+ for ip in self.op.add_reserved_ips:
+ try:
+ if self.pool.IsReserved(ip):
+ self.LogWarning("IP address %s is already reserved", ip)
+ else:
+ self.pool.Reserve(ip, external=True)
+ 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:
+ if ip == self.network.gateway:
+ self.LogWarning("Cannot unreserve Gateway's IP")
+ continue
+ try:
+ if not self.pool.IsReserved(ip):
+ self.LogWarning("IP address %s is already unreserved", ip)
+ else:
+ self.pool.Release(ip, external=True)
+ 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
+
+ if self.op.network6:
+ self.network.network6 = self.network6
+
+ if self.op.gateway6:
+ self.network.gateway6 = self.gateway6
+
+ self.pool.Validate()
+
+ self.cfg.Update(self.network, feedback_fn)
+
+
+class _NetworkQuery(_QueryBase):
+ FIELDS = query.NETWORK_FIELDS
+
+ def ExpandNames(self, lu):
+ lu.needed_locks = {}
+ lu.share_locks = _ShareAll()
+
+ self.do_locking = self.use_locking
+
+ all_networks = lu.cfg.GetAllNetworksInfo()
+ name_to_uuid = dict((n.name, n.uuid) for n in all_networks.values())
+
+ if self.names:
+ missing = []
+ self.wanted = []
+
+ for name in self.names:
+ if name in name_to_uuid:
+ self.wanted.append(name_to_uuid[name])
+ else:
+ missing.append(name)
+
+ if missing:
+ raise errors.OpPrereqError("Some networks do not exist: %s" % missing,
+ errors.ECODE_NOENT)
+ else:
+ self.wanted = locking.ALL_SET
+
+ if self.do_locking:
+ lu.needed_locks[locking.LEVEL_NETWORK] = self.wanted
+ if query.NETQ_INST in self.requested_data:
+ lu.needed_locks[locking.LEVEL_INSTANCE] = locking.ALL_SET
+ if query.NETQ_GROUP in self.requested_data:
+ lu.needed_locks[locking.LEVEL_NODEGROUP] = locking.ALL_SET
+
+ def DeclareLocks(self, lu, level):
+ pass
+
+ def _GetQueryData(self, lu):
+ """Computes the list of networks and their attributes.
+
+ """
+ all_networks = lu.cfg.GetAllNetworksInfo()
+
+ network_uuids = self._GetNames(lu, all_networks.keys(),
+ locking.LEVEL_NETWORK)
+
+ do_instances = query.NETQ_INST in self.requested_data
+ do_groups = query.NETQ_GROUP in self.requested_data
+
+ network_to_instances = None
+ network_to_groups = None
+
+ # For NETQ_GROUP, we need to map network->[groups]
+ if do_groups:
+ all_groups = lu.cfg.GetAllNodeGroupsInfo()
+ network_to_groups = dict((uuid, []) for uuid in network_uuids)
+ for _, group in all_groups.iteritems():
+ for net_uuid in network_uuids:
+ netparams = group.networks.get(net_uuid, None)
+ if netparams:
+ info = (group.name, netparams[constants.NIC_MODE],
+ netparams[constants.NIC_LINK])
+
+ network_to_groups[net_uuid].append(info)
+
+ if do_instances:
+ all_instances = lu.cfg.GetAllInstancesInfo()
+ network_to_instances = dict((uuid, []) for uuid in network_uuids)
+ for instance in all_instances.values():
+ for nic in instance.nics:
+ if nic.network in network_uuids:
+ network_to_instances[nic.network].append(instance.name)
+ break
+
+ if query.NETQ_STATS in self.requested_data:
+ stats = \
+ dict((uuid,
+ self._GetStats(network.AddressPool(all_networks[uuid])))
+ for uuid in network_uuids)
+ else:
+ stats = None
+
+ return query.NetworkQueryData([all_networks[uuid]
+ for uuid in network_uuids],
+ network_to_groups,
+ network_to_instances,
+ stats)
+
+ @staticmethod
+ def _GetStats(pool):
+ """Returns statistics for a network address pool.
+
+ """
+ return {
+ "free_count": pool.GetFreeCount(),
+ "reserved_count": pool.GetReservedCount(),
+ "map": pool.GetMap(),
+ "external_reservations":
+ utils.CommaJoin(pool.GetExternalReservations()),
+ }
+
+
+class LUNetworkQuery(NoHooksLU):
+ """Logical unit for querying networks.
+
+ """
+ REQ_BGL = False
+
+ def CheckArguments(self):
+ self.nq = _NetworkQuery(qlang.MakeSimpleFilter("name", self.op.names),
+ self.op.output_fields, self.op.use_locking)
+
+ def ExpandNames(self):
+ self.nq.ExpandNames(self)
+
+ def Exec(self, feedback_fn):
+ return self.nq.OldStyleQuery(self)
+
+
+def _FmtNetworkConflict(details):
+ """Utility for L{_NetworkConflictCheck}.
+
+ """
+ return utils.CommaJoin("nic%s/%s" % (idx, ipaddr)
+ for (idx, ipaddr) in details)
+
+
+def _NetworkConflictCheck(lu, check_fn, action, instances):
+ """Checks for network interface conflicts with a network.
+
+ @type lu: L{LogicalUnit}
+ @type check_fn: callable receiving one parameter (L{objects.NIC}) and
+ returning boolean
+ @param check_fn: Function checking for conflict
+ @type action: string
+ @param action: Part of error message (see code)
+ @raise errors.OpPrereqError: If conflicting IP addresses are found.
+
+ """
+ conflicts = []
+
+ for (_, instance) in lu.cfg.GetMultiInstanceInfo(instances):
+ instconflicts = [(idx, nic.ip)
+ for (idx, nic) in enumerate(instance.nics)
+ if check_fn(nic)]
+
+ if instconflicts:
+ conflicts.append((instance.name, instconflicts))
+
+ if conflicts:
+ lu.LogWarning("IP addresses from network '%s', which is about to %s"
+ " node group '%s', are in use: %s" %
+ (lu.network_name, action, lu.group.name,
+ utils.CommaJoin(("%s: %s" %
+ (name, _FmtNetworkConflict(details)))
+ for (name, details) in conflicts)))
+
+ raise errors.OpPrereqError("Conflicting IP addresses found; "
+ " remove/modify the corresponding network"
+ " interfaces", errors.ECODE_STATE)
+
+
+class LUNetworkConnect(LogicalUnit):
+ """Connect a network to a nodegroup
+
+ """
+ HPATH = "network-connect"
+ HTYPE = constants.HTYPE_NETWORK
+ REQ_BGL = False
+
+ def ExpandNames(self):
+ self.network_name = self.op.network_name
+ self.group_name = self.op.group_name
+ self.network_mode = self.op.network_mode
+ self.network_link = self.op.network_link
+
+ self.network_uuid = self.cfg.LookupNetwork(self.network_name)
+ self.group_uuid = self.cfg.LookupNodeGroup(self.group_name)
+
+ self.needed_locks = {
+ locking.LEVEL_INSTANCE: [],
+ locking.LEVEL_NODEGROUP: [self.group_uuid],
+ }
+ 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
+ if self.op.conflicts_check:
+ self.needed_locks[locking.LEVEL_INSTANCE] = \
+ self.cfg.GetNodeGroupInstances(self.group_uuid)
+
+ def BuildHooksEnv(self):
+ ret = {
+ "GROUP_NAME": self.group_name,
+ "GROUP_NETWORK_MODE": self.network_mode,
+ "GROUP_NETWORK_LINK": self.network_link,
+ }
+ return ret
+
+ def BuildHooksNodes(self):
+ nodes = self.cfg.GetNodeGroup(self.group_uuid).members
+ return (nodes, nodes)
+
+ def CheckPrereq(self):
+ owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP))
+
+ assert self.group_uuid in owned_groups
+
+ # Check if locked instances are still correct
+ owned_instances = frozenset(self.owned_locks(locking.LEVEL_INSTANCE))
+ if self.op.conflicts_check:
+ _CheckNodeGroupInstances(self.cfg, self.group_uuid, owned_instances)
+
+ 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
+ if self.network_uuid in self.group.networks:
+ self.LogWarning("Network '%s' is already mapped to group '%s'" %
+ (self.network_name, self.group.name))
+ self.connected = True
+
+ # check only if not already connected
+ elif self.op.conflicts_check:
+ pool = network.AddressPool(self.cfg.GetNetwork(self.network_uuid))
+
+ _NetworkConflictCheck(self, lambda nic: pool.Contains(nic.ip),
+ "connect to", owned_instances)
+
+ def Exec(self, feedback_fn):
+ # Connect the network and update the group only if not already connected
+ if not self.connected:
+ self.group.networks[self.network_uuid] = self.netparams
+ self.cfg.Update(self.group, feedback_fn)
+
+
+class LUNetworkDisconnect(LogicalUnit):
+ """Disconnect a network to a nodegroup
+
+ """
+ HPATH = "network-disconnect"
+ HTYPE = constants.HTYPE_NETWORK
+ REQ_BGL = False
+
+ def ExpandNames(self):
+ self.network_name = self.op.network_name
+ self.group_name = self.op.group_name
+
+ self.network_uuid = self.cfg.LookupNetwork(self.network_name)
+ self.group_uuid = self.cfg.LookupNodeGroup(self.group_name)
+
+ self.needed_locks = {
+ locking.LEVEL_INSTANCE: [],
+ locking.LEVEL_NODEGROUP: [self.group_uuid],
+ }
+ self.share_locks[locking.LEVEL_INSTANCE] = 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)
+
+ def BuildHooksEnv(self):
+ ret = {
+ "GROUP_NAME": self.group_name,
+ }
+ return ret
+
+ def BuildHooksNodes(self):
+ nodes = self.cfg.GetNodeGroup(self.group_uuid).members
+ return (nodes, nodes)
+
+ def CheckPrereq(self):
+ owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP))
+
+ assert self.group_uuid in owned_groups
+
+ # Check if locked instances are still correct
+ owned_instances = frozenset(self.owned_locks(locking.LEVEL_INSTANCE))
+ _CheckNodeGroupInstances(self.cfg, self.group_uuid, owned_instances)
+
+ 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.connected = False
+
+ # We need this check only if network is not already connected
+ else:
+ _NetworkConflictCheck(self, lambda nic: nic.network == self.network_uuid,
+ "disconnect from", owned_instances)
+
+ def Exec(self, feedback_fn):
+ # Disconnect the network and update the group only if network is connected
+ if self.connected:
+ del self.group.networks[self.network_uuid]
+ self.cfg.Update(self.group, feedback_fn)
--
1.8.2.1