Support to check if subnet is associated with router

Change-Id: I8041fbfdb01a7a1efa721c623ab3f43efd2cc0f0
This commit is contained in:
Lingxian Kong 2020-08-23 08:32:59 +12:00
parent 1113980613
commit 8daade000c
5 changed files with 54 additions and 10 deletions

View File

@ -0,0 +1,7 @@
---
features:
- Added a config option ``enable_access_check`` (default True) to decide if
Trove should check the subnet of the user port is associated with a Neutron
router. This check is needed for creating public-facing instances and the
instance initialization. This check could be skipped When using Neutron
provider network.

View File

@ -1396,7 +1396,14 @@ network_opts = [
help='ID of the Neutron public network to create floating IP for the '
'public trove instance. If not given, Trove will try to query '
'all the public networks and use the first one in the list.'
)
),
cfg.BoolOpt(
'enable_access_check', default=True,
help='Check if the user provided network is associated with router. '
'This is needed for the instance initialization. The check is '
'also necessary when creating public facing instance. A scenario '
'to set this option False is when using Neutron provider '
'network.')
]
service_credentials_group = cfg.OptGroup(

View File

@ -54,8 +54,21 @@ def reset_management_networks():
MGMT_NETWORKS = None
def check_subnet_router(client, subnet_id):
"""Check if the subnet is associated with a router."""
router_ports = client.list_ports(
device_owner="network:router_interface",
fixed_ips=f"subnet_id={subnet_id}")["ports"]
if not router_ports:
raise exception.TroveError(f"Subnet {subnet_id} is not "
f"associated with router.")
def create_port(client, name, description, network_id, security_groups,
is_public=False, subnet_id=None, ip=None):
is_public=False, subnet_id=None, ip=None, is_mgmt=False):
enable_access_check = (not is_mgmt and
(CONF.network.enable_access_check or is_public))
port_body = {
"port": {
"name": name,
@ -66,6 +79,9 @@ def create_port(client, name, description, network_id, security_groups,
}
if subnet_id:
if enable_access_check:
check_subnet_router(client, subnet_id)
fixed_ips = {
"fixed_ips": [{"subnet_id": subnet_id}]
}
@ -76,6 +92,11 @@ def create_port(client, name, description, network_id, security_groups,
port = client.create_port(body=port_body)
port_id = port['port']['id']
if not subnet_id and enable_access_check:
# Check if the subnet has been associated with a router.
subnet_id = port['port']['fixed_ips'][0]['subnet_id']
check_subnet_router(client, subnet_id)
if is_public:
make_port_public(client, port_id)

View File

@ -471,15 +471,15 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
security_groups,
is_public=is_public,
subnet_id=network_info.get('subnet_id'),
ip=network_info.get('ip_address')
ip=network_info.get('ip_address'),
is_mgmt=is_mgmt
)
except Exception:
error = ("Failed to create %s port for instance %s"
% (type, self.id))
LOG.exception(error)
except Exception as e:
self.update_db(
task_status=inst_models.InstanceTasks.BUILDING_ERROR_PORT
)
error = (f"Failed to create {type} port for instance {self.id}: "
f"{str(e)}")
raise TroveError(message=error)
return port_id
@ -518,7 +518,7 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
port_id = self._create_port(
{'network_id': CONF.management_networks[-1]},
port_sgs,
is_mgmt=True
is_mgmt=True,
)
LOG.info("Management port %s created for instance: %s", port_id,
self.id)
@ -533,7 +533,7 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
network_info,
port_sgs,
is_mgmt=False,
is_public=access.get('is_public', False)
is_public=access.get('is_public', False),
)
LOG.info("User port %s created for instance %s", port_id,
self.id)

View File

@ -417,12 +417,21 @@ class FreshInstanceTasksTest(BaseFreshInstanceTasksTest):
}
mock_client.create_port.side_effect = [
{'port': {'id': 'fake-mgmt-port-id'}},
{'port': {'id': 'fake-user-port-id'}}
{
'port': {
'id': 'fake-user-port-id',
'fixed_ips': [{'subnet_id': 'fake-subnet-id'}]
}
}
]
mock_client.list_networks.return_value = {
'networks': [{'id': 'fake-public-net-id'}]
}
mock_client.list_ports.return_value = {
'ports': [{'id': 'fake-port-id'}]
}
mock_neutron_client.return_value = mock_client
mock_flavor = {'id': 8, 'ram': 768, 'name': 'bigger_flavor'}
config_content = {'config_contents': 'some junk'}
mock_single_instance_template.return_value.config_contents = (