import shutil
import itertools
import operator
+import ipaddr
from ganeti import ssh
from ganeti import utils
from ganeti import runtime
from ganeti import pathutils
from ganeti import vcluster
+from ganeti import network
from ganeti.masterd import iallocator
import ganeti.masterd.instance # pylint: disable=W0611
# Network LUs
class LUNetworkAdd(LogicalUnit):
+ """Logical unit for creating networks.
+
+ """
+ HPATH = "network-add"
+ HTYPE = constants.HTYPE_NETWORK
+ REQ_BGL = False
+
def BuildHooksNodes(self):
- pass
+ """Build hooks nodes.
+
+ """
+ mn = self.cfg.GetMasterNode()
+ return ([mn], [mn])
+
+ 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.
+
+ This checks that the given group name is not an existing node group
+ already.
+
+ """
+ if self.op.network is None:
+ raise errors.OpPrereqError("Network must be given",
+ errors.ECODE_INVAL)
+
+ uuid = self.cfg.LookupNetwork(self.op.network_name)
+
+ if uuid:
+ raise errors.OpPrereqError("Network '%s' already defined" %
+ self.op.network, errors.ECODE_EXISTS)
+
def BuildHooksEnv(self):
- pass
+ """Build hooks env.
+
+ """
+ env = {
+ "NETWORK_NAME": self.op.network_name,
+ "NETWORK_SUBNET": self.op.network,
+ "NETWORK_GATEWAY": self.op.gateway,
+ "NETWORK_SUBNET6": self.op.network6,
+ "NETWORK_GATEWAY6": self.op.gateway6,
+ "NETWORK_MAC_PREFIX": self.op.mac_prefix,
+ "NETWORK_TYPE": self.op.network_type,
+ }
+ return env
+
+ 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,
+ network_type=self.op.network_type,
+ uuid=self.network_uuid,
+ family=4)
+ # Initialize the associated address pool
+ try:
+ pool = network.AddressPool.InitializeNetwork(nobj)
+ except errors.AddressPoolError, e:
+ raise errors.OpExecError("Cannot create IP pool for this network. %s" % e)
+
+ # 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
+
+ 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
+
+ if self.op.add_reserved_ips:
+ for ip in self.op.add_reserved_ips:
+ try:
+ pool.Reserve(ip, external=True)
+ except errors.AddressPoolError, e:
+ raise errors.OpExecError("Cannot reserve IP %s. %s " % (ip, e))
+
+ self.cfg.AddNetwork(nobj, self.proc.GetECId(), check_uuid=False)
+ del self.remove_locks[locking.LEVEL_NETWORK]
class LUNetworkRemove(LogicalUnit):
- def BuildHooksNodes(self):
- pass
+ HPATH = "network-remove"
+ HTYPE = constants.HTYPE_NETWORK
+ REQ_BGL = False
+
+ 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.
+
+ 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.
+
+ """
+ if not self.network_uuid:
+ raise errors.OpPrereqError("Network %s not found" % self.op.network_name,
+ errors.ECODE_INVAL)
+
+ # Verify that the network is not conncted.
+ node_groups = [group.name
+ for group in self.cfg.GetAllNodeGroupsInfo().values()
+ for network in group.networks.keys()
+ if network == self.network_uuid]
+
+ 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)
def BuildHooksEnv(self):
- pass
+ """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):
from ganeti import netutils
from ganeti import runtime
from ganeti import pathutils
+from ganeti import network
_config_lock = locking.SharedLock("ConfigWriter")
nodegroups = ["%s %s" % (nodegroup.uuid, nodegroup.name) for nodegroup in
self._config_data.nodegroups.values()]
nodegroups_data = fn(utils.NiceSort(nodegroups))
+ networks = ["%s %s" % (net.uuid, net.name) for net in
+ self._config_data.networks.values()]
+ networks_data = fn(utils.NiceSort(networks))
ssconf_values = {
constants.SS_CLUSTER_NAME: cluster.cluster_name,
constants.SS_MAINTAIN_NODE_HEALTH: str(cluster.maintain_node_health),
constants.SS_UID_POOL: uid_pool,
constants.SS_NODEGROUPS: nodegroups_data,
+ constants.SS_NETWORKS: networks_data,
}
bad_values = [(k, v) for k, v in ssconf_values.items()
if not isinstance(v, (str, basestring))]
"""
for rm in self._all_rms:
rm.DropECReservations(ec_id)
+
+ @locking.ssynchronized(_config_lock, shared=1)
+ def GetAllNetworksInfo(self):
+ """Get the configuration of all networks
+
+ """
+ return dict(self._config_data.networks)
+
+ def _UnlockedGetNetworkList(self):
+ """Get the list of networks.
+
+ This function is for internal use, when the config lock is already held.
+
+ """
+ return self._config_data.networks.keys()
+
+ @locking.ssynchronized(_config_lock, shared=1)
+ def GetNetworkList(self):
+ """Get the list of networks.
+
+ @return: array of networks, ex. ["main", "vlan100", "200]
+
+ """
+ return self._UnlockedGetNetworkList()
+
+ @locking.ssynchronized(_config_lock, shared=1)
+ def GetNetworkNames(self):
+ """Get a list of network names
+
+ """
+ names = [network.name
+ for network in self._config_data.networks.values()]
+ return names
+
+ def _UnlockedGetNetwork(self, uuid):
+ """Returns information about a network.
+
+ This function is for internal use, when the config lock is already held.
+
+ """
+ if uuid not in self._config_data.networks:
+ return None
+
+ return self._config_data.networks[uuid]
+
+ @locking.ssynchronized(_config_lock, shared=1)
+ def GetNetwork(self, uuid):
+ """Returns information about a network.
+
+ It takes the information from the configuration file.
+
+ @param uuid: UUID of the network
+
+ @rtype: L{objects.Network}
+ @return: the network object
+
+ """
+ return self._UnlockedGetNetwork(uuid)
+
+ @locking.ssynchronized(_config_lock)
+ def AddNetwork(self, net, ec_id, check_uuid=True):
+ """Add a network to the configuration.
+
+ @type net: L{objects.Network}
+ @param net: the Network object to add
+ @type ec_id: string
+ @param ec_id: unique id for the job to use when creating a missing UUID
+
+ """
+ self._UnlockedAddNetwork(net, ec_id, check_uuid)
+ self._WriteConfig()
+
+ def _UnlockedAddNetwork(self, net, ec_id, check_uuid):
+ """Add a network to the configuration.
+
+ """
+ logging.info("Adding network %s to configuration", net.name)
+
+ if check_uuid:
+ self._EnsureUUID(net, ec_id)
+
+ existing_uuid = self._UnlockedLookupNetwork(net.name)
+ if existing_uuid:
+ raise errors.OpPrereqError("Desired network name '%s' already"
+ " exists as a network (UUID: %s)" %
+ (net.name, existing_uuid),
+ errors.ECODE_EXISTS)
+ net.serial_no = 1
+ self._config_data.networks[net.uuid] = net
+ self._config_data.cluster.serial_no += 1
+
+ def _UnlockedLookupNetwork(self, target):
+ """Lookup a network's UUID.
+
+ @type target: string
+ @param target: network name or UUID
+ @rtype: string
+ @return: network UUID
+ @raises errors.OpPrereqError: when the target network cannot be found
+
+ """
+ if target in self._config_data.networks:
+ return target
+ for net in self._config_data.networks.values():
+ if net.name == target:
+ return net.uuid
+ return None
+
+ @locking.ssynchronized(_config_lock, shared=1)
+ def LookupNetwork(self, target):
+ """Lookup a network's UUID.
+
+ This function is just a wrapper over L{_UnlockedLookupNetwork}.
+
+ @type target: string
+ @param target: network name or UUID
+ @rtype: string
+ @return: network UUID
+
+ """
+ return self._UnlockedLookupNetwork(target)
+
+ @locking.ssynchronized(_config_lock)
+ def RemoveNetwork(self, network_uuid):
+ """Remove a network from the configuration.
+
+ @type network_uuid: string
+ @param network_uuid: the UUID of the network to remove
+
+ """
+ logging.info("Removing network %s from configuration", network_uuid)
+
+ if network_uuid not in self._config_data.networks:
+ raise errors.ConfigurationError("Unknown network '%s'" % network_uuid)
+
+ del self._config_data.networks[network_uuid]
+ self._config_data.cluster.serial_no += 1
+ self._WriteConfig()
#: Level for node resources, used for operations with possibly high impact on
#: the node's disks.
LEVEL_NODE_RES = 4
+LEVEL_NETWORK = 5
LEVELS = [
LEVEL_CLUSTER,
LEVEL_NODEGROUP,
LEVEL_NODE,
LEVEL_NODE_RES,
+ LEVEL_NETWORK,
]
# Lock levels which are modifiable
LEVEL_NODE,
LEVEL_NODEGROUP,
LEVEL_INSTANCE,
+ LEVEL_NETWORK,
])
#: Lock level names (make sure to use singular form)
LEVEL_NODEGROUP: "nodegroup",
LEVEL_NODE: "node",
LEVEL_NODE_RES: "node-res",
+ LEVEL_NETWORK: "network",
}
# Constant for the big ganeti lock
"""
_instance = None
- def __init__(self, nodes, nodegroups, instances):
+ def __init__(self, nodes, nodegroups, instances, networks):
"""Constructs a new GanetiLockManager object.
There should be only a GanetiLockManager object at any time, so this
LEVEL_NODE: LockSet(nodes, "node", monitor=self._monitor),
LEVEL_NODE_RES: LockSet(nodes, "node-res", monitor=self._monitor),
LEVEL_NODEGROUP: LockSet(nodegroups, "nodegroup", monitor=self._monitor),
- LEVEL_INSTANCE: LockSet(instances, "instance",
- monitor=self._monitor),
+ LEVEL_INSTANCE: LockSet(instances, "instance", monitor=self._monitor),
+ LEVEL_NETWORK: LockSet(networks, "network", monitor=self._monitor),
}
assert compat.all(ls.name == LEVEL_NAMES[level]
self.glm = locking.GanetiLockManager(
self.cfg.GetNodeList(),
self.cfg.GetNodeGroupList(),
- self.cfg.GetInstanceList())
+ self.cfg.GetInstanceList(),
+ self.cfg.GetNetworkList())
self.cfg.SetContext(self)