From ff7f86fa0153e365ab30fa2dd700cd2d2d2de170 Mon Sep 17 00:00:00 2001 From: zhiyuan_cai Date: Mon, 19 Sep 2016 16:57:25 +0800 Subject: [PATCH] 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: I12094f30804c0bad2f74e0ff510ac26bd217cfd4 --- devstack/local.conf.node_1.sample | 26 ++- devstack/local.conf.node_2.sample | 25 ++- devstack/local.conf.sample | 4 - devstack/plugin.sh | 1 - tricircle/common/constants.py | 1 + tricircle/common/utils.py | 16 ++ tricircle/db/api.py | 10 +- tricircle/network/central_plugin.py | 27 ++++ tricircle/network/exceptions.py | 5 + tricircle/network/local_plugin.py | 150 ++++++++++++++---- .../tests/unit/network/test_central_plugin.py | 14 +- .../tests/unit/network/test_local_plugin.py | 45 ++++++ tricircle/xjob/xmanager.py | 17 +- tricircle/xjob/xservice.py | 5 +- 14 files changed, 283 insertions(+), 63 deletions(-) diff --git a/devstack/local.conf.node_1.sample b/devstack/local.conf.node_1.sample index d32ba9f0..26c54ba3 100644 --- a/devstack/local.conf.node_1.sample +++ b/devstack/local.conf.node_1.sample @@ -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 diff --git a/devstack/local.conf.node_2.sample b/devstack/local.conf.node_2.sample index 5437630c..83a99a63 100644 --- a/devstack/local.conf.node_2.sample +++ b/devstack/local.conf.node_2.sample @@ -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 diff --git a/devstack/local.conf.sample b/devstack/local.conf.sample index 4e439fb2..b05e1b21 100644 --- a/devstack/local.conf.sample +++ b/devstack/local.conf.sample @@ -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 diff --git a/devstack/plugin.sh b/devstack/plugin.sh index 22c335a5..45e7016a 100644 --- a/devstack/plugin.sh +++ b/devstack/plugin.sh @@ -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 diff --git a/tricircle/common/constants.py b/tricircle/common/constants.py index 65330d69..d2333c29 100644 --- a/tricircle/common/constants.py +++ b/tricircle/common/constants.py @@ -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) diff --git a/tricircle/common/utils.py b/tricircle/common/utils.py index 7315c8e4..ca310500 100644 --- a/tricircle/common/utils.py +++ b/tricircle/common/utils.py @@ -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', diff --git a/tricircle/db/api.py b/tricircle/db/api.py index e78d8f12..22772bc6 100644 --- a/tricircle/db/api.py +++ b/tricircle/db/api.py @@ -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): diff --git a/tricircle/network/central_plugin.py b/tricircle/network/central_plugin.py index deb2d491..11f117a7 100644 --- a/tricircle/network/central_plugin.py +++ b/tricircle/network/central_plugin.py @@ -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): diff --git a/tricircle/network/exceptions.py b/tricircle/network/exceptions.py index 1122b700..6d0417f0 100644 --- a/tricircle/network/exceptions.py +++ b/tricircle/network/exceptions.py @@ -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') diff --git a/tricircle/network/local_plugin.py b/tricircle/network/local_plugin.py index 1fc3ca20..a7f35f22 100644 --- a/tricircle/network/local_plugin.py +++ b/tricircle/network/local_plugin.py @@ -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 diff --git a/tricircle/tests/unit/network/test_central_plugin.py b/tricircle/tests/unit/network/test_central_plugin.py index 2ddedbf2..f7e6e783 100644 --- a/tricircle/tests/unit/network/test_central_plugin.py +++ b/tricircle/tests/unit/network/test_central_plugin.py @@ -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) diff --git a/tricircle/tests/unit/network/test_local_plugin.py b/tricircle/tests/unit/network/test_local_plugin.py index 4bfe10fd..df24c8c1 100644 --- a/tricircle/tests/unit/network/test_local_plugin.py +++ b/tricircle/tests/unit/network/test_local_plugin.py @@ -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[:] diff --git a/tricircle/xjob/xmanager.py b/tricircle/xjob/xmanager.py index 9148eb95..f7c443fe 100644 --- a/tricircle/xjob/xmanager.py +++ b/tricircle/xjob/xmanager.py @@ -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, diff --git a/tricircle/xjob/xservice.py b/tricircle/xjob/xservice.py index dc1a39d1..39f15167 100644 --- a/tricircle/xjob/xservice.py +++ b/tricircle/xjob/xservice.py @@ -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 = [