diff --git a/test/conftest.py b/test/conftest.py index 03d00132e5dd950ae963063d4d05c9887c7853ed..83996ad620b2431fdc09185fdbd671b1adda3427 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -57,7 +57,7 @@ def configuration_data() -> dict: "IPAM": { "INFOBLOX": { "scheme": "https", - "wapi_version": "v2.12", + "wapi_version": "2.12", "host": "10.0.0.1", "username": "robot-user", "password": "robot-user-password", diff --git a/test/services/__init__.py b/test/services/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/services/test_infoblox.py b/test/services/test_infoblox.py new file mode 100644 index 0000000000000000000000000000000000000000..003107a3cb5feb6696d40c791582ecfd966f920e --- /dev/null +++ b/test/services/test_infoblox.py @@ -0,0 +1,286 @@ +import ipaddress +import re +from os import PathLike + +import pytest +import responses +from requests import codes + +from gso.services import infoblox +from gso.services.infoblox import AllocationError, DeletionError + + +def _set_up_network_responses(): + responses.add(method=responses.GET, url=re.compile(r".+/wapi/v2\.12/network\?network=10\.255\.255\.0.+"), json=[]) + + responses.add(method=responses.GET, url=re.compile(r".+/wapi/v2\.12/ipv6network\?network=dead%3Abeef.+"), json=[]) + + responses.add( + method=responses.POST, + url=re.compile(r".+/wapi/v2\.12/network.+"), + json={ + "_ref": "network/ZG5zLm5ldHdvcmskMTAuMjU1LjI1NS4yMC8zMi8w:10.255.255.20/32/default", + "network": "10.255.255.20/32", + }, + status=codes.CREATED, + ) + + responses.add( + method=responses.POST, + url=re.compile(r".+/wapi/v2\.12/ipv6network.+"), + json={ + "_ref": "ipv6network/ZG5zLm5ldHdvcmskZGVhZDpiZWVmOjoxOC8xMjgvMA:dead%3Abeef%3A%3A18/128/default", + "network": "dead:beef::18/128", + }, + status=codes.CREATED, + ) + + +def _set_up_host_responses(): + responses.add( + method=responses.GET, + url="https://10.0.0.1/wapi/v2.12/record%3Ahost?_return_fields=extattrs%2Cipv6addrs%2Cname%2Cview%2Caliases", + json=[], + ) + + responses.add( + method=responses.GET, + url="https://10.0.0.1/wapi/v2.12/record%3Ahost?name=test.lo.geant.net&ipv6addr=func%3Anextavailableip%3Adead%3A" + "beef%3A%3A%2F80%2Cdefault", + json=[], + ) + + responses.add( + method=responses.GET, + url="https://10.0.0.1/wapi/v2.12/record%3Ahost?name=test.lo.geant.net&_return_fields=extattrs%2Cipv4addrs%2Cnam" + "e%2Cview%2Caliases", + json=[], + ) + + responses.add( + method=responses.GET, + url="https://10.0.0.1/wapi/v2.12/record%3Ahost?name=broken&_return_fields=extattrs%2Cipv4addrs%2Cname%2Cview%2C" + "aliases", + json=[], + ) + + responses.add( + method=responses.GET, + url=re.compile( + r"https://10.0.0.1/wapi/v2.12/record%3Ahost\?name=broken&ipv6addr=func%3Anextavailableip%3Adead%3Abeef%3A%3" + r"A%2F80%2Cdefault.*" + ), + json=[], + status=codes.BAD, + ) + + responses.add( + method=responses.POST, + url=re.compile(r".+/wapi/v2\.12/record%3Ahost\?_return_fields=extattrs%2Cipv6addrs.+"), + json={ + "_ref": "record:host/ZG5zLmhvc3QkLl9kZWZhdWx0Lm5ldC5nZWFudC5sby50ZXN0:test.lo.geant.net/default", + "ipv6addrs": [ + { + "_ref": "record:host_ipv6addr/ZG5zLmhvc3RfYWRkcmVzcyQuX2RlZmF1bHQubmV0LmdlYW50LmxvLnRlc3QuZGVhZDpiZ" + "WVmOjoxLg:dead%3Abeef%3A%3A1/test.lo.geant.net/default", + "configure_for_dhcp": False, + "duid": "00:00:00:00:00:00:00:00:00:00", + "host": "test.lo.geant.net", + "ipv6addr": "dead:beef::1", + } + ], + "ip": "dead:beef::1", + "name": "test.lo.geant.net", + "view": "default", + }, + status=codes.CREATED, + ) + + responses.add( + method=responses.PUT, + url="https://10.0.0.1/wapi/v2.12/record%3Ahost/ZG5zLmhvc3QkLl9kZWZhdWx0Lm5ldC5nZWFudC5sd28udGVzdA%3Atest.lo.gea" + "nt.net/default?_return_fields=extattrs%2Cipv4addrs%2Cname%2Cview%2Caliases", + json={ + "ipv4addrs": [ + { + "_ref": "record:host_ipv4addr/ZG5zLmhvc3RfYWRkcmVzcyQuX2RlZmF1bHQubmV0LmdlYW50Lmx3by50ZXN0LjEwLjI1N" + "S4yNTUuMTI5Lg:10.255.255.129/test.lo.geant.net/default", + "configure_for_dhcp": False, + "host": "test.lo.geant.net", + "ipv4addr": "10.255.255.129", + "mac": "00:00:00:00:00:00", + } + ], + "name": "test.lo.geant.net", + "view": "default", + }, + ) + + responses.add( + method=responses.GET, + url="https://10.0.0.1/wapi/v2.12/record%3Ahost?name=test.lo.geant.net&_return_fields=extattrs%2Cipv4addrs%2Cnam" + "e%2Cview%2Caliases", + json=[ + { + "_ref": "record:host/ZG5zLmhvc3QkLl9kZWZhdWx0Lm5ldC5nZWFudC5sd28udGVzdA:test.lo.geant.net/default", + "ipv4addrs": [ + { + "_ref": "record:host_ipv4addr/ZG5zLmhvc3RfYWRkcmVzcyQuX2RlZmF1bHQubmV0LmdlYW50Lmx3by50ZXN0LjEwL" + "jI1N" + "S4yNTUuMTI5Lg:10.255.255.129/test.lo.geant.net/default", + "configure_for_dhcp": False, + "host": "test.lo.geant.net", + "ipv4addr": "10.255.255.129", + "mac": "00:00:00:00:00:00", + } + ], + "name": "test.lo.geant.net", + "view": "default", + } + ], + ) + + +@responses.activate +def test_allocate_networks(data_config_filename: PathLike): + _set_up_network_responses() + + new_v4_network = infoblox.allocate_v4_network("TRUNK") + new_v6_network = infoblox.allocate_v6_network("TRUNK") + + assert new_v4_network == ipaddress.IPv4Network("10.255.255.20/32") + assert new_v6_network == ipaddress.IPv6Network("dead:beef::18/128") + + +@responses.activate +def test_allocate_bad_network(data_config_filename: PathLike): + _set_up_network_responses() + + with pytest.raises(AllocationError) as e: + infoblox.allocate_v4_network("LO") + assert e.value.args[0] == "Cannot allocate anything in [], check whether any IP space is available." + + with pytest.raises(AllocationError) as e: + infoblox.allocate_v6_network("LO") + assert e.value.args[0] == "Cannot allocate anything in [], check whether any IP space is available." + + +@responses.activate +def test_allocate_good_host(data_config_filename: PathLike): + _set_up_host_responses() + new_host = infoblox.allocate_host("test.lo.geant.net", "LO", [], "test host") + assert new_host == (ipaddress.ip_address("10.255.255.129"), ipaddress.ip_address("dead:beef::1")) + + +@responses.activate +def test_allocate_bad_host(data_config_filename: PathLike): + _set_up_host_responses() + with pytest.raises(AllocationError) as e: + infoblox.allocate_host("broken", "TRUNK", [], "Unavailable host") + assert e.value.args[0] == "Cannot find 1 available IP address in networks []." + + +@responses.activate +def test_delete_good_network(data_config_filename: PathLike): + responses.add( + method=responses.GET, + url="https://10.0.0.1/wapi/v2.12/network?network=10.255.255.0%2F26&_return_fields=comment%2Cextattrs%2Cnetwork%" + "2Cnetwork_view", + json=[ + { + "_ref": "network/ZG5zLm5ldHdvcmskNjIuNDAuOTYuMC8yNC8w:10.255.255.0/26/default", + "network": "10.255.255.0/26", + "network_view": "default", + } + ], + ) + + responses.add( + method=responses.DELETE, + url="https://10.0.0.1/wapi/v2.12/network/ZG5zLm5ldHdvcmskNjIuNDAuOTYuMC8yNC8w%3A10.255.255.0/26/default", + json=[], + ) + + infoblox.delete_network(ipaddress.IPv4Network("10.255.255.0/26")) + + +@responses.activate +def test_delete_non_existent_network(data_config_filename: PathLike): + responses.add( + method=responses.GET, + url="https://10.0.0.1/wapi/v2.12/network?network=10.255.255.0%2F26&_return_fields=comment%2Cextattrs%2Cnetwork%" + "2Cnetwork_view", + json=[], + ) + + with pytest.raises(DeletionError) as e: + infoblox.delete_network(ipaddress.IPv4Network("10.255.255.0/26")) + assert e.value.args[0] == "Could not find network 10.255.255.0/26, nothing has been deleted." + + +@responses.activate +def test_delete_good_host(data_config_filename: PathLike): + responses.add( + method=responses.GET, + url=re.compile( + r"https://10\.0\.0\.1/wapi/v2\.12/record%3Ahost\?(?:name=ha_lo\.gso|ipv4addr=10\.255\.255\.1)?.+" + ), + json=[ + { + "_ref": "record:host/ZG5zLmhvc3QkLl9kZWZhdWx0Lmdzby5oYV9sbw:ha_lo.gso/default", + "ipv4addrs": [ + { + "_ref": "record:host_ipv4addr/ZG5zLmhvc3RfYWRkcmVzcyQuX2RlZmF1bHQuZ3NvLmhhX2xvLjEwLjI1NS4yNTUuM" + "S40.255.255.1/ha_lo.gso/default", + "configure_for_dhcp": False, + "host": "ha_lo.gso", + "ipv4addr": "10.255.255.1", + } + ], + "ipv6addrs": [ + { + "_ref": "record:host_ipv6addr/ZG5zLmhvc3RfYWRkcmVzcyQuX2RlZmF1bHQuZvLmhhX2xvLmRlYWQ6YmVlZjo6MS4" + ":dead%3Abeef%3A%3A1/ha_lo.gso/default", + "configure_for_dhcp": False, + "host": "ha_lo.gso", + "ipv6addr": "dead:beef::1", + } + ], + "name": "ha_lo.gso", + "view": "default", + } + ], + ) + + responses.add( + method=responses.DELETE, + url=re.compile( + r"https://10\.0\.0\.1/wapi/v2\.12/record%3Ahost/.+(ha_lo\.gso|dead:beef::1|10\.255\.255\.1)/default" + ), + json=[], + ) + + infoblox.delete_host_by_fqdn("ha_lo.gso") + infoblox.delete_host_by_ip(ipaddress.IPv4Address("10.255.255.1")) + infoblox.delete_host_by_ip(ipaddress.IPv6Address("dead:beef::1")) + + +@responses.activate +def test_delete_bad_host(data_config_filename: PathLike): + responses.add( + method=responses.GET, + url=re.compile(r".+"), + json=[], + ) + + with pytest.raises(DeletionError) as e: + infoblox.delete_host_by_ip(ipaddress.IPv4Address("10.255.255.1")) + assert e.value.args[0] == "Could not find host at 10.255.255.1, nothing has been deleted." + + with pytest.raises(DeletionError) as e: + infoblox.delete_host_by_ip(ipaddress.IPv6Address("dead:beef::1")) + assert e.value.args[0] == "Could not find host at dead:beef::1, nothing has been deleted." + + with pytest.raises(DeletionError) as e: + infoblox.delete_host_by_fqdn("fake.host.net") + assert e.value.args[0] == "Could not find host at fake.host.net, nothing has been deleted." diff --git a/test/test_ipam.py b/test/test_ipam.py deleted file mode 100644 index 13d24b34b3d1696720025673fc8850057a8369bc..0000000000000000000000000000000000000000 --- a/test/test_ipam.py +++ /dev/null @@ -1,466 +0,0 @@ -import ipaddress -import re -from os import PathLike - -import pytest -import responses - -from gso.services import ipam - - -@responses.activate -def test_allocate_networks(data_config_filename: PathLike): - responses.add( - method=responses.POST, - url=re.compile(r".*/wapi.*/network.*"), - json={ - "_ref": "network/ZG5zLm5ldHdvcmskMTAuMjU1LjI1NS4yMC8zMi8w:10.255.255.20/32/default", # noqa: E501 - "network": "10.255.255.20/32", - }, - ) - - responses.add( - method=responses.POST, - url=re.compile(r".*/wapi.*/ipv6network.*"), - json={ - "_ref": "ipv6network/ZG5zLm5ldHdvcmskZGVhZDpiZWVmOjoxOC8xMjgvMA:dead%3Abeef%3A%3A18/128/default", # noqa: E501 - "network": "dead:beef::18/128", - }, - ) - - service_networks = ipam.allocate_networks(service_type="TRUNK") - assert service_networks == ipam.ServiceNetworks( - v4=ipaddress.ip_network("10.255.255.20/32"), v6=ipaddress.ip_network("dead:beef::18/128") - ) - - # should fail because this service type has networks instead of containers - with pytest.raises(AssertionError): - service_networks = ipam.allocate_networks(service_type="LO") - assert service_networks is None - - -@responses.activate -def test_allocate_host(data_config_filename: PathLike): - responses.add( - method=responses.POST, - url=re.compile(r".*/wapi.*/record:host$"), - json="record:host/ZG5zLmhvc3QkLm5vbl9ETlNfaG9zdF9yb290LjAuMTY4MzcwNTU4MzY3MC5nc28udGVzdA:test.lo/%20", # noqa: E501 - ) - - responses.add( - method=responses.GET, - url=re.compile(r".*/wapi.*/network.*10.255.255.*"), - json=[ - { - "_ref": "network/ZG5zLm5ldHdvcmskMTAuMjU1LjI1NS4yMC8zMi8w:10.255.255.20/32/default", # noqa: E501 - "network": "10.255.255.20/32", - "network_view": "default", - } - ], - ) - - responses.add( - method=responses.GET, - url=re.compile(r".*/wapi.*/network.*10.255.254.*"), - json=[ - { - "_ref": "network/ZG5zLm5Gd0VHQkRQUjMzLjMwNzIuMzE1LzAyLzI:10.255.254.20/32/default", # noqa: E501 - "network": "10.255.254.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=[]) - - responses.add( - method=responses.POST, - url=re.compile(r".*/wapi.*/network/.*10.255.255.*?_function=next_available_ip&num=1$"), # noqa: E501 - json={"ips": ["10.255.255.20"]}, - ) - - responses.add( - method=responses.POST, - url=re.compile(r".*/wapi.*/network/.*10.255.254.*?_function=next_available_ip&num=1$"), # noqa: E501 - body="Cannot find 1 available IP address(es) in this network", - status=400, - ) - - responses.add( - method=responses.POST, - url=re.compile(r".*/wapi.*/ipv6network/.*?_function=next_available_ip&num=1$"), # noqa: E501 - json={"ips": ["dead:beef::18"]}, - ) - - responses.add( - method=responses.POST, - url=re.compile(r".*/wapi.*/network.*_return_fields.*"), - json={ - "_ref": "network/ZG5zLm5ldHdvcmskMTAuMjU1LjI1NS4yMC8zMi8w:10.255.255.20/32/default", # noqa: E501 - "network": "10.255.255.20/32", - }, - ) - - responses.add( - method=responses.POST, - url=re.compile(r".*/wapi.*/ipv6network.*_return_fields.*"), - json={ - "_ref": "ipv6network/ZG5zLm5ldHdvcmskZGVhZDpiZWVmOjoxOC8xMjgvMA:dead%3Abeef%3A%3A18/128/default", # noqa: E501 - "network": "dead:beef::18/128", - }, - ) - - # test host creation by IP addresses - service_hosts = ipam.allocate_host( - hostname="test", - service_type="TRUNK", - host_addresses=ipam.HostAddresses( - v4=ipaddress.ip_address("10.255.255.20"), v6=ipaddress.ip_address("dead:beef::18") - ), - ) - assert service_hosts == ipam.HostAddresses( - v4=ipaddress.ip_address("10.255.255.20"), v6=ipaddress.ip_address("dead:beef::18") - ) - - # test host creation by network addresses - service_hosts = ipam.allocate_host( - hostname="test", - service_type="TRUNK", - service_networks=ipam.ServiceNetworks( - v4=ipaddress.ip_network("10.255.255.20/32"), v6=ipaddress.ip_network("dead:beef::18/128") - ), - ) - assert service_hosts == ipam.HostAddresses( - v4=ipaddress.ip_address("10.255.255.20"), v6=ipaddress.ip_address("dead:beef::18") - ) - - # test host creation by just service_type when service cfg uses networks - service_hosts = ipam.allocate_host(hostname="test", service_type="LO") - assert service_hosts == ipam.HostAddresses( - v4=ipaddress.ip_address("10.255.255.20"), v6=ipaddress.ip_address("dead:beef::18") - ) - - # test host creation by just service_type when service cfg uses containers - service_hosts = ipam.allocate_host(hostname="test", service_type="TRUNK") - assert service_hosts == ipam.HostAddresses( - v4=ipaddress.ip_address("10.255.255.20"), v6=ipaddress.ip_address("dead:beef::18") - ) - - # test host creation that should return a no available IP error - with pytest.raises(AssertionError): - service_hosts = ipam.allocate_host( - hostname="test", - service_type="TRUNK", - service_networks=ipam.ServiceNetworks( - v4=ipaddress.ip_network("10.255.254.20/32"), v6=ipaddress.ip_network("dead:beef::18/128") - ), - ) - assert service_hosts is None - - # test host creation that should return a network not exist error - with pytest.raises(AssertionError): - service_hosts = ipam.allocate_host( - hostname="test", - service_type="TRUNK", - service_networks=ipam.ServiceNetworks( - v4=ipaddress.ip_network("10.255.255.20/32"), v6=ipaddress.ip_network("beef:dead::18/128") - ), - ) - assert service_hosts is None - - -@responses.activate -def test_delete_network(data_config_filename: PathLike): - 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_network(network=ipaddress.ip_network("10.255.255.0/26"), service_type="LO") - assert service_network == ipam.V4ServiceNetwork(v4=ipaddress.ip_network("10.255.255.0/26")) - - with pytest.raises(AssertionError): - service_network = ipam.delete_network(network=ipaddress.ip_network("10.255.255.20/32"), service_type="LO") - assert service_network is None - - service_network = ipam.delete_network(network=ipaddress.ip_network("dead:beef::18/128"), service_type="TRUNK") - assert service_network == ipam.V6ServiceNetwork(v6=ipaddress.ip_network("dead:beef::18/128")) - - with pytest.raises(AssertionError): - service_network = ipam.delete_network(network=ipaddress.ip_network("beef:dead::18/128"), service_type="TRUNK") - assert service_network is None - - -@responses.activate -def test_delete_host(data_config_filename: PathLike): - responses.add( - method=responses.GET, - url=re.compile(r".*/wapi.*record:host.*"), - json=[ - { - "_ref": "record:host/ZG5zLmhvc3QkLl9kZWZhdWx0Lmdzby5oYV9sbw:ha_lo.gso/default", # noqa: E501 - "ipv4addrs": [ - { - "_ref": "record:host_ipv4addr/ZG5zLmhvc3RfYWRkcmVzcyQuX2RlZmF1bHQuZ3NvLmhhX2xvLjEwLjI1NS4yNTUuMS40.255.255.1/ha_lo.gso/default", # noqa: E501 - "configure_for_dhcp": False, - "host": "ha_lo.gso", - "ipv4addr": "10.255.255.1", - } - ], - "ipv6addrs": [ - { - "_ref": "record:host_ipv6addr/ZG5zLmhvc3RfYWRkcmVzcyQuX2RlZmF1bHQuZvLmhhX2xvLmRlYWQ6YmVlZjo6MS4:dead%3Abeef%3A%3A1/ha_lo.gso/default", # noqa: E501 - "configure_for_dhcp": False, - "host": "ha_lo.gso", - "ipv6addr": "dead:beef::1", - } - ], - "name": "ha_lo.gso", - "view": "default", - } - ], - ) - - responses.add( - method=responses.GET, - url=re.compile(r".*/wapi.*record:cname.*"), - json=[ - { - "_ref": "record:cname/ZG5zLmJpbmRfY25hbWUkLl9kZWZhdWx0Lmdzby5oYS5hbGlhczE:alias1.ha.gso/default", # noqa: E501 - "canonical": "hA_LO.lo", - "name": "alias1.ha.lo", - "view": "default", - }, - { - "_ref": "record:cname/5zLmJpbmRfY25hbWUkLl9kZWZhdWx0Lmdzby5oYS5hbGlhczI:alias2.ha.gso/default", # noqa: E501 - "canonical": "hA_LO.lo", - "name": "alias2.ha.lo", - "view": "default", - }, - ], - ) - - responses.add( - method=responses.DELETE, - url=re.compile(r".*/wapi.*record:host.*"), - body="record:host/ZG5zLmhvc3QkLl9kZWZhdWx0Lmdzby5oYl9sbw:hb_lo.gso/default", # noqa: E501 - ) - - responses.add( - method=responses.DELETE, - url=re.compile(r".*/wapi.*record:cname.*"), - body="record:cname/ZG5zLmJpbmRfY25hbWUkLl9kZWZhdWx0Lmdzby5oYi5hbGlhczE:alias1.hb.gso/default", # noqa: E501 - ) - - input_host_addresses = ipam.HostAddresses( - v4=ipaddress.ip_address("10.255.255.1"), v6=ipaddress.ip_address("dead:beef::1") - ) - host_addresses = ipam.delete_host( - hostname="ha_lo", - host_addresses=input_host_addresses, - cname_aliases=["alias1.ha", "alias2.ha"], - service_type="LO", - ) - assert host_addresses == ipam.HostAddresses( - v4=ipaddress.ip_address("10.255.255.1"), v6=ipaddress.ip_address("dead:beef::1") - ) - - # Fail because missing CNAME - with pytest.raises(AssertionError): - host_addresses = ipam.delete_host( - hostname="ha_lo", host_addresses=input_host_addresses, cname_aliases=["alias1.ha"], service_type="LO" - ) - assert host_addresses is None - - # Fail because non-matching CNAME - with pytest.raises(AssertionError): - host_addresses = ipam.delete_host( - hostname="ha_lo", - host_addresses=input_host_addresses, - cname_aliases=["alias1.ha", "alias2.ha", "alias3.ha"], - service_type="LO", - ) - assert host_addresses is None - - -@responses.activate -def test_validate_network(data_config_filename: PathLike): - 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", - "comment": "the subscription id is 0123456789abcdef", - } - ], - ) - - service_network = ipam.validate_network( - gso_subscription_id="0123456789abcdef", network=ipam.ipaddress.ip_network("10.255.255.0/26") - ) - assert service_network == ipam.V4ServiceNetwork(v4=ipaddress.ip_network("10.255.255.0/26")) - - # Fail because non-matching subscription id - with pytest.raises(AssertionError): - service_network = ipam.validate_network( - gso_subscription_id="1a2b3c4d5e6f7890", network=ipam.ipaddress.ip_network("10.255.255.0/26") - ) - assert service_network is None - - -@responses.activate -def test_validate_host(data_config_filename: PathLike): - responses.add( - method=responses.GET, - url=re.compile(r".*/wapi.*record:host.*"), - json=[ - { - "_ref": "record:host/ZG5zLmhvc3QkLl9kZWZhdWx0Lmdzby5oYV9sbw:ha_lo.gso/default", # noqa: E501 - "ipv4addrs": [ - { - "_ref": "record:host_ipv4addr/ZG5zLmhvc3RfYWRkcmVzcyQuX2RlZmF1bHQuZ3NvLmhhX2xvLjEwLjI1NS4yNTUuMS40.255.255.1/ha_lo.gso/default", # noqa: E501 - "configure_for_dhcp": False, - "host": "ha_lo.gso", - "ipv4addr": "10.255.255.1", - } - ], - "ipv6addrs": [ - { - "_ref": "record:host_ipv6addr/ZG5zLmhvc3RfYWRkcmVzcyQuX2RlZmF1bHQuZvLmhhX2xvLmRlYWQ6YmVlZjo6MS4:dead%3Abeef%3A%3A1/ha_lo.gso/default", # noqa: E501 - "configure_for_dhcp": False, - "host": "ha_lo.gso", - "ipv6addr": "dead:beef::1", - } - ], - "name": "ha_lo.gso", - "view": "default", - } - ], - ) - - responses.add( - method=responses.GET, - url=re.compile(r".*/wapi.*record:cname.*"), - json=[ - { - "_ref": "record:cname/ZG5zLmJpbmRfY25hbWUkLl9kZWZhdWx0Lmdzby5oYS5hbGlhczE:alias1.ha.gso/default", # noqa: E501 - "canonical": "hA_LO.lo", - "name": "alias1.ha.lo", - "view": "default", - }, - { - "_ref": "record:cname/5zLmJpbmRfY25hbWUkLl9kZWZhdWx0Lmdzby5oYS5hbGlhczI:alias2.ha.gso/default", # noqa: E501 - "canonical": "hA_LO.lo", - "name": "alias2.ha.lo", - "view": "default", - }, - ], - ) - - input_host_addresses = ipam.HostAddresses( - v4=ipaddress.ip_address("10.255.255.1"), v6=ipaddress.ip_address("dead:beef::1") - ) - host_addresses = ipam.validate_host( - hostname="ha_lo", - host_addresses=input_host_addresses, - cname_aliases=["alias1.ha", "alias2.ha"], - service_type="LO", - ) - assert host_addresses == ipam.HostAddresses( - v4=ipaddress.ip_address("10.255.255.1"), v6=ipaddress.ip_address("dead:beef::1") - ) - - # Fail because non-matching hostname - host_addresses = ipam.validate_host( - hostname="wrong_hostname", - host_addresses=input_host_addresses, - cname_aliases=["alias1.ha", "alias2.ha"], - service_type="LO", - ) - with pytest.raises(AssertionError): - host_addresses = ipam.HostAddresses( - v4=ipaddress.ip_address("10.255.255.1"), v6=ipaddress.ip_address("dead:beef::1") - ) - assert host_addresses is None