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

NAT-200: delete network in ipam

parent 63f6f34f
Branches
Tags
2 merge requests!27Merge develop into NAT-185,!15Nat 185
This commit is part of merge request !15. Comments created here will be created in the context of that merge request.
...@@ -172,9 +172,9 @@ def _allocate_network( ...@@ -172,9 +172,9 @@ def _allocate_network(
assert 'network' in r.json() assert 'network' in r.json()
allocated_network = r.json()['network'] allocated_network = r.json()['network']
if ip_version == 4: if ip_version == 4:
return V4ServiceNetwork(v4=allocated_network) return V4ServiceNetwork(v4=ipaddress.ip_network(allocated_network))
else: else:
return V6ServiceNetwork(v6=allocated_network) return V6ServiceNetwork(v6=ipaddress.ip_network(allocated_network))
def allocate_service_ipv4_network(service_type, comment="", extattrs={} def allocate_service_ipv4_network(service_type, comment="", extattrs={}
...@@ -495,6 +495,72 @@ def allocate_service_host(hostname=None, ...@@ -495,6 +495,72 @@ def allocate_service_host(hostname=None,
return host return host
def delete_service_network(network, service_type=None
) -> Union[V4ServiceNetwork, V6ServiceNetwork]:
"""
Delete IPv4 or IPv6 network by CIDR.
"""
oss = settings.load_oss_params()
assert oss.IPAM
ipam_params = oss.IPAM
assert ipam_params.INFOBLOX
infoblox_params = ipam_params.INFOBLOX
assert hasattr(ipam_params, service_type) \
and service_type != 'INFOBLOX', "Invalid service type."
ip_version = _ip_network_version(network)
ipnetwork = ipaddress.ip_network(network)
# Ensure that the network to be deleted is under the service type.
# Otherwise user is not allowed to delete it
if ip_version == 4:
oss_ipv4_containers = getattr(ipam_params, service_type).V4.containers
oss_ipv4_networks = getattr(ipam_params, service_type).V4.networks
if oss_ipv4_containers:
assert any(ipnetwork.subnet_of(oss_ipv4_container)
for oss_ipv4_container in oss_ipv4_containers), \
"Can't delete: network doesn't belong to service type."
else:
assert ipnetwork in oss_ipv4_networks, \
"Can't delete: network doesn't belong to service type."
else:
oss_ipv6_containers = getattr(ipam_params, service_type).V6.containers
oss_ipv6_networks = getattr(ipam_params, service_type).V6.networks
if oss_ipv6_containers:
assert any(ipnetwork.subnet_of(oss_ipv6_container)
for oss_ipv6_container in oss_ipv6_containers), \
"Can't delete: network doesn't belong to service type."
else:
assert ipnetwork in oss_ipv6_networks, \
"Can't delete: network doesn't belong to service type."
network_info = _find_networks(network=network, ip_version=ip_version)
assert len(network_info) == 1, "Network does not exist."
assert '_ref' in network_info[0]
r = requests.delete(
f'{_wapi(infoblox_params)}/{network_info[0]["_ref"]}',
auth=HTTPBasicAuth(infoblox_params.username,
infoblox_params.password),
verify=False
)
assert r.status_code >= 200 and r.status_code < 300, \
f"HTTP error {r.status_code}: {r.reason}\n\n{r.text}"
# Extract ipv4/ipv6 address from the network reference obtained in the
# response
r_text = r.text
print(r_text)
network_address = ipaddress.ip_network(
r_text.rsplit("/", 1)[0].split(":")[1].replace("%3A", ":"))
if ip_version == 4:
return V4ServiceNetwork(v4=ipaddress.ip_network(network_address))
else:
return V6ServiceNetwork(v6=ipaddress.ip_network(network_address))
""" """
Below methods are not used for supported outside calls Below methods are not used for supported outside calls
""" """
...@@ -556,43 +622,6 @@ def _get_network_capacity(network=None): ...@@ -556,43 +622,6 @@ def _get_network_capacity(network=None):
return utilization return utilization
def _delete_network(network) -> Union[V4ServiceNetwork, V6ServiceNetwork]:
"""
Delete IPv4 or IPv6 network by CIDR.
"""
# TODO: should we check that there are no hosts in this network before
# deleting? Deleting a network deletes the hosts in it, but not the
# associated DNS records.
oss = settings.load_oss_params()
assert oss.IPAM.INFOBLOX
infoblox_params = oss.IPAM.INFOBLOX
ip_version = _ip_network_version(network)
network_info = _find_networks(network=network, ip_version=ip_version)
assert len(network_info) == 1, "Network does not exist."
assert '_ref' in network_info[0]
r = requests.delete(
f'{_wapi(infoblox_params)}/{network_info[0]["_ref"]}',
auth=HTTPBasicAuth(infoblox_params.username,
infoblox_params.password),
verify=False
)
assert r.status_code >= 200 and r.status_code < 300, \
f"HTTP error {r.status_code}: {r.reason}\n\n{r.text}"
# Extract ipv4/ipv6 address from the network reference obtained in the
# response
r_json = r.json()
network_address = ipaddress.ip_network(
r_json.rsplit("/", 1)[0].split(":")[1].replace("%3A", ":"))
if ip_version == 4:
return V4ServiceNetwork(v4=network_address)
else:
return V6ServiceNetwork(v6=network_address)
def _delete_host_by_ip(addr) -> Union[V4HostAddress, V6HostAddress]: def _delete_host_by_ip(addr) -> Union[V4HostAddress, V6HostAddress]:
""" """
Delete IPv4 or IPv6 host by its address. Delete IPv4 or IPv6 host by its address.
......
import ipaddress import ipaddress
from pydantic import BaseSettings from pydantic import BaseSettings
from typing import Union
from gso.services import _ipam from gso.services import _ipam
...@@ -57,6 +58,14 @@ def new_service_host(hostname, ...@@ -57,6 +58,14 @@ def new_service_host(hostname,
extattrs=extattrs) extattrs=extattrs)
def delete_service_network(network, service_type
) -> Union[V4ServiceNetwork, V6ServiceNetwork]:
return _ipam.delete_service_network(
network=network,
service_type=service_type
)
if __name__ == '__main__': if __name__ == '__main__':
# sample call flow to allocate two loopback interfaces and a trunk service # sample call flow to allocate two loopback interfaces and a trunk service
# new_service_host can be called passing networks, addresses, or nothing. # new_service_host can be called passing networks, addresses, or nothing.
...@@ -74,11 +83,11 @@ if __name__ == '__main__': ...@@ -74,11 +83,11 @@ if __name__ == '__main__':
# loA_v4_host_address = ipaddress.ip_address('10.255.255.0') # loA_v4_host_address = ipaddress.ip_address('10.255.255.0')
# loA_v6_host_address = ipaddress.ip_address('dead:beef::0') # loA_v6_host_address = ipaddress.ip_address('dead:beef::0')
# loA_host_addresses = HostAddresses(v4=loA_v4_host_address, # loA_host_addresses = HostAddresses(v4=loA_v4_host_address,
# v6=loA_v6_host_address) # v6=loA_v6_host_address)
# new_service_host(hostname=hostname_A+"_LO", # new_service_host(hostname=hostname_A+"_LO",
# host_addresses=loA_host_addresses, # host_addresses=loA_host_addresses,
# cname_aliases=["alias1.hA", "alias2.hA"], # cname_aliases=["alias1.hA", "alias2.hA"],
# service_type='LO') # service_type='LO')
new_service_host(hostname=hostname_A+"_LO", new_service_host(hostname=hostname_A+"_LO",
cname_aliases=["alias1.hA", "alias2.hA"], cname_aliases=["alias1.hA", "alias2.hA"],
service_type='LO') service_type='LO')
......
...@@ -70,7 +70,6 @@ def test_new_service_host(data_config_filename): ...@@ -70,7 +70,6 @@ def test_new_service_host(data_config_filename):
"network_view": "default" "network_view": "default"
} }
] ]
) )
responses.add( responses.add(
...@@ -83,7 +82,6 @@ def test_new_service_host(data_config_filename): ...@@ -83,7 +82,6 @@ def test_new_service_host(data_config_filename):
"network_view": "default" "network_view": "default"
} }
] ]
) )
responses.add( responses.add(
...@@ -194,3 +192,97 @@ def test_new_service_host(data_config_filename): ...@@ -194,3 +192,97 @@ def test_new_service_host(data_config_filename):
) )
) )
assert service_hosts is None assert service_hosts is None
@responses.activate
def test_delete_service_network(data_config_filename):
responses.add(
method=responses.GET,
url=re.compile(r'.*/wapi.*/network.*10.255.255.0.*'),
json=[
{
"_ref": "network/ZG5zLm5ldHdvcmskMTAuMjU1LjI1NS4yMC8zMi8w:10.255.255.0/26/default", # noqa: E501
"network": "10.255.255.0/26",
"network_view": "default"
}
]
)
responses.add(
method=responses.GET,
url=re.compile(r'.*/wapi.*/network.*10.255.255.20.*'),
json=[
{
"_ref": "network/ZG5zLm5Gd0VHQkRQUjMzLjMwNzIuMzE1LzAyLzI:100.255.255.20/32/default", # noqa: E501
"network": "100.255.255.20/32",
"network_view": "default"
}
]
)
responses.add(
method=responses.GET,
url=re.compile(r'.*/wapi.*/ipv6network.*dead.*beef.*'),
json=[
{
"_ref": "ipv6network/ZG5zLm5ldHdvcmskZGVhZDpiZWVmOjoxOC8xMjgvMA:dead%3Abeef%3A%3A18/128/default", # noqa: E501
"network": "dead:beef::18/128",
"network_view": "default"
}
]
)
responses.add(
method=responses.GET,
url=re.compile(r'.*/wapi.*/ipv6network.*beef.*dead.*'),
json=[
{
"_ref": "ipv6network/ZG5zLm5ldHdvcmskZGVhZDpiZWVmOjoxOC8xMjgvMA:beef%3Adead%3A%3A18/128/default", # noqa: E501
"network": "beef:dead::18/128",
"network_view": "default"
}
]
)
responses.add(
method=responses.DELETE,
url=re.compile(r'.*/wapi.*/network.*10.255.255.0.*'),
body="network/ZG5zLm5ldHdvcmskMTAuMjU1LjI1NS4yMC8zMi8w:10.255.255.0/26/default" # noqa: E501
)
responses.add(
method=responses.DELETE,
url=re.compile(r'.*/wapi.*/network.*100.255.255.*'),
body="network/ZG5zLm5Gd0VHQkRQUjMzLjMwNzIuMzE1LzAyLzI:100.255.255.20/32/default" # noqa: E501
)
responses.add(
method=responses.DELETE,
url=re.compile(r'.*/wapi.*/ipv6network.*dead.*beef.*'),
body="ipv6network/ZG5zLm5ldHdvcmskZGVhZDpiZWVmOjoxOC8xMjgvMA:dead%3Abeef%3A%3A18/128/default" # noqa: E501
)
responses.add(
method=responses.DELETE,
url=re.compile(r'.*/wapi.*/ipv6network.*beef.*dead.*'),
body="ipv6network/ZG5zLm5ldHdvcmskZGVhZDpiZWVmOjoxOC8xMjgvMA:beef%3Adead%3A%3A18/128/default" # noqa: E501
)
service_network = ipam.delete_service_network(network='10.255.255.0/26', service_type='LO') # noqa: E501
assert service_network == ipam.V4ServiceNetwork(
v4=ipaddress.ip_network('10.255.255.0/26')
)
with pytest.raises(AssertionError):
service_network = ipam.delete_service_network(network='10.255.255.20/32', service_type='LO') # noqa: E501
assert service_network is None
service_network = ipam.delete_service_network(network='dead:beef::18/128', service_type='TRUNK') # noqa: E501
assert service_network == ipam.V6ServiceNetwork(
v6=ipaddress.ip_network('dead:beef::18/128')
)
with pytest.raises(AssertionError):
service_network = ipam.delete_service_network(network='beef:dead::18/128', service_type='TRUNK') # noqa: E501
assert service_network is None
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment