diff --git a/tobiko/openstack/neutron/_floating_ip.py b/tobiko/openstack/neutron/_floating_ip.py index 12d720d69..438f0c7ef 100644 --- a/tobiko/openstack/neutron/_floating_ip.py +++ b/tobiko/openstack/neutron/_floating_ip.py @@ -130,9 +130,8 @@ def ensure_floating_ip(fixed_ip_address: str, return find_floating_ip(port=port) except tobiko.ObjectNotFound: from tobiko.openstack import stacks - subnet = tobiko.select(port['fixed_ips']).with_attributes( - ip_address=fixed_ip_address).unique['subnet_id'] - _router.ensure_router_interface(subnet=subnet) + for fixed_ip in port['fixed_ips']: + _router.ensure_router_interface(subnet=fixed_ip['subnet_id']) fixture = stacks.FloatingIpStackFixture(port=port) return tobiko.setup_fixture(fixture).floating_ip_details diff --git a/tobiko/openstack/neutron/_router.py b/tobiko/openstack/neutron/_router.py index 19036867d..036b3e3ae 100644 --- a/tobiko/openstack/neutron/_router.py +++ b/tobiko/openstack/neutron/_router.py @@ -187,19 +187,28 @@ def ensure_router_interface(subnet: _subnet.SubnetIdType, client: _client.NeutronClientType = None): if isinstance(subnet, str): subnet = _subnet.get_subnet(subnet=subnet, client=client) - if 'gateway_ip' not in subnet: - if router is None: - from tobiko.openstack import stacks - router = stacks.get_router_id() - LOG.debug("Add router interface: subnet={subnet['id']}") - interface = add_router_interface(router=router, - subnet=subnet, - add_cleanup=False, - client=client) - interface_dump = json.dumps(interface, sort_keys=True, indent=4) - LOG.info(f"Added router interface:\n{interface_dump}") - subnet = _subnet.get_subnet(subnet=subnet, client=client) - assert subnet['gateway_ip'] + gateway_ip = subnet.get('gateway_ip') + if gateway_ip is not None: + try: + gateway_port = _port.find_port(fixed_ip=f'ip_address={gateway_ip}') + except _port.NoSuchPort: + pass + else: + if gateway_port['device_owner'] == 'network:router_interface': + return + + if router is None: + from tobiko.openstack import stacks + router = stacks.get_router_id() + LOG.debug("Add router interface: subnet={subnet['id']}") + interface = add_router_interface(router=router, + subnet=subnet, + add_cleanup=False, + client=client) + interface_dump = json.dumps(interface, sort_keys=True, indent=4) + LOG.info(f"Added router interface:\n{interface_dump}") + subnet = _subnet.get_subnet(subnet=subnet, client=client) + assert subnet['gateway_ip'] class NoSuchRouter(tobiko.ObjectNotFound): diff --git a/tobiko/openstack/neutron/_subnet.py b/tobiko/openstack/neutron/_subnet.py index 09adc2a03..a7af828c8 100644 --- a/tobiko/openstack/neutron/_subnet.py +++ b/tobiko/openstack/neutron/_subnet.py @@ -113,5 +113,16 @@ def find_subnet(client: _client.NeutronClientType = None, return default +def update_subnet(subnet: SubnetIdType, + client: _client.NeutronClientType = None, + **params) -> SubnetType: + subnet_id = get_subnet_id(subnet) + try: + return _client.neutron_client(client).update_subnet( + subnet_id, body={'subnet': params})['subnet'] + except _client.NotFound as ex: + raise NoSuchSubnet(id=subnet_id) from ex + + class NoSuchSubnet(tobiko.ObjectNotFound): message = "No such subnet found for {id!r}" diff --git a/tobiko/openstack/stacks/neutron/floating_ip.yaml b/tobiko/openstack/stacks/neutron/floating_ip.yaml index a21b2c333..4cb564d5e 100644 --- a/tobiko/openstack/stacks/neutron/floating_ip.yaml +++ b/tobiko/openstack/stacks/neutron/floating_ip.yaml @@ -25,12 +25,12 @@ parameters: resources: _network: - type: OS::Neutron::Network - external_id: network + type: OS::Neutron::Net + external_id: {get_param: network} _port: type: OS::Neutron::Port - external_id: port + external_id: {get_param: port} _floating_ip: type: OS::Neutron::FloatingIP @@ -55,3 +55,7 @@ outputs: port_id: value: {get_resource: _port} + + floating_ip_id: + description: floating IP identifier + value: { get_resource: _floating_ip }