Central and local plugin (part 2, l3 functionality)
1. What is the problem Necessary changes for local plugin and central plugin to boot a virtual machine have been submitted in this patch[1]. As the next step, we need to add l3 functionality to the local and central plugin. 2. What is the solution to the problem Several changes in local plugin. (1) Before creating local subnet, local plugin sends request to central plugin to create a "reserved gateway port", and use the ip address of this port as the gateway ip of the local subnet. (2) When local plugin receives network or subnet creation request, if the request contains "name" parameter and the name is a UUID, local plugin uses the name as the id of the local network or subnet. 3. What the features need to be implemented to the Tricircle to realize the solution With this patch, users can connect virtual machines booted directly via the local Nova server in different networks with a router. [1] https://review.openstack.org/375281 Change-Id: I12094f30804c0bad2f74e0ff510ac26bd217cfd4changes/76/378476/4
parent
b0789882eb
commit
ff7f86fa01
|
@ -46,16 +46,9 @@ OVS_BRIDGE_MAPPINGS=bridge:br-bridge
|
|||
Q_ENABLE_TRICIRCLE=True
|
||||
enable_plugin tricircle https://github.com/openstack/tricircle/
|
||||
|
||||
# Tricircle Services
|
||||
enable_service t-api
|
||||
enable_service t-ngw
|
||||
enable_service t-cgw
|
||||
enable_service t-job
|
||||
|
||||
# Use Neutron instead of nova-network
|
||||
disable_service n-net
|
||||
enable_service q-svc
|
||||
enable_service q-svc1
|
||||
enable_service q-dhcp
|
||||
enable_service q-agt
|
||||
enable_service q-l3
|
||||
|
@ -68,3 +61,22 @@ disable_service n-obj
|
|||
disable_service c-bak
|
||||
disable_service tempest
|
||||
disable_service horizon
|
||||
|
||||
CENTRAL_REGION_NAME=CentralRegion
|
||||
TRICIRCLE_NEUTRON_PORT=20001
|
||||
|
||||
[[post-config|$NEUTRON_CONF]]
|
||||
|
||||
[DEFAULT]
|
||||
core_plugin=tricircle.network.local_plugin.TricirclePlugin
|
||||
|
||||
[client]
|
||||
admin_username=admin
|
||||
admin_password=$ADMIN_PASSWORD
|
||||
admin_tenant=demo
|
||||
auto_refresh_endpoint=True
|
||||
top_pod_name=$CENTRAL_REGION_NAME
|
||||
|
||||
[tricircle]
|
||||
real_core_plugin=neutron.plugins.ml2.plugin.Ml2Plugin
|
||||
central_neutron_url=http://127.0.0.1:$TRICIRCLE_NEUTRON_PORT
|
||||
|
|
|
@ -38,12 +38,11 @@ NEUTRON_CREATE_INITIAL_NETWORKS=False
|
|||
Q_USE_PROVIDERNET_FOR_PUBLIC=True
|
||||
|
||||
HOST_IP=10.250.201.25
|
||||
REGION_NAME=Pod2
|
||||
REGION_NAME=RegionTwo
|
||||
KEYSTONE_REGION_NAME=RegionOne
|
||||
SERVICE_HOST=$HOST_IP
|
||||
KEYSTONE_SERVICE_HOST=10.250.201.24
|
||||
KEYSTONE_AUTH_HOST=10.250.201.24
|
||||
GLANCE_SERVICE_HOST=10.250.201.24
|
||||
|
||||
Q_ML2_PLUGIN_VLAN_TYPE_OPTIONS=(network_vlan_ranges=bridge:2001:3000,extern:3001:4000)
|
||||
OVS_BRIDGE_MAPPINGS=bridge:br-bridge,extern:br-ext
|
||||
|
@ -60,8 +59,26 @@ enable_service c-vol
|
|||
enable_service c-sch
|
||||
|
||||
disable_service n-obj
|
||||
disable_service g-api
|
||||
disable_service g-reg
|
||||
disable_service c-bak
|
||||
disable_service tempest
|
||||
disable_service horizon
|
||||
|
||||
CENTRAL_REGION_NAME=CentralRegion
|
||||
TRICIRCLE_NEUTRON_PORT=20001
|
||||
|
||||
[[post-config|$NEUTRON_CONF]]
|
||||
|
||||
[DEFAULT]
|
||||
core_plugin=tricircle.network.local_plugin.TricirclePlugin
|
||||
|
||||
[client]
|
||||
admin_username=admin
|
||||
admin_password=$ADMIN_PASSWORD
|
||||
admin_tenant=demo
|
||||
auto_refresh_endpoint=True
|
||||
top_pod_name=$CENTRAL_REGION_NAME
|
||||
|
||||
[tricircle]
|
||||
real_core_plugin=neutron.plugins.ml2.plugin.Ml2Plugin
|
||||
# change the ip to the ip of the machine hosting central Neutron server
|
||||
central_neutron_url=http://10.250.201.24:$TRICIRCLE_NEUTRON_PORT
|
||||
|
|
|
@ -35,10 +35,6 @@ LIBVIRT_FIREWALL_DRIVER=nova.virt.firewall.NoopFirewallDriver
|
|||
Q_ENABLE_TRICIRCLE=True
|
||||
enable_plugin tricircle https://github.com/openstack/tricircle/
|
||||
|
||||
# Tricircle Services
|
||||
enable_service t-api
|
||||
enable_service t-job
|
||||
|
||||
# Use Neutron instead of nova-network
|
||||
disable_service n-net
|
||||
enable_service q-svc
|
||||
|
|
|
@ -86,7 +86,6 @@ function configure_tricircle_xjob {
|
|||
echo "Configuring Tricircle xjob"
|
||||
|
||||
init_common_tricircle_conf $TRICIRCLE_XJOB_CONF
|
||||
iniset $TRICIRCLE_XJOB_CONF DEFAULT enable_api_gateway False
|
||||
|
||||
setup_colorized_logging $TRICIRCLE_XJOB_CONF DEFAULT
|
||||
fi
|
||||
|
|
|
@ -59,6 +59,7 @@ ns_bridge_port_name = 'ns_bridge_port_%s_%s_%s'
|
|||
|
||||
dhcp_port_name = 'dhcp_port_%s' # subnet_id
|
||||
interface_port_name = 'interface_%s_%s' # b_pod_id t_subnet_id
|
||||
interface_port_device_id = 'reserved_gateway_port'
|
||||
|
||||
MAX_INT = 0x7FFFFFFF
|
||||
expire_time = datetime.datetime(2000, 1, 1)
|
||||
|
|
|
@ -18,6 +18,7 @@ import six
|
|||
import pecan
|
||||
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from tricircle.common import constants as cons
|
||||
import tricircle.common.exceptions as t_exceptions
|
||||
|
@ -126,6 +127,21 @@ def get_bottom_network_name(network):
|
|||
return '%s#%s' % (network['id'], network['name'])
|
||||
|
||||
|
||||
def get_id_from_name(_type, name):
|
||||
if _type == cons.RT_NETWORK:
|
||||
tokens = name.split('#')
|
||||
if len(tokens) == 2:
|
||||
id_candidate = tokens[1]
|
||||
else:
|
||||
id_candidate = tokens[0]
|
||||
else:
|
||||
id_candidate = name
|
||||
if uuidutils.is_uuid_like(id_candidate):
|
||||
return id_candidate
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def format_error(code, message, error_type=None):
|
||||
error_type_map = {400: 'badRequest',
|
||||
403: 'forbidden',
|
||||
|
|
|
@ -57,9 +57,8 @@ def get_pod(context, pod_id):
|
|||
|
||||
|
||||
def list_pods(context, filters=None, sorts=None):
|
||||
with context.session.begin():
|
||||
return core.query_resource(context, models.Pod, filters or [],
|
||||
sorts or [])
|
||||
return core.query_resource(context, models.Pod, filters or [],
|
||||
sorts or [])
|
||||
|
||||
|
||||
def update_pod(context, pod_id, update_dict):
|
||||
|
@ -116,9 +115,8 @@ def get_pod_service_configuration(context, config_id):
|
|||
|
||||
|
||||
def list_pod_service_configurations(context, filters=None, sorts=None):
|
||||
with context.session.begin():
|
||||
return core.query_resource(context, models.PodServiceConfiguration,
|
||||
filters or [], sorts or [])
|
||||
return core.query_resource(context, models.PodServiceConfiguration,
|
||||
filters or [], sorts or [])
|
||||
|
||||
|
||||
def update_pod_service_configuration(context, config_id, update_dict):
|
||||
|
|
|
@ -386,6 +386,19 @@ class TricirclePlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||
context, subnet_id, subnet)
|
||||
|
||||
def create_port(self, context, port):
|
||||
port_body = port['port']
|
||||
if port_body['device_id'] == t_constants.interface_port_device_id:
|
||||
_, region_name, subnet_id = port_body['name'].split('_')
|
||||
gateway_port_body = self.helper.get_create_interface_body(
|
||||
port_body['tenant_id'], port_body['network_id'], region_name,
|
||||
subnet_id)
|
||||
t_ctx = t_context.get_context_from_neutron_context(context)
|
||||
pod = db_api.get_pod_by_name(t_ctx, region_name)
|
||||
_, t_gateway_id = self.helper.prepare_top_element(
|
||||
t_ctx, context, port_body['tenant_id'], pod,
|
||||
{'id': port_body['name']}, t_constants.RT_PORT,
|
||||
gateway_port_body)
|
||||
return super(TricirclePlugin, self).get_port(context, t_gateway_id)
|
||||
db_port = super(TricirclePlugin, self).create_port_db(context, port)
|
||||
return self._make_port_dict(db_port)
|
||||
|
||||
|
@ -414,6 +427,20 @@ class TricirclePlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||
db_api.create_resource_mapping(t_ctx, resource_id, resource_id,
|
||||
pod['pod_id'], res['tenant_id'],
|
||||
resource_type)
|
||||
|
||||
interfaces = super(TricirclePlugin, self).get_ports(
|
||||
context,
|
||||
{'network_id': [res['network_id']],
|
||||
'device_owner': [constants.DEVICE_OWNER_ROUTER_INTF]})
|
||||
interfaces = [inf for inf in interfaces if inf['device_id']]
|
||||
if interfaces:
|
||||
# request may be come from service, we use an admin context
|
||||
# to run the xjob
|
||||
admin_context = t_context.get_admin_context()
|
||||
self.xjob_handler.setup_bottom_router(
|
||||
admin_context, res['network_id'],
|
||||
interfaces[0]['device_id'], pod['pod_id'])
|
||||
|
||||
return res
|
||||
|
||||
def delete_port(self, context, port_id, l3_port_check=True):
|
||||
|
|
|
@ -32,3 +32,8 @@ class BottomPodOperationFailure(exceptions.NeutronException):
|
|||
|
||||
class DhcpPortNotFound(exceptions.NotFound):
|
||||
message = _('Dhcp port for subnet %(subnet_id)s not found')
|
||||
|
||||
|
||||
class GatewayPortNotFound(exceptions.NotFound):
|
||||
message = _('Gateway port for subnet %(subnet_id)s and region %(region)s '
|
||||
'not found')
|
||||
|
|
|
@ -28,7 +28,9 @@ from tricircle.common import client # noqa
|
|||
import tricircle.common.constants as t_constants
|
||||
import tricircle.common.context as t_context
|
||||
from tricircle.common.i18n import _
|
||||
|
||||
from tricircle.common import resource_handle
|
||||
import tricircle.common.utils as t_utils
|
||||
import tricircle.network.exceptions as t_exceptions
|
||||
from tricircle.network import helper
|
||||
|
||||
|
@ -59,6 +61,18 @@ class TricirclePlugin(plugin.Ml2Plugin):
|
|||
self.neutron_handle.endpoint_url = \
|
||||
cfg.CONF.tricircle.central_neutron_url
|
||||
|
||||
def start_rpc_listeners(self):
|
||||
return self.core_plugin.start_rpc_listeners()
|
||||
|
||||
def start_rpc_state_reports_listener(self):
|
||||
return self.core_plugin.start_rpc_state_reports_listener()
|
||||
|
||||
def rpc_workers_supported(self):
|
||||
return self.core_plugin.rpc_workers_supported()
|
||||
|
||||
def rpc_state_report_workers_supported(self):
|
||||
return self.core_plugin.rpc_state_report_workers_supported()
|
||||
|
||||
@staticmethod
|
||||
def _adapt_network_body(network):
|
||||
network_type = network.get('provider:network_type')
|
||||
|
@ -147,6 +161,43 @@ class TricirclePlugin(plugin.Ml2Plugin):
|
|||
dhcp_port_body['port']['id'] = t_ports[0]['id']
|
||||
self.core_plugin.create_port(q_ctx, dhcp_port_body)
|
||||
|
||||
def _ensure_gateway_port(self, t_ctx, t_subnet):
|
||||
region_name = cfg.CONF.nova.region_name
|
||||
gateway_port_name = t_constants.interface_port_name % (region_name,
|
||||
t_subnet['id'])
|
||||
gateway_port_body = {
|
||||
'port': {'tenant_id': t_subnet['tenant_id'],
|
||||
'admin_state_up': True,
|
||||
'name': gateway_port_name,
|
||||
'network_id': t_subnet['network_id'],
|
||||
'device_id': t_constants.interface_port_device_id}}
|
||||
try:
|
||||
return self.neutron_handle.handle_create(
|
||||
t_ctx, t_constants.RT_PORT, gateway_port_body)
|
||||
except Exception:
|
||||
raw_client = self.neutron_handle._get_client(t_ctx)
|
||||
params = {'name': gateway_port_name}
|
||||
t_ports = raw_client.list_ports(**params)['ports']
|
||||
if not t_ports:
|
||||
raise t_exceptions.GatewayPortNotFound(
|
||||
subnet_id=t_subnet['id'], region=region_name)
|
||||
return t_ports[0]
|
||||
|
||||
def create_network(self, context, network):
|
||||
# this method is overwritten for bottom bridge network and external
|
||||
# network creation, for internal network, get_network and get_networks
|
||||
# will do the trick
|
||||
net_body = network['network']
|
||||
self._adapt_network_body(net_body)
|
||||
if net_body['name']:
|
||||
net_id = t_utils.get_id_from_name(t_constants.RT_NETWORK,
|
||||
net_body['name'])
|
||||
if net_id:
|
||||
net_body['id'] = net_id
|
||||
b_network = self.core_plugin.create_network(context,
|
||||
{'network': net_body})
|
||||
return b_network
|
||||
|
||||
def get_network(self, context, _id, fields=None):
|
||||
try:
|
||||
b_network = self.core_plugin.get_network(context, _id, fields)
|
||||
|
@ -174,12 +225,14 @@ class TricirclePlugin(plugin.Ml2Plugin):
|
|||
return self.core_plugin.get_networks(
|
||||
context, filters, fields, sorts, limit, marker, page_reverse)
|
||||
|
||||
b_networks = self.core_plugin.get_networks(
|
||||
context, filters, fields, sorts, limit, marker, page_reverse)
|
||||
for b_network in b_networks:
|
||||
b_full_networks = self.core_plugin.get_networks(
|
||||
context, filters, None, sorts, limit, marker, page_reverse)
|
||||
b_networks = []
|
||||
for b_network in b_full_networks:
|
||||
subnet_ids = self._ensure_subnet(context, b_network, False)
|
||||
if subnet_ids:
|
||||
b_network['subnets'] = subnet_ids
|
||||
b_networks.append(self._fields(b_network, fields))
|
||||
|
||||
if len(b_networks) == len(filters['id']):
|
||||
return b_networks
|
||||
|
@ -206,6 +259,31 @@ class TricirclePlugin(plugin.Ml2Plugin):
|
|||
b_networks.append(self._fields(b_network, fields))
|
||||
return b_networks
|
||||
|
||||
def create_subnet(self, context, subnet):
|
||||
# this method is overwritten for bottom bridge subnet and external
|
||||
# subnet creation, for internal subnet, get_subnet and get_subnets
|
||||
# will do the trick
|
||||
subnet_body = subnet['subnet']
|
||||
if subnet_body['name']:
|
||||
subnet_id = t_utils.get_id_from_name(t_constants.RT_SUBNET,
|
||||
subnet_body['name'])
|
||||
if subnet_id:
|
||||
subnet_body['id'] = subnet_id
|
||||
b_subnet = self.core_plugin.create_subnet(context,
|
||||
{'subnet': subnet_body})
|
||||
return b_subnet
|
||||
|
||||
def _create_bottom_subnet(self, t_ctx, q_ctx, t_subnet):
|
||||
gateway_port = self._ensure_gateway_port(t_ctx, t_subnet)
|
||||
subnet_body = helper.NetworkHelper.get_create_subnet_body(
|
||||
gateway_port['tenant_id'], t_subnet, t_subnet['network_id'],
|
||||
gateway_port['fixed_ips'][0]['ip_address'])['subnet']
|
||||
t_subnet['gateway_ip'] = subnet_body['gateway_ip']
|
||||
t_subnet['allocation_pools'] = subnet_body['allocation_pools']
|
||||
|
||||
b_subnet = self.core_plugin.create_subnet(q_ctx, {'subnet': t_subnet})
|
||||
return b_subnet
|
||||
|
||||
def get_subnet(self, context, _id, fields=None):
|
||||
t_ctx = t_context.get_context_from_neutron_context(context)
|
||||
try:
|
||||
|
@ -214,11 +292,9 @@ class TricirclePlugin(plugin.Ml2Plugin):
|
|||
t_subnet = self.neutron_handle.handle_get(t_ctx, 'subnet', _id)
|
||||
if not t_subnet:
|
||||
raise q_exceptions.SubnetNotFound(subnet_id=_id)
|
||||
b_subnet = self.core_plugin.create_subnet(context,
|
||||
{'subnet': t_subnet})
|
||||
b_subnet = self._create_bottom_subnet(t_ctx, context, t_subnet)
|
||||
if b_subnet['enable_dhcp']:
|
||||
self._ensure_subnet_dhcp_port(t_ctx, context, b_subnet)
|
||||
|
||||
return self._fields(b_subnet, fields)
|
||||
|
||||
def get_subnets(self, context, filters=None, fields=None, sorts=None,
|
||||
|
@ -232,10 +308,13 @@ class TricirclePlugin(plugin.Ml2Plugin):
|
|||
context, filters, fields, sorts, limit, marker, page_reverse)
|
||||
|
||||
t_ctx = t_context.get_context_from_neutron_context(context)
|
||||
b_subnets = self.core_plugin.get_subnets(
|
||||
context, filters, fields, sorts, limit, marker, page_reverse)
|
||||
for b_subnet in b_subnets:
|
||||
self._ensure_subnet_dhcp_port(t_ctx, context, b_subnet)
|
||||
b_full_subnets = self.core_plugin.get_subnets(
|
||||
context, filters, None, sorts, limit, marker, page_reverse)
|
||||
b_subnets = []
|
||||
for b_subnet in b_full_subnets:
|
||||
if b_subnet['enable_dhcp']:
|
||||
self._ensure_subnet_dhcp_port(t_ctx, context, b_subnet)
|
||||
b_subnets.append(self._fields(b_subnet, fields))
|
||||
if len(b_subnets) == len(filters['id']):
|
||||
return b_subnets
|
||||
|
||||
|
@ -251,13 +330,19 @@ class TricirclePlugin(plugin.Ml2Plugin):
|
|||
missing_subnets = [subnet for subnet in t_subnets if (
|
||||
subnet['id'] in missing_id_set)]
|
||||
for subnet in missing_subnets:
|
||||
b_subnet = self.core_plugin.create_subnet(
|
||||
context, {'subnet': subnet})
|
||||
b_subnet = self._create_bottom_subnet(t_ctx, context, subnet)
|
||||
if b_subnet['enable_dhcp']:
|
||||
self._ensure_subnet_dhcp_port(t_ctx, context, b_subnet)
|
||||
b_subnets.append(self._fields(b_subnet, fields))
|
||||
return b_subnets
|
||||
|
||||
@staticmethod
|
||||
def _is_special_port(port):
|
||||
return port.get('device_owner') in (
|
||||
q_constants.DEVICE_OWNER_ROUTER_INTF,
|
||||
q_constants.DEVICE_OWNER_FLOATINGIP,
|
||||
q_constants.DEVICE_OWNER_ROUTER_GW)
|
||||
|
||||
def create_port(self, context, port):
|
||||
port_body = port['port']
|
||||
network_id = port_body['network_id']
|
||||
|
@ -268,25 +353,34 @@ class TricirclePlugin(plugin.Ml2Plugin):
|
|||
raw_client = self.neutron_handle._get_client(t_ctx)
|
||||
|
||||
if port_body['fixed_ips'] is not q_constants.ATTR_NOT_SPECIFIED:
|
||||
fixed_ip = port_body['fixed_ips'][0]
|
||||
ip_address = fixed_ip.get('ip_address')
|
||||
if not ip_address:
|
||||
# dhcp agent may request to create a dhcp port without
|
||||
# specifying ip address, we just raise an exception to reject
|
||||
# this request
|
||||
raise q_exceptions.InvalidIpForNetwork(ip_address='None')
|
||||
params = {'fixed_ips': 'ip_address=%s' % ip_address}
|
||||
t_ports = raw_client.list_ports(**params)['ports']
|
||||
if not t_ports:
|
||||
raise q_exceptions.InvalidIpForNetwork(
|
||||
ip_address=fixed_ip['ip_address'])
|
||||
t_port = t_ports[0]
|
||||
if not self._is_special_port(port_body):
|
||||
fixed_ip = port_body['fixed_ips'][0]
|
||||
ip_address = fixed_ip.get('ip_address')
|
||||
if not ip_address:
|
||||
# dhcp agent may request to create a dhcp port without
|
||||
# specifying ip address, we just raise an exception to
|
||||
# reject this request
|
||||
raise q_exceptions.InvalidIpForNetwork(ip_address='None')
|
||||
params = {'fixed_ips': 'ip_address=%s' % ip_address}
|
||||
t_ports = raw_client.list_ports(**params)['ports']
|
||||
if not t_ports:
|
||||
raise q_exceptions.InvalidIpForNetwork(
|
||||
ip_address=fixed_ip['ip_address'])
|
||||
t_port = t_ports[0]
|
||||
else:
|
||||
t_port = port_body
|
||||
else:
|
||||
self._adapt_port_body_for_client(port['port'])
|
||||
t_port = raw_client.create_port(port)['port']
|
||||
subnet_id = t_port['fixed_ips'][0]['subnet_id']
|
||||
# get_subnet will create bottom subnet if it doesn't exist
|
||||
self.get_subnet(context, subnet_id)
|
||||
|
||||
if not self._is_special_port(port_body):
|
||||
subnet_id = t_port['fixed_ips'][0]['subnet_id']
|
||||
# get_subnet will create bottom subnet if it doesn't exist
|
||||
self.get_subnet(context, subnet_id)
|
||||
|
||||
for field in ('name', 'device_id'):
|
||||
if port_body.get(field):
|
||||
t_port[field] = port_body[field]
|
||||
b_port = self.core_plugin.create_port(context, {'port': t_port})
|
||||
return b_port
|
||||
|
||||
|
|
|
@ -1020,9 +1020,11 @@ class PluginTest(unittest.TestCase,
|
|||
core.initialize()
|
||||
core.ModelBase.metadata.create_all(core.get_engine())
|
||||
cfg.CONF.register_opts(q_config.core_opts)
|
||||
cfg.CONF.register_opts(plugin.tricircle_opts)
|
||||
plugin_path = \
|
||||
'tricircle.tests.unit.network.test_central_plugin.FakePlugin'
|
||||
cfg.CONF.set_override('core_plugin', plugin_path)
|
||||
cfg.CONF.set_override('enable_api_gateway', True)
|
||||
self.context = context.Context()
|
||||
self.save_method = manager.NeutronManager._get_default_service_plugins
|
||||
manager.NeutronManager._get_default_service_plugins = mock.Mock()
|
||||
|
@ -2110,16 +2112,16 @@ class PluginTest(unittest.TestCase,
|
|||
b_bridge_net_id = db_api.get_bottom_id_by_top_id_pod_name(
|
||||
t_ctx, net['id'], 'pod_1', constants.RT_NETWORK)
|
||||
calls = [mock.call(t_ctx,
|
||||
{'floatingip': {
|
||||
'floating_network_id': b_bridge_net_id,
|
||||
'floating_ip_address': '100.128.0.3',
|
||||
'port_id': b_port_id}}),
|
||||
mock.call(t_ctx,
|
||||
{'floatingip': {
|
||||
'floating_network_id': b_ext_net_id,
|
||||
'floating_ip_address': fip[
|
||||
'floating_ip_address'],
|
||||
'port_id': ns_bridge_port['id']}}),
|
||||
mock.call(t_ctx,
|
||||
{'floatingip': {
|
||||
'floating_network_id': b_bridge_net_id,
|
||||
'floating_ip_address': '100.128.0.3',
|
||||
'port_id': b_port_id}})]
|
||||
'port_id': ns_bridge_port['id']}})]
|
||||
mock_create.assert_has_calls(calls)
|
||||
|
||||
@patch.object(driver.Pool, 'get_instance', new=fake_get_instance)
|
||||
|
|
|
@ -19,6 +19,7 @@ from mock import patch
|
|||
import six
|
||||
import unittest
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
import neutron_lib.constants as q_constants
|
||||
|
@ -106,6 +107,9 @@ class FakeCorePlugin(object):
|
|||
create_resource('port', False, port['port'])
|
||||
return port['port']
|
||||
|
||||
def update_port(self, context, _id, port):
|
||||
pass
|
||||
|
||||
def get_port(self, context, _id, fields=None):
|
||||
return get_resource('port', False, _id)
|
||||
|
||||
|
@ -180,6 +184,15 @@ class FakeNeutronHandle(object):
|
|||
def handle_get(self, context, _type, _id):
|
||||
return get_resource(_type, True, _id)
|
||||
|
||||
def handle_create(self, context, _type, body):
|
||||
if _type == 'port':
|
||||
return FakeClient().create_port(body)['port']
|
||||
create_resource(_type, True, body[_type])
|
||||
return body[_type]
|
||||
|
||||
def handle_update(self, context, _type, _id, body):
|
||||
pass
|
||||
|
||||
|
||||
class FakePlugin(plugin.TricirclePlugin):
|
||||
def __init__(self):
|
||||
|
@ -207,6 +220,9 @@ class PluginTest(unittest.TestCase):
|
|||
'name': 'subnet1',
|
||||
'network_id': network_id,
|
||||
'cidr': '10.0.1.0/24',
|
||||
'ip_version': 4,
|
||||
'allocation_pools': [{'start': '10.0.1.2',
|
||||
'end': '10.0.1.254'}],
|
||||
'enable_dhcp': True}
|
||||
t_port = {'id': port_id,
|
||||
'tenant_id': self.tenant_id,
|
||||
|
@ -232,10 +248,26 @@ class PluginTest(unittest.TestCase):
|
|||
b_port = get_resource('port', False, port['id'])
|
||||
b_net.pop('project_id')
|
||||
b_subnet.pop('project_id')
|
||||
pool = subnet.pop('allocation_pools')[0]
|
||||
b_pools = b_subnet.pop('allocation_pools')
|
||||
b_gateway_ip = b_subnet.pop('gateway_ip')
|
||||
|
||||
def ip_to_digit(ip):
|
||||
return int(ip[ip.rindex('.') + 1:])
|
||||
|
||||
pool_range = range(ip_to_digit(pool['start']),
|
||||
ip_to_digit(pool['end']) + 1)
|
||||
b_pool_range1 = range(ip_to_digit(b_pools[0]['start']),
|
||||
ip_to_digit(b_pools[0]['end']) + 1)
|
||||
b_pool_range2 = range(ip_to_digit(b_pools[1]['start']),
|
||||
ip_to_digit(b_pools[1]['end']) + 1)
|
||||
b_pool_range = b_pool_range1 + [
|
||||
ip_to_digit(b_gateway_ip)] + b_pool_range2
|
||||
port.pop('name')
|
||||
b_port.pop('name')
|
||||
self.assertDictEqual(net, b_net)
|
||||
self.assertDictEqual(subnet, b_subnet)
|
||||
self.assertEqual(pool_range, b_pool_range)
|
||||
self.assertEqual('vlan', b_net_type)
|
||||
self.assertDictEqual(port, b_port)
|
||||
|
||||
|
@ -329,6 +361,19 @@ class PluginTest(unittest.TestCase):
|
|||
b_port.pop('project_id')
|
||||
self.assertDictEqual(t_ports[i], b_port)
|
||||
|
||||
@patch.object(t_context, 'get_context_from_neutron_context')
|
||||
@patch.object(FakeNeutronHandle, 'handle_update')
|
||||
def test_update_port(self, mock_update, mock_context):
|
||||
cfg.CONF.set_override('region_name', 'Pod1', 'nova')
|
||||
mock_context.return_value = self.context
|
||||
update_body = {'port': {'device_owner': 'compute:None',
|
||||
'binding:host_id': 'fake_host'}}
|
||||
port_id = 'fake_port_id'
|
||||
self.plugin.update_port(self.context, port_id, update_body)
|
||||
mock_update.assert_called_once_with(
|
||||
self.context, 'port', port_id,
|
||||
{'port': {'binding:profile': {'region': 'Pod1'}}})
|
||||
|
||||
def tearDown(self):
|
||||
for res in RES_LIST:
|
||||
del res[:]
|
||||
|
|
|
@ -385,9 +385,13 @@ class XManager(PeriodicTasks):
|
|||
t_subnet_id = t_port['fixed_ips'][0]['subnet_id']
|
||||
t_subnet = t_client.get_subnets(ctx, t_subnet_id)
|
||||
|
||||
(b_net_id,
|
||||
subnet_map) = self.helper.prepare_bottom_network_subnets(
|
||||
ctx, q_ctx, project_id, b_pod, t_net, [t_subnet])
|
||||
if CONF.enable_api_gateway:
|
||||
(b_net_id,
|
||||
subnet_map) = self.helper.prepare_bottom_network_subnets(
|
||||
ctx, q_ctx, project_id, b_pod, t_net, [t_subnet])
|
||||
else:
|
||||
(b_net_id,
|
||||
subnet_map) = (t_net['id'], {t_subnet['id']: t_subnet['id']})
|
||||
|
||||
# the gateway ip of bottom subnet is set to the ip of t_port, so
|
||||
# we just attach the bottom subnet to the bottom router and neutron
|
||||
|
@ -456,13 +460,14 @@ class XManager(PeriodicTasks):
|
|||
_, b_ns_bridge_port_id = self.helper.prepare_bottom_element(
|
||||
ctx, project_id, b_ext_pod, t_ns_bridge_port,
|
||||
constants.RT_PORT, port_body)
|
||||
self._safe_create_bottom_floatingip(
|
||||
ctx, b_ext_pod, b_ext_client, b_ext_net_id, add_fip,
|
||||
b_ns_bridge_port_id)
|
||||
# swap these two lines
|
||||
self._safe_create_bottom_floatingip(
|
||||
ctx, b_pod, b_client, b_ns_bridge_net_id,
|
||||
t_ns_bridge_port['fixed_ips'][0]['ip_address'],
|
||||
b_int_port_id)
|
||||
self._safe_create_bottom_floatingip(
|
||||
ctx, b_ext_pod, b_ext_client, b_ext_net_id, add_fip,
|
||||
b_ns_bridge_port_id)
|
||||
else:
|
||||
self._safe_create_bottom_floatingip(
|
||||
ctx, b_pod, b_client, b_ext_net_id, add_fip,
|
||||
|
|
|
@ -55,7 +55,10 @@ common_opts = [
|
|||
help=_("Running job is considered expires after this time, in"
|
||||
" seconds")),
|
||||
cfg.FloatOpt('worker_sleep_time', default=0.1,
|
||||
help=_("Seconds a worker sleeps after one run in a loop"))
|
||||
help=_("Seconds a worker sleeps after one run in a loop")),
|
||||
cfg.BoolOpt('enable_api_gateway',
|
||||
default=False,
|
||||
help=_('Whether the Nova API gateway is enabled'))
|
||||
]
|
||||
|
||||
service_opts = [
|
||||
|
|
Loading…
Reference in New Issue