Commit eaa4c57c authored by Dimitris Aragiorgis's avatar Dimitris Aragiorgis Committed by Iustin Pop

IP pool related objects, opcodes and constants

Config objects:
 * Introduce L{Network} with
  - IPv4 network field (mandatory)
  - IPv4 gateway, IPv6 (network/gateway), mac prefix, type (optional)
 * Modify existing config objects to support networks:
  - Add new slot 'network' to L{NIC} config object
  - Add new slot 'networks' to L{NodeGroup} config object

Opcodes:
 * Introduce new opcodes for networks
  - add/remove/modify/query/connect/disconnect.
 * In InstanceCreate/InstanceSetParams add conflicts_check option

Constants:
 * INIC_PARAM 'INIC_NETWORK'
 * NIC_IP_POOL for automaticaly obtain an IP from a pool
 * NETWORK_TYPE_PUBLIC/PRIVATE for network types

Checking of network_type handled by the opcode parameter validation.
Introduce _CheckCIDR*Notation() functions for network parameters
validation.
Signed-off-by: default avatarApollon Oikonomopoulos <apollon@noc.grnet.gr>
Signed-off-by: default avatarDimitris Aragiorgis <dimara@grnet.gr>
Reviewed-by: default avatarIustin Pop <iustin@google.com>
parent edb5a1c8
......@@ -603,6 +603,7 @@ def InitConfig(version, cluster_config, master_node_config,
nodegroups=nodegroups,
nodes=nodes,
instances={},
networks={},
serial_no=1,
ctime=now, mtime=now)
utils.WriteFile(cfg_file,
......
......@@ -15301,6 +15301,61 @@ class LUTestAllocator(NoHooksLU):
result = ial.out_text
return result
# Network LUs
class LUNetworkAdd(LogicalUnit):
def BuildHooksNodes(self):
pass
def BuildHooksEnv(self):
pass
class LUNetworkRemove(LogicalUnit):
def BuildHooksNodes(self):
pass
def BuildHooksEnv(self):
pass
class LUNetworkSetParams(LogicalUnit):
def BuildHooksNodes(self):
pass
def BuildHooksEnv(self):
pass
class _NetworkQuery(_QueryBase):
def ExpandNames(self, lu):
pass
def DeclareLocks(self, lu, level):
pass
def _GetQueryData(self, lu):
pass
class LUNetworkQuery(NoHooksLU):
pass
class LUNetworkConnect(LogicalUnit):
def BuildHooksNodes(self):
pass
def BuildHooksEnv(self):
pass
class LUNetworkDisconnect(LogicalUnit):
def BuildHooksNodes(self):
pass
def BuildHooksEnv(self):
pass
#: Query type implementations
_QUERY_IMPL = {
......@@ -15308,6 +15363,7 @@ _QUERY_IMPL = {
constants.QR_INSTANCE: _InstanceQuery,
constants.QR_NODE: _NodeQuery,
constants.QR_GROUP: _GroupQuery,
constants.QR_NETWORK: _NetworkQuery,
constants.QR_OS: _OsQuery,
constants.QR_EXPORT: _ExportQuery,
}
......
......@@ -302,6 +302,7 @@ HTYPE_CLUSTER = "CLUSTER"
HTYPE_NODE = "NODE"
HTYPE_GROUP = "GROUP"
HTYPE_INSTANCE = "INSTANCE"
HTYPE_NETWORK = "NETWORK"
HKR_SKIP = 0
HKR_FAIL = 1
......@@ -1065,9 +1066,17 @@ NIC_LINK = "link"
NIC_MODE_BRIDGED = "bridged"
NIC_MODE_ROUTED = "routed"
NIC_IP_POOL = "pool"
NIC_VALID_MODES = frozenset([NIC_MODE_BRIDGED, NIC_MODE_ROUTED])
# An extra description of the network.
# Can be used by hooks/kvm-vif-bridge to apply different rules
NETWORK_TYPE_PRIVATE = "private"
NETWORK_TYPE_PUBLIC = "public"
NETWORK_VALID_TYPES = frozenset([NETWORK_TYPE_PRIVATE, NETWORK_TYPE_PUBLIC])
NICS_PARAMETER_TYPES = {
NIC_MODE: VTYPE_STRING,
NIC_LINK: VTYPE_STRING,
......@@ -1095,11 +1104,13 @@ INIC_MAC = "mac"
INIC_IP = "ip"
INIC_MODE = "mode"
INIC_LINK = "link"
INIC_NETWORK = "network"
INIC_PARAMS_TYPES = {
INIC_IP: VTYPE_MAYBE_STRING,
INIC_LINK: VTYPE_STRING,
INIC_MAC: VTYPE_STRING,
INIC_MODE: VTYPE_STRING,
INIC_NETWORK: VTYPE_MAYBE_STRING,
}
INIC_PARAMS = frozenset(INIC_PARAMS_TYPES.keys())
......@@ -1603,6 +1614,7 @@ QR_GROUP = "group"
QR_OS = "os"
QR_JOB = "job"
QR_EXPORT = "export"
QR_NETWORK = "network"
#: List of resources which can be queried using L{opcodes.OpQuery}
QR_VIA_OP = frozenset([
......@@ -1612,6 +1624,7 @@ QR_VIA_OP = frozenset([
QR_GROUP,
QR_OS,
QR_EXPORT,
QR_NETWORK,
])
#: List of resources which can be queried using Local UniX Interface
......@@ -1703,6 +1716,7 @@ SS_HYPERVISOR_LIST = "hypervisor_list"
SS_MAINTAIN_NODE_HEALTH = "maintain_node_health"
SS_UID_POOL = "uid_pool"
SS_NODEGROUPS = "nodegroups"
SS_NETWORKS = "networks"
SS_FILE_PERMS = 0444
......
......@@ -51,7 +51,7 @@ from socket import AF_INET
__all__ = ["ConfigObject", "ConfigData", "NIC", "Disk", "Instance",
"OS", "Node", "NodeGroup", "Cluster", "FillDict"]
"OS", "Node", "NodeGroup", "Cluster", "FillDict", "Network"]
_TIMESTAMPS = ["ctime", "mtime"]
_UUID = ["uuid"]
......@@ -432,6 +432,7 @@ class ConfigData(ConfigObject):
"nodes",
"nodegroups",
"instances",
"networks",
"serial_no",
] + _TIMESTAMPS
......@@ -444,7 +445,7 @@ class ConfigData(ConfigObject):
"""
mydict = super(ConfigData, self).ToDict()
mydict["cluster"] = mydict["cluster"].ToDict()
for key in "nodes", "instances", "nodegroups":
for key in "nodes", "instances", "nodegroups", "networks":
mydict[key] = self._ContainerToDicts(mydict[key])
return mydict
......@@ -459,6 +460,7 @@ class ConfigData(ConfigObject):
obj.nodes = cls._ContainerFromDicts(obj.nodes, dict, Node)
obj.instances = cls._ContainerFromDicts(obj.instances, dict, Instance)
obj.nodegroups = cls._ContainerFromDicts(obj.nodegroups, dict, NodeGroup)
obj.networks = cls._ContainerFromDicts(obj.networks, dict, Network)
return obj
def HasAnyDiskOfType(self, dev_type):
......@@ -495,11 +497,13 @@ class ConfigData(ConfigObject):
# gives a good approximation.
if self.HasAnyDiskOfType(constants.LD_DRBD8):
self.cluster.drbd_usermode_helper = constants.DEFAULT_DRBD_HELPER
if self.networks is None:
self.networks = {}
class NIC(ConfigObject):
"""Config object representing a network card."""
__slots__ = ["mac", "ip", "nicparams"]
__slots__ = ["mac", "ip", "network", "nicparams"]
@classmethod
def CheckParameterSyntax(cls, nicparams):
......@@ -1359,6 +1363,7 @@ class NodeGroup(TaggableObject):
"hv_state_static",
"disk_state_static",
"alloc_policy",
"networks",
] + _TIMESTAMPS + _UUID
def ToDict(self):
......@@ -1406,6 +1411,9 @@ class NodeGroup(TaggableObject):
if self.ipolicy is None:
self.ipolicy = MakeEmptyIPolicy()
if self.networks is None:
self.networks = {}
def FillND(self, node):
"""Return filled out ndparams for L{objects.Node}
......@@ -1989,6 +1997,26 @@ class InstanceConsole(ConfigObject):
return True
class Network(ConfigObject):
"""Object representing a network definition for ganeti.
"""
__slots__ = [
"name",
"serial_no",
"network_type",
"mac_prefix",
"family",
"network",
"network6",
"gateway",
"gateway6",
"size",
"reservations",
"ext_reservations",
] + _TIMESTAMPS + _UUID
class SerializableConfigParser(ConfigParser.SafeConfigParser):
"""Simple wrapper over ConfigParse that allows serialization.
......
......@@ -35,6 +35,7 @@ opcodes.
import logging
import re
import ipaddr
from ganeti import constants
from ganeti import errors
......@@ -167,6 +168,9 @@ _PIgnoreIpolicy = ("ignore_ipolicy", False, ht.TBool,
_PAllowRuntimeChgs = ("allow_runtime_changes", True, ht.TBool,
"Allow runtime changes (eg. memory ballooning)")
#: a required network name
_PNetworkName = ("network_name", ht.NoDefault, ht.TNonEmptyString,
"Set network name")
#: OP_ID conversion regular expression
_OPID_RE = re.compile("([a-z])([A-Z])")
......@@ -343,6 +347,51 @@ def _CheckStorageType(storage_type):
_PStorageType = ("storage_type", ht.NoDefault, _CheckStorageType,
"Storage type")
_CheckNetworkType = ht.TElemOf(constants.NETWORK_VALID_TYPES)
#: Network type parameter
_PNetworkType = ("network_type", None, ht.TOr(ht.TNone, _CheckNetworkType),
"Network type")
def _CheckCIDRNetNotation(value):
"""Ensure a given cidr notation type is valid.
"""
try:
ipaddr.IPv4Network(value)
except ipaddr.AddressValueError:
return False
return True
def _CheckCIDRAddrNotation(value):
"""Ensure a given cidr notation type is valid.
"""
try:
ipaddr.IPv4Address(value)
except ipaddr.AddressValueError:
return False
return True
def _CheckCIDR6AddrNotation(value):
"""Ensure a given cidr notation type is valid.
"""
try:
ipaddr.IPv6Address(value)
except ipaddr.AddressValueError:
return False
return True
def _CheckCIDR6NetNotation(value):
"""Ensure a given cidr notation type is valid.
"""
try:
ipaddr.IPv6Network(value)
except ipaddr.AddressValueError:
return False
return True
class _AutoOpParamSlots(objectutils.AutoSlots):
"""Meta class for opcode definitions.
......@@ -1201,6 +1250,7 @@ class OpInstanceCreate(OpCode):
("identify_defaults", False, ht.TBool,
"Reset instance parameters to default if equal"),
("ip_check", True, ht.TBool, _PIpCheckDoc),
("conflicts_check", True, ht.TBool, "Check for conflicting IPs"),
("mode", ht.NoDefault, ht.TElemOf(constants.INSTANCE_CREATE_MODES),
"Instance creation mode"),
("nics", ht.NoDefault, ht.TListOf(_TestNicDef),
......@@ -1594,6 +1644,7 @@ class OpInstanceSetParams(OpCode):
("wait_for_sync", True, ht.TBool,
"Whether to wait for the disk to synchronize, when changing template"),
("offline", None, ht.TMaybeBool, "Whether to mark instance as offline"),
("conflicts_check", True, ht.TBool, "Check for conflicting IPs"),
]
OP_RESULT = _TSetParamsResult
......@@ -1952,6 +2003,88 @@ class OpTestDummy(OpCode):
WITH_LU = False
# Network opcodes
# Add a new network in the cluster
class OpNetworkAdd(OpCode):
"""Add an IP network to the cluster."""
OP_DSC_FIELD = "network_name"
OP_PARAMS = [
_PNetworkName,
_PNetworkType,
("network", None, ht.TAnd(ht.TString ,_CheckCIDRNetNotation), None),
("gateway", None, ht.TOr(ht.TNone, _CheckCIDRAddrNotation), None),
("network6", None, ht.TOr(ht.TNone, _CheckCIDR6NetNotation), None),
("gateway6", None, ht.TOr(ht.TNone, _CheckCIDR6AddrNotation), None),
("mac_prefix", None, ht.TMaybeString, None),
("add_reserved_ips", None,
ht.TOr(ht.TNone, ht.TListOf(_CheckCIDRAddrNotation)), None),
]
class OpNetworkRemove(OpCode):
"""Remove an existing network from the cluster.
Must not be connected to any nodegroup.
"""
OP_DSC_FIELD = "network_name"
OP_PARAMS = [
_PNetworkName,
_PForce,
]
class OpNetworkSetParams(OpCode):
"""Modify Network's parameters except for IPv4 subnet"""
OP_DSC_FIELD = "network_name"
OP_PARAMS = [
_PNetworkName,
_PNetworkType,
("gateway", None, ht.TOr(ht.TNone, _CheckCIDRAddrNotation), None),
("network6", None, ht.TOr(ht.TNone, _CheckCIDR6NetNotation), None),
("gateway6", None, ht.TOr(ht.TNone, _CheckCIDR6AddrNotation), None),
("mac_prefix", None, ht.TMaybeString, None),
("add_reserved_ips", None,
ht.TOr(ht.TNone, ht.TListOf(_CheckCIDRAddrNotation)), None),
("remove_reserved_ips", None,
ht.TOr(ht.TNone, ht.TListOf(_CheckCIDRAddrNotation)), None),
]
class OpNetworkConnect(OpCode):
"""Connect a Network to a specific Nodegroup with the defined netparams
(mode, link). Nics in this Network will inherit those params.
Produce errors if a NIC (that its not already assigned to a network)
has an IP that is contained in the Network this will produce error unless
--no-conflicts-check is passed.
"""
OP_DSC_FIELD = "network_name"
OP_PARAMS = [
_PGroupName,
_PNetworkName,
("network_mode", None, ht.TString, None),
("network_link", None, ht.TString, None),
("conflicts_check", True, ht.TBool, "Check for conflicting IPs"),
]
class OpNetworkDisconnect(OpCode):
"""Disconnect a Network from a Nodegroup. Produce errors if NICs are
present in the Network unless --no-conficts-check option is passed.
"""
OP_DSC_FIELD = "network_name"
OP_PARAMS = [
_PGroupName,
_PNetworkName,
("conflicts_check", True, ht.TBool, "Check for conflicting IPs"),
]
class OpNetworkQuery(OpCode):
"""Compute the list of networks."""
OP_PARAMS = [
_POutputFields,
("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString),
"Empty list to query all groups, group names otherwise"),
]
def _GetOpList():
"""Returns list of all defined opcodes.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment