Skip to content
Snippets Groups Projects
Commit 80a419b0 authored by JORGE SASIAIN's avatar JORGE SASIAIN
Browse files

NAT-152: add support for extattrs

parent b14c9d0a
No related branches found
No related tags found
1 merge request!9Ipam service
......@@ -38,6 +38,8 @@ class HostAddresses(BaseSettings):
class IPAMErrors(Enum):
# HTTP error code, match in error message
CONTAINER_FULL = 400, "Can not find requested number of networks"
EXTATTR_UNKNOWN = 400, "Unknown extensible attribute"
EXTATTR_BADVALUE = 400, "Bad value for extensible attribute"
# TODO: remove this!
......@@ -144,7 +146,8 @@ def _get_network_capacity(network=None):
def _allocate_network(
infoblox_params: settings.InfoBloxParams,
network_params: Union[settings.V4NetworkParams, settings.V6NetworkParams],
ip_version=4
ip_version=4,
extattrs={}
) -> Union[V4ServiceNetwork, V6ServiceNetwork]:
assert ip_version in [4, 6]
endpoint = 'network' if ip_version == 4 else 'ipv6network'
......@@ -152,6 +155,7 @@ def _allocate_network(
'ipv6networkcontainer'
# only return in the response the allocated network, not all available
# TODO: any validation needed for extrattrs wherever it's used?
req_payload = {
"network": {
"_object_function": "next_available_network",
......@@ -163,7 +167,8 @@ def _allocate_network(
"network": str(network_params.containers[0])
},
"_result_field": "networks",
}
},
"extattrs": extattrs
}
container_index = 0
......@@ -198,7 +203,7 @@ def _allocate_network(
return V6ServiceNetwork(v6=allocated_network)
def allocate_service_ipv4_network(service_type) -> V4ServiceNetwork:
def allocate_service_ipv4_network(service_type, extattrs) -> V4ServiceNetwork:
"""
Allocate IPv4 network within the container of the specified service type.
"""
......@@ -209,10 +214,11 @@ def allocate_service_ipv4_network(service_type) -> V4ServiceNetwork:
and service_type != 'INFOBLOX', "Invalid service type."
return _allocate_network(ipam_params.INFOBLOX,
getattr(ipam_params, service_type).V4,
4)
4,
extattrs)
def allocate_service_ipv6_network(service_type) -> V6ServiceNetwork:
def allocate_service_ipv6_network(service_type, extattrs) -> V6ServiceNetwork:
"""
Allocate IPv6 network within the container of the specified service type.
"""
......@@ -223,7 +229,8 @@ def allocate_service_ipv6_network(service_type) -> V6ServiceNetwork:
and service_type != 'INFOBLOX', "Invalid service type."
return _allocate_network(ipam_params.INFOBLOX,
getattr(ipam_params, service_type).V6,
6)
6,
extattrs)
def _find_next_available_ip(infoblox_params, network_ref):
......@@ -242,7 +249,7 @@ def _find_next_available_ip(infoblox_params, network_ref):
return received_ip[0]
def _allocate_host(hostname=None, addr=None, network=None
def _allocate_host(hostname=None, addr=None, network=None, extattrs={}
) -> Union[V4HostAddress, V6HostAddress]:
"""
If network is not None, allocate host in that network.
......@@ -278,7 +285,8 @@ def _allocate_host(hostname=None, addr=None, network=None
],
"name": hostname,
"configure_for_dns": False,
"view": "default"
"view": "default",
"extattrs": extattrs
}
r = requests.post(
......@@ -296,7 +304,8 @@ def _allocate_host(hostname=None, addr=None, network=None
dns_req_payload = {
f"ipv{ip_version}addr": addr,
"name": hostname,
"view": "default"
"view": "default",
"extattrs": extattrs
}
endpoint = 'record:a' if ip_version == 4 else 'record:aaaa'
......@@ -322,7 +331,8 @@ def _allocate_host(hostname=None, addr=None, network=None
def allocate_service_host(hostname=None,
service_type=None,
service_networks: ServiceNetworks = None,
host_addresses: HostAddresses = None
host_addresses: HostAddresses = None,
extattrs={}
) -> HostAddresses:
"""
Allocate host with both IPv4 and IPv6 address (and respective DNS
......@@ -370,19 +380,22 @@ def allocate_service_host(hostname=None,
assert first_nonfull_ipv4_network, \
"No available IPv4 addresses for this service type."
v4_host = _allocate_host(hostname=hostname+domain_name,
network=first_nonfull_ipv4_network)
network=first_nonfull_ipv4_network,
extattrs=extattrs)
elif service_networks:
network = service_networks.v4
assert any(network.subnet_of(ipv4_container)
for ipv4_container in ipv4_containers)
v4_host = _allocate_host(hostname=hostname+domain_name,
network=str(network))
network=str(network),
extattrs=extattrs)
elif host_addresses:
addr = host_addresses.v4
assert any(addr in ipv4_container
for ipv4_container in ipv4_containers)
v4_host = _allocate_host(hostname=hostname+domain_name,
addr=str(addr))
addr=str(addr),
extattrs=extattrs)
# IPv6
if not service_networks and not host_addresses:
......@@ -396,19 +409,22 @@ def allocate_service_host(hostname=None,
assert 'network' in ipv6_networks_info[0]
# TODO: if "no available IP" error, create a new network?
v6_host = _allocate_host(hostname=hostname+domain_name,
network=ipv6_networks_info[0]['network'])
network=ipv6_networks_info[0]['network'],
extattrs=extattrs)
elif service_networks:
network = service_networks.v6
assert any(network.subnet_of(ipv6_container)
for ipv6_container in ipv6_containers)
v6_host = _allocate_host(hostname=hostname+domain_name,
network=str(network))
network=str(network),
extattrs=extattrs)
elif host_addresses:
addr = host_addresses.v6
assert any(addr in ipv6_container
for ipv6_container in ipv6_containers)
v6_host = _allocate_host(hostname=hostname+domain_name,
addr=str(addr))
addr=str(addr),
extattrs=extattrs)
return HostAddresses(v4=v4_host.v4, v6=v6_host.v6)
......
......@@ -30,11 +30,11 @@ class HostAddresses(BaseSettings):
v6: ipaddress.IPv6Address
def new_service_networks(service_type) -> ServiceNetworks:
def new_service_networks(service_type, extattrs={}) -> ServiceNetworks:
v4_service_network = _ipam.allocate_service_ipv4_network(
service_type=service_type)
service_type=service_type, extattrs=extattrs)
v6_service_network = _ipam.allocate_service_ipv6_network(
service_type=service_type)
service_type=service_type, extattrs=extattrs)
return ServiceNetworks(
v4=v4_service_network.v4,
v6=v6_service_network.v6)
......@@ -42,32 +42,58 @@ def new_service_networks(service_type) -> ServiceNetworks:
def new_service_host(hostname,
service_type,
service_networks: ServiceNetworks) -> HostAddresses:
service_networks: ServiceNetworks = None,
host_addresses: HostAddresses = None,
extattrs={}) -> HostAddresses:
return _ipam.allocate_service_host(
hostname=hostname,
service_type=service_type,
service_networks=service_networks)
service_networks=service_networks,
host_addresses=host_addresses,
extattrs=extattrs)
if __name__ == '__main__':
# sample call flow to allocate two loopback interfaces and a trunk service
# new_service_host can be called passing networks or addresses
# - the first time is called by passing a specific ipv4/ipv6 address pair
# - the rest are called by passing the ipv4/ipv6 network pair
# - host h1 for service LO uses a specific ipv4/ipv6 address pair
# - the rest use the ipv4/ipv6 network pair
# networks and hosts can be allocated with extensible attributes
# - host h2 for service LO uses extattrs for both network and address/DNS
# - the rest don't use extattrs
hostname_A = 'newhost1'
hostname_B = 'newhost2'
# h1 loopback
lo1_service_networks = new_service_networks('LO')
hostname_A = 'h1'
hostname_B = 'h2'
# h1 LO (loopback)
lo1_service_networks = new_service_networks(service_type='LO')
lo1_v4_host_address = lo1_service_networks.v4.network_address
lo1_v6_host_address = lo1_service_networks.v6.network_address
lo1_host_addresses = HostAddresses(v4=lo1_v4_host_address,
v6=lo1_v6_host_address)
new_service_host(hostname_A, 'LO', lo1_service_networks)
# h2 loopback
lo2_service_networks = new_service_networks('LO')
new_service_host(hostname_B, 'LO', lo2_service_networks)
# h1-h2 trunk
trunk12_service_networks = new_service_networks('TRUNK')
new_service_host(hostname_A, 'TRUNK', trunk12_service_networks)
new_service_host(hostname_B, 'TRUNK', trunk12_service_networks)
new_service_host(hostname=hostname_A,
service_type='LO',
host_addresses=lo1_host_addresses)
# h2 LO (loopback)
lo2_network_extattrs = {
"vrf_name": {"value": "dummy_vrf"},
}
lo2_host_extattrs = {
"Site": {"value": "dummy_site"},
}
lo2_service_networks = \
new_service_networks(service_type='LO', extattrs=lo2_network_extattrs)
new_service_host(hostname=hostname_B,
service_type='LO',
service_networks=lo2_service_networks,
extattrs=lo2_host_extattrs)
# h1-h2 TRUNK
trunk12_service_networks = new_service_networks(service_type='TRUNK')
new_service_host(hostname=hostname_A,
service_type='TRUNK',
service_networks=trunk12_service_networks)
new_service_host(hostname=hostname_B,
service_type='TRUNK',
service_networks=trunk12_service_networks)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment