Skip to content
Snippets Groups Projects
Commit b9a3897d authored by Simone Spinelli's avatar Simone Spinelli
Browse files

Merge branch 'feature/ipam-integration' into 'develop'

Feature/ipam integration

See merge request !16
parents 43f4ad56 4c346d4f
No related branches found
No related tags found
1 merge request!16Feature/ipam integration
...@@ -12,18 +12,18 @@ ...@@ -12,18 +12,18 @@
"password": "robot-user-password" "password": "robot-user-password"
}, },
"LO": { "LO": {
"V4": {"containers": ["1.1.0.0/24"], "mask": 32}, "V4": {"containers": ["1.1.0.0/24"], "networks": [], "mask": 32},
"V6": {"containers": ["dead:beef::/64"], "mask": 128}, "V6": {"containers": ["dead:beef::/64"], "networks": [], "mask": 128},
"domain_name": ".lo" "domain_name": ".lo"
}, },
"TRUNK": { "TRUNK": {
"V4": {"containers": ["1.1.1.0/24"], "mask": 31}, "V4": {"containers": ["1.1.1.0/24"], "networks": [], "mask": 31},
"V6": {"containers": ["dead:beef::/64"], "mask": 126}, "V6": {"containers": ["dead:beef::/64"], "networks": [], "mask": 126},
"domain_name": ".trunk" "domain_name": ".trunk"
}, },
"GEANT_IP": { "GEANT_IP": {
"V4": {"containers": ["1.1.2.0/24"], "mask": 31}, "V4": {"containers": ["1.1.2.0/24"], "networks": [], "mask": 31},
"V6": {"containers": ["dead:beef::/64"], "mask": 126}, "V6": {"containers": ["dead:beef::/64"], "networks": [], "mask": 126},
"domain_name": ".geantip" "domain_name": ".geantip"
} }
}, },
......
This diff is collapsed.
...@@ -46,68 +46,64 @@ def new_service_host(hostname, ...@@ -46,68 +46,64 @@ def new_service_host(hostname,
service_type, service_type,
service_networks: ServiceNetworks = None, service_networks: ServiceNetworks = None,
host_addresses: HostAddresses = None, host_addresses: HostAddresses = None,
cname_aliases=None,
extattrs={}) -> HostAddresses: extattrs={}) -> HostAddresses:
return _ipam.allocate_service_host( return _ipam.allocate_service_host(
hostname=hostname, hostname=hostname,
service_type=service_type, service_type=service_type,
service_networks=service_networks, service_networks=service_networks,
host_addresses=host_addresses, host_addresses=host_addresses,
cname_aliases=cname_aliases,
extattrs=extattrs) extattrs=extattrs)
'''
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 or addresses # new_service_host can be called passing networks, addresses, or nothing.
# - host h1 for service LO uses a specific ipv4/ipv6 address pair # - host h1 for service TRUNK uses a specific ipv4/ipv6 address pair
# - the rest use the ipv4/ipv6 network pair # - host h2 for service TRUNK uses the ipv4/ipv6 network pair
# - service LO uses nothing
# networks and hosts can be allocated with extensible attributes # networks and hosts can be allocated with extensible attributes
# - host h2 for service LO uses extattrs for both network and address/DNS # networks can be created with a comment
# - the rest don't use extattrs # CNAME records can be optionally created
hostname_A = 'h1' hostname_A = 'hA'
hostname_B = 'h2' hostname_B = 'hB'
# h1 LO (loopback) # h1 LO (loopback)
lo1_service_networks = new_service_networks( new_service_host(hostname=hostname_A+"_LO",
service_type='LO', cname_aliases=["alias1.hA", "alias2.hA"],
comment="Network for h1 LO" service_type='LO')
)
lo1_v4_host_address = lo1_service_networks.v4.network_address
lo1_v6_host_address = lo1_service_networks.v6.network_address
print(lo1_v4_host_address)
print(lo1_v6_host_address)
lo1_host_addresses = HostAddresses(v4=lo1_v4_host_address,
v6=lo1_v6_host_address)
new_service_host(hostname=hostname_A,
service_type='LO',
host_addresses=lo1_host_addresses)
# h2 LO (loopback) # h2 LO (loopback)
lo2_network_extattrs = { new_service_host(hostname=hostname_B+"_LO",
cname_aliases=["alias1.hB"],
service_type='LO')
# h1-h2 TRUNK
trunk12_network_extattrs = {
"vrf_name": {"value": "dummy_vrf"}, "vrf_name": {"value": "dummy_vrf"},
} }
lo2_host_extattrs = { trunk12_host_extattrs = {
"Site": {"value": "dummy_site"}, "Site": {"value": "dummy_site"},
} }
lo2_service_networks = \
new_service_networks(service_type='LO',
comment="Network for h2 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( trunk12_service_networks = new_service_networks(
service_type='TRUNK', service_type='TRUNK',
extattrs=trunk12_network_extattrs,
comment="Network for h1-h2 TRUNK" comment="Network for h1-h2 TRUNK"
) )
new_service_host(hostname=hostname_A,
trunk12_v4_host_address = trunk12_service_networks.v4.network_address
trunk12_v6_host_address = trunk12_service_networks.v6.network_address
trunk12_host_addresses = HostAddresses(v4=trunk12_v4_host_address,
v6=trunk12_v6_host_address)
new_service_host(hostname=hostname_A+"_TRUNK",
service_type='TRUNK', service_type='TRUNK',
service_networks=trunk12_service_networks) host_addresses=trunk12_host_addresses,
new_service_host(hostname=hostname_B, extattrs=trunk12_host_extattrs)
new_service_host(hostname=hostname_B+"_TRUNK",
service_type='TRUNK', service_type='TRUNK',
service_networks=trunk12_service_networks) service_networks=trunk12_service_networks,
''' extattrs=trunk12_host_extattrs)
...@@ -18,11 +18,13 @@ class InfoBloxParams(BaseSettings): ...@@ -18,11 +18,13 @@ class InfoBloxParams(BaseSettings):
class V4NetworkParams(BaseSettings): class V4NetworkParams(BaseSettings):
containers: list[ipaddress.IPv4Network] containers: list[ipaddress.IPv4Network]
networks: list[ipaddress.IPv4Network]
mask: int # TODO: validation on mask? mask: int # TODO: validation on mask?
class V6NetworkParams(BaseSettings): class V6NetworkParams(BaseSettings):
containers: list[ipaddress.IPv6Network] containers: list[ipaddress.IPv6Network]
networks: list[ipaddress.IPv6Network]
mask: int # TODO: validation on mask? mask: int # TODO: validation on mask?
......
...@@ -19,6 +19,7 @@ from gso.products.product_types import device ...@@ -19,6 +19,7 @@ from gso.products.product_types import device
from gso.products.product_types.device import DeviceInactive, \ from gso.products.product_types.device import DeviceInactive, \
DeviceProvisioning DeviceProvisioning
from gso.products.product_types.site import Site from gso.products.product_types.site import Site
from gso.services import _ipam
from gso.services import provisioning_proxy from gso.services import provisioning_proxy
from gso.services.provisioning_proxy import await_pp_results, \ from gso.services.provisioning_proxy import await_pp_results, \
confirm_pp_results confirm_pp_results
...@@ -84,15 +85,14 @@ def iso_from_ipv4(ipv4_address): ...@@ -84,15 +85,14 @@ def iso_from_ipv4(ipv4_address):
@step('Get information from IPAM') @step('Get information from IPAM')
def get_info_from_ipam(subscription: DeviceInactive) -> State: def get_info_from_ipam(subscription: DeviceProvisioning) -> State:
# lo = ipam.new_device_lo_address() lo0_alias = re.sub('.geant.net', '', subscription.device.device_fqdn)
# subscription.device.lo_ipv4_address = lo.v4 lo0_name = f'lo0.{lo0_alias}'
# subscription.device.lo_ipv6_address = lo.v6 lo0_addr = _ipam.allocate_service_host(hostname=lo0_name,
# TODO: get info about how these should be generated service_type='LO',
subscription.device.device_lo_ipv4_address = \ cname_aliases=[lo0_alias])
ipaddress.ip_address('10.10.10.20') subscription.device.device_lo_ipv4_address = lo0_addr.v4
subscription.device.device_lo_ipv6_address = \ subscription.device.device_lo_ipv6_address = lo0_addr.v6
ipaddress.ip_address('fc00:798:10::20')
subscription.device.device_lo_iso_address \ subscription.device.device_lo_iso_address \
= iso_from_ipv4(str(subscription.device.device_lo_ipv4_address)) = iso_from_ipv4(str(subscription.device.device_lo_ipv4_address))
subscription.device.device_si_ipv4_network = '192.168.0.0/31' subscription.device.device_si_ipv4_network = '192.168.0.0/31'
...@@ -116,19 +116,19 @@ def initialize_subscription( ...@@ -116,19 +116,19 @@ def initialize_subscription(
subscription.device.device_vendor = device_vendor subscription.device.device_vendor = device_vendor
subscription.device.device_site \ subscription.device.device_site \
= Site.from_subscription(device_site[0]).site = Site.from_subscription(device_site[0]).site
fqdn = str(hostname + '.' + fqdn = f'{hostname}.{subscription.device.device_site.site_name.lower()}.' \
subscription.device.device_site.site_name.lower() + '.' + f'{subscription.device.device_site.site_country_code.lower()}' \
subscription.device.device_site.site_country_code.lower() + f'.geant.net'
'.geant.net')
subscription.device.device_fqdn = fqdn subscription.device.device_fqdn = fqdn
subscription.device.device_role = device_role subscription.device.device_role = device_role
subscription.description = f'Device {fqdn} ' \ subscription.description = f'Device {fqdn} ' \
f'({subscription.device_type})' f'({subscription.device_type})'
subscription = device.DeviceProvisioning.from_other_lifecycle( subscription = device.DeviceProvisioning.from_other_lifecycle(
subscription, SubscriptionLifecycle.PROVISIONING subscription, SubscriptionLifecycle.PROVISIONING
) )
return {'subscription': subscription, 'fqdn': fqdn} return {'subscription': subscription}
@step('Provision device [DRY RUN]') @step('Provision device [DRY RUN]')
...@@ -158,8 +158,8 @@ def create_device(): ...@@ -158,8 +158,8 @@ def create_device():
init init
>> create_subscription >> create_subscription
>> store_process_subscription(Target.CREATE) >> store_process_subscription(Target.CREATE)
>> get_info_from_ipam
>> initialize_subscription >> initialize_subscription
>> get_info_from_ipam
>> provision_device_dry >> provision_device_dry
>> await_pp_results >> await_pp_results
>> confirm_pp_results >> confirm_pp_results
......
...@@ -2,9 +2,10 @@ import contextlib ...@@ -2,9 +2,10 @@ import contextlib
import json import json
import os import os
import socket import socket
import pytest
import tempfile import tempfile
import pytest
@pytest.fixture(scope='session') @pytest.fixture(scope='session')
def configuration_data(): def configuration_data():
...@@ -26,17 +27,21 @@ def configuration_data(): ...@@ -26,17 +27,21 @@ def configuration_data():
"password": "robot-user-password" "password": "robot-user-password"
}, },
"LO": { "LO": {
"V4": {"containers": ["10.255.255.0/24"], "mask": 32}, "V4": {"containers": ["10.255.255.0/24"], "networks": [],
"V6": {"containers": ["dead:beef::/64"], "mask": 128}, "mask": 32},
"V6": {"containers": ["dead:beef::/64"], "networks": [],
"mask": 128},
"domain_name": ".lo" "domain_name": ".lo"
}, },
"TRUNK": { "TRUNK": {
"V4": { "V4": {
"containers": ["10.255.255.0/24", "10.255.254.0/24"], "containers": ["10.255.255.0/24", "10.255.254.0/24"],
"networks": [],
"mask": 31 "mask": 31
}, },
"V6": { "V6": {
"containers": ["dead:beef::/64", "dead:beee::/64"], "containers": ["dead:beef::/64", "dead:beee::/64"],
"networks": [],
"mask": 126 "mask": 126
}, },
"domain_name": ".trunk" "domain_name": ".trunk"
...@@ -44,10 +49,12 @@ def configuration_data(): ...@@ -44,10 +49,12 @@ def configuration_data():
"GEANT_IP": { "GEANT_IP": {
"V4": { "V4": {
"containers": ["10.255.255.0/24", "10.255.254.0/24"], "containers": ["10.255.255.0/24", "10.255.254.0/24"],
"networks": [],
"mask": 31 "mask": 31
}, },
"V6": { "V6": {
"containers": ["dead:beef::/64", "dead:beee::/64"], "containers": ["dead:beef::/64", "dead:beee::/64"],
"networks": [],
"mask": 126 "mask": 126
}, },
"domain_name": ".geantip" "domain_name": ".geantip"
......
import ipaddress import ipaddress
import re import re
import responses import responses
from gso.services import ipam from gso.services import ipam
...@@ -7,12 +8,12 @@ from gso.services import ipam ...@@ -7,12 +8,12 @@ from gso.services import ipam
@responses.activate @responses.activate
def test_new_service_networks(data_config_filename): def test_new_service_networks(data_config_filename):
responses.add( responses.add(
method=responses.POST, method=responses.POST,
url=re.compile(r'.*/wapi.*/network.*'), url=re.compile(r'.*/wapi.*/network.*'),
json={ json={
'_ref': 'network/ZG5zLm5ldHdvcmskMTAuMjU1LjI1NS4yMC8zMi8w:10.255.255.20/32/default', # noqa: E501 '_ref': 'network/ZG5zLm5ldHdvcmskMTAuMjU1LjI1NS4yMC8zMi8w:10.255.2'
'55.20/32/default', # noqa: E501
'network': '10.255.255.20/32' 'network': '10.255.255.20/32'
} }
) )
...@@ -21,7 +22,8 @@ def test_new_service_networks(data_config_filename): ...@@ -21,7 +22,8 @@ def test_new_service_networks(data_config_filename):
method=responses.POST, method=responses.POST,
url=re.compile(r'.*/wapi.*/ipv6network.*'), url=re.compile(r'.*/wapi.*/ipv6network.*'),
json={ json={
'_ref': 'ipv6network/ZG5zLm5ldHdvcmskZGVhZDpiZWVmOjoxOC8xMjgvMA:dead%3Abeef%3A%3A18/128/default', # noqa: E501 '_ref': 'ipv6network/ZG5zLm5ldHdvcmskZGVhZDpiZWVmOjoxOC8xMjgvMA:de'
'ad%3Abeef%3A%3A18/128/default', # noqa: E501
'network': 'dead:beef::18/128' 'network': 'dead:beef::18/128'
} }
) )
...@@ -35,23 +37,25 @@ def test_new_service_networks(data_config_filename): ...@@ -35,23 +37,25 @@ def test_new_service_networks(data_config_filename):
@responses.activate @responses.activate
def test_new_service_host(data_config_filename): def test_new_service_host(data_config_filename):
responses.add( responses.add(
method=responses.POST, method=responses.POST,
url=re.compile(r'.*/wapi.*/record:host$'), url=re.compile(r'.*/wapi.*/record:host$'),
json='record:host/ZG5zLmhvc3QkLm5vbl9ETlNfaG9zdF9yb290LjAuMTY4MzcwNTU4MzY3MC5nc28udGVzdA:test.lo/%20' # noqa: E501 json='record:host/ZG5zLmhvc3QkLm5vbl9ETlNfaG9zdF9yb290LjAuMTY4MzcwNTU4'
'MzY3MC5nc28udGVzdA:test.lo/%20' # noqa: E501
) )
responses.add( responses.add(
method=responses.POST, method=responses.POST,
url=re.compile(r'.*/wapi.*/record:a$'), url=re.compile(r'.*/wapi.*/record:a$'),
json='record:a/ZG5zLmJpbmRfYSQuX2RlZmF1bHQuZ3NvLHRlc3QsMTAuMjU1LjI1NS44:test.lo/default' # noqa: E501 json='record:a/ZG5zLmJpbmRfYSQuX2RlZmF1bHQuZ3NvLHRlc3QsMTAuMjU1LjI1NS4'
'4:test.lo/default' # noqa: E501
) )
responses.add( responses.add(
method=responses.POST, method=responses.POST,
url=re.compile(r'.*/wapi.*/record:aaaa$'), url=re.compile(r'.*/wapi.*/record:aaaa$'),
json='record:aaaa/ZG5zLmJpbmRfYSQuX2RlZmF1bHQuZ3NvLHRlc3QsMTAuMjU1LjI1NS44:test.lo/default' # noqa: E501 json='record:aaaa/ZG5zLmJpbmRfYSQuX2RlZmF1bHQuZ3NvLHRlc3QsMTAuMjU1LjI1'
'NS44:test.lo/default' # noqa: E501
) )
responses.add( responses.add(
...@@ -59,7 +63,8 @@ def test_new_service_host(data_config_filename): ...@@ -59,7 +63,8 @@ def test_new_service_host(data_config_filename):
url=re.compile(r'.*/wapi.*/network.*'), url=re.compile(r'.*/wapi.*/network.*'),
json=[ json=[
{ {
"_ref": "network/ZG5zLm5ldHdvcmskMTAuMjU1LjI1NS4yMC8zMi8w:10.255.255.20/32/default", # noqa: E501 "_ref": "network/ZG5zLm5ldHdvcmskMTAuMjU1LjI1NS4yMC8zMi8w:10.2"
"55.255.20/32/default", # noqa: E501
"network": "10.255.255.20/32", "network": "10.255.255.20/32",
"network_view": "default" "network_view": "default"
} }
...@@ -72,7 +77,8 @@ def test_new_service_host(data_config_filename): ...@@ -72,7 +77,8 @@ def test_new_service_host(data_config_filename):
url=re.compile(r'.*/wapi.*/ipv6network.*'), url=re.compile(r'.*/wapi.*/ipv6network.*'),
json=[ json=[
{ {
"_ref": "ipv6network/ZG5zLm5ldHdvcmskZGVhZDpiZWVmOjoxOC8xMjgvMA:dead%3Abeef%3A%3A18/128/default", # noqa: E501 "_ref": "ipv6network/ZG5zLm5ldHdvcmskZGVhZDpiZWVmOjoxOC8xMjgvM"
"A:dead%3Abeef%3A%3A18/128/default", # noqa: E501
"network": "dead:beef::18/128", "network": "dead:beef::18/128",
"network_view": "default" "network_view": "default"
} }
...@@ -81,13 +87,17 @@ def test_new_service_host(data_config_filename): ...@@ -81,13 +87,17 @@ def test_new_service_host(data_config_filename):
responses.add( responses.add(
method=responses.POST, method=responses.POST,
url=re.compile(r'.*/wapi.*/network.*/.*?_function=next_available_ip&num=1.*'), # noqa: E501 url=re.compile(
r'.*/wapi.*/network.*/.*?_function=next_available_ip&num=1.*'),
# noqa: E501
json={'ips': ['10.255.255.20']} json={'ips': ['10.255.255.20']}
) )
responses.add( responses.add(
method=responses.POST, method=responses.POST,
url=re.compile(r'.*/wapi.*/ipv6network.*/.*?_function=next_available_ip&num=1.*'), # noqa: E501 url=re.compile(
r'.*/wapi.*/ipv6network.*/.*?_function=next_available_ip&num=1.*'),
# noqa: E501
json={'ips': ['dead:beef::18']} json={'ips': ['dead:beef::18']}
) )
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment