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 @@
"password": "robot-user-password"
},
"LO": {
"V4": {"containers": ["1.1.0.0/24"], "mask": 32},
"V6": {"containers": ["dead:beef::/64"], "mask": 128},
"V4": {"containers": ["1.1.0.0/24"], "networks": [], "mask": 32},
"V6": {"containers": ["dead:beef::/64"], "networks": [], "mask": 128},
"domain_name": ".lo"
},
"TRUNK": {
"V4": {"containers": ["1.1.1.0/24"], "mask": 31},
"V6": {"containers": ["dead:beef::/64"], "mask": 126},
"V4": {"containers": ["1.1.1.0/24"], "networks": [], "mask": 31},
"V6": {"containers": ["dead:beef::/64"], "networks": [], "mask": 126},
"domain_name": ".trunk"
},
"GEANT_IP": {
"V4": {"containers": ["1.1.2.0/24"], "mask": 31},
"V6": {"containers": ["dead:beef::/64"], "mask": 126},
"V4": {"containers": ["1.1.2.0/24"], "networks": [], "mask": 31},
"V6": {"containers": ["dead:beef::/64"], "networks": [], "mask": 126},
"domain_name": ".geantip"
}
},
......
This diff is collapsed.
......@@ -46,68 +46,64 @@ def new_service_host(hostname,
service_type,
service_networks: ServiceNetworks = None,
host_addresses: HostAddresses = None,
cname_aliases=None,
extattrs={}) -> HostAddresses:
return _ipam.allocate_service_host(
hostname=hostname,
service_type=service_type,
service_networks=service_networks,
host_addresses=host_addresses,
cname_aliases=cname_aliases,
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
# - host h1 for service LO uses a specific ipv4/ipv6 address pair
# - the rest use the ipv4/ipv6 network pair
# new_service_host can be called passing networks, addresses, or nothing.
# - host h1 for service TRUNK uses a specific ipv4/ipv6 address 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
# - host h2 for service LO uses extattrs for both network and address/DNS
# - the rest don't use extattrs
# networks can be created with a comment
# CNAME records can be optionally created
hostname_A = 'h1'
hostname_B = 'h2'
hostname_A = 'hA'
hostname_B = 'hB'
# h1 LO (loopback)
lo1_service_networks = new_service_networks(
service_type='LO',
comment="Network for h1 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)
new_service_host(hostname=hostname_A+"_LO",
cname_aliases=["alias1.hA", "alias2.hA"],
service_type='LO')
# 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"},
}
lo2_host_extattrs = {
trunk12_host_extattrs = {
"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(
service_type='TRUNK',
extattrs=trunk12_network_extattrs,
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_networks=trunk12_service_networks)
new_service_host(hostname=hostname_B,
host_addresses=trunk12_host_addresses,
extattrs=trunk12_host_extattrs)
new_service_host(hostname=hostname_B+"_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):
class V4NetworkParams(BaseSettings):
containers: list[ipaddress.IPv4Network]
networks: list[ipaddress.IPv4Network]
mask: int # TODO: validation on mask?
class V6NetworkParams(BaseSettings):
containers: list[ipaddress.IPv6Network]
networks: list[ipaddress.IPv6Network]
mask: int # TODO: validation on mask?
......
......@@ -19,6 +19,7 @@ from gso.products.product_types import device
from gso.products.product_types.device import DeviceInactive, \
DeviceProvisioning
from gso.products.product_types.site import Site
from gso.services import _ipam
from gso.services import provisioning_proxy
from gso.services.provisioning_proxy import await_pp_results, \
confirm_pp_results
......@@ -84,15 +85,14 @@ def iso_from_ipv4(ipv4_address):
@step('Get information from IPAM')
def get_info_from_ipam(subscription: DeviceInactive) -> State:
# lo = ipam.new_device_lo_address()
# subscription.device.lo_ipv4_address = lo.v4
# subscription.device.lo_ipv6_address = lo.v6
# TODO: get info about how these should be generated
subscription.device.device_lo_ipv4_address = \
ipaddress.ip_address('10.10.10.20')
subscription.device.device_lo_ipv6_address = \
ipaddress.ip_address('fc00:798:10::20')
def get_info_from_ipam(subscription: DeviceProvisioning) -> State:
lo0_alias = re.sub('.geant.net', '', subscription.device.device_fqdn)
lo0_name = f'lo0.{lo0_alias}'
lo0_addr = _ipam.allocate_service_host(hostname=lo0_name,
service_type='LO',
cname_aliases=[lo0_alias])
subscription.device.device_lo_ipv4_address = lo0_addr.v4
subscription.device.device_lo_ipv6_address = lo0_addr.v6
subscription.device.device_lo_iso_address \
= iso_from_ipv4(str(subscription.device.device_lo_ipv4_address))
subscription.device.device_si_ipv4_network = '192.168.0.0/31'
......@@ -116,19 +116,19 @@ def initialize_subscription(
subscription.device.device_vendor = device_vendor
subscription.device.device_site \
= Site.from_subscription(device_site[0]).site
fqdn = str(hostname + '.' +
subscription.device.device_site.site_name.lower() + '.' +
subscription.device.device_site.site_country_code.lower() +
'.geant.net')
fqdn = f'{hostname}.{subscription.device.device_site.site_name.lower()}.' \
f'{subscription.device.device_site.site_country_code.lower()}' \
f'.geant.net'
subscription.device.device_fqdn = fqdn
subscription.device.device_role = device_role
subscription.description = f'Device {fqdn} ' \
f'({subscription.device_type})'
subscription = device.DeviceProvisioning.from_other_lifecycle(
subscription, SubscriptionLifecycle.PROVISIONING
)
return {'subscription': subscription, 'fqdn': fqdn}
return {'subscription': subscription}
@step('Provision device [DRY RUN]')
......@@ -158,8 +158,8 @@ def create_device():
init
>> create_subscription
>> store_process_subscription(Target.CREATE)
>> get_info_from_ipam
>> initialize_subscription
>> get_info_from_ipam
>> provision_device_dry
>> await_pp_results
>> confirm_pp_results
......
......@@ -2,9 +2,10 @@ import contextlib
import json
import os
import socket
import pytest
import tempfile
import pytest
@pytest.fixture(scope='session')
def configuration_data():
......@@ -26,17 +27,21 @@ def configuration_data():
"password": "robot-user-password"
},
"LO": {
"V4": {"containers": ["10.255.255.0/24"], "mask": 32},
"V6": {"containers": ["dead:beef::/64"], "mask": 128},
"V4": {"containers": ["10.255.255.0/24"], "networks": [],
"mask": 32},
"V6": {"containers": ["dead:beef::/64"], "networks": [],
"mask": 128},
"domain_name": ".lo"
},
"TRUNK": {
"V4": {
"containers": ["10.255.255.0/24", "10.255.254.0/24"],
"networks": [],
"mask": 31
},
"V6": {
"containers": ["dead:beef::/64", "dead:beee::/64"],
"networks": [],
"mask": 126
},
"domain_name": ".trunk"
......@@ -44,10 +49,12 @@ def configuration_data():
"GEANT_IP": {
"V4": {
"containers": ["10.255.255.0/24", "10.255.254.0/24"],
"networks": [],
"mask": 31
},
"V6": {
"containers": ["dead:beef::/64", "dead:beee::/64"],
"networks": [],
"mask": 126
},
"domain_name": ".geantip"
......
import ipaddress
import re
import responses
from gso.services import ipam
......@@ -7,12 +8,12 @@ from gso.services import ipam
@responses.activate
def test_new_service_networks(data_config_filename):
responses.add(
method=responses.POST,
url=re.compile(r'.*/wapi.*/network.*'),
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'
}
)
......@@ -21,7 +22,8 @@ def test_new_service_networks(data_config_filename):
method=responses.POST,
url=re.compile(r'.*/wapi.*/ipv6network.*'),
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'
}
)
......@@ -35,23 +37,25 @@ def test_new_service_networks(data_config_filename):
@responses.activate
def test_new_service_host(data_config_filename):
responses.add(
method=responses.POST,
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(
method=responses.POST,
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(
method=responses.POST,
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(
......@@ -59,7 +63,8 @@ def test_new_service_host(data_config_filename):
url=re.compile(r'.*/wapi.*/network.*'),
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_view": "default"
}
......@@ -72,7 +77,8 @@ def test_new_service_host(data_config_filename):
url=re.compile(r'.*/wapi.*/ipv6network.*'),
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_view": "default"
}
......@@ -81,13 +87,17 @@ def test_new_service_host(data_config_filename):
responses.add(
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']}
)
responses.add(
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']}
)
......
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