diff options
-rw-r--r-- | neutron/agent/dhcp_agent.py | 12 | ||||
-rw-r--r-- | neutron/context.py | 2 | ||||
-rw-r--r-- | neutron/db/migration/__init__.py | 34 | ||||
-rw-r--r-- | neutron/db/migration/alembic_migrations/versions/31d7f831a591_add_constraint_for_routerid.py | 115 | ||||
-rw-r--r-- | neutron/db/securitygroups_db.py | 6 | ||||
-rw-r--r-- | neutron/extensions/securitygroup.py | 5 | ||||
-rw-r--r-- | neutron/plugins/cisco/db/n1kv_db_v2.py | 22 | ||||
-rwxr-xr-x | neutron/plugins/linuxbridge/agent/linuxbridge_neutron_agent.py | 3 | ||||
-rw-r--r-- | neutron/tests/unit/cisco/n1kv/test_n1kv_plugin.py | 25 | ||||
-rw-r--r-- | neutron/tests/unit/test_api_v2_resource.py | 10 | ||||
-rw-r--r-- | neutron/tests/unit/test_dhcp_agent.py | 27 | ||||
-rw-r--r-- | neutron/tests/unit/test_extension_security_group.py | 3 |
12 files changed, 154 insertions, 110 deletions
diff --git a/neutron/agent/dhcp_agent.py b/neutron/agent/dhcp_agent.py index c8ea89b021..c174367cbc 100644 --- a/neutron/agent/dhcp_agent.py +++ b/neutron/agent/dhcp_agent.py @@ -225,17 +225,21 @@ class DhcpAgent(manager.Manager): enable_metadata = self.dhcp_driver_cls.should_enable_metadata( self.conf, network) + dhcp_network_enabled = False for subnet in network.subnets: if subnet.enable_dhcp: if self.call_driver('enable', network): - if (subnet.ip_version == 4 and self.conf.use_namespaces - and enable_metadata): - self.enable_isolated_metadata_proxy(network) - enable_metadata = False # Don't trigger twice + dhcp_network_enabled = True self.cache.put(network) break + if enable_metadata and dhcp_network_enabled: + for subnet in network.subnets: + if subnet.ip_version == 4 and subnet.enable_dhcp: + self.enable_isolated_metadata_proxy(network) + break + def disable_dhcp_helper(self, network_id): """Disable DHCP for a network known to the agent.""" network = self.cache.get_network_by_id(network_id) diff --git a/neutron/context.py b/neutron/context.py index f248e70250..1da9b77423 100644 --- a/neutron/context.py +++ b/neutron/context.py @@ -144,7 +144,7 @@ class ContextBase(common_context.RequestContext): context.is_admin = True if 'admin' not in [x.lower() for x in context.roles]: - context.roles.append('admin') + context.roles = context.roles + ["admin"] if read_deleted is not None: context.read_deleted = read_deleted diff --git a/neutron/db/migration/__init__.py b/neutron/db/migration/__init__.py index 55c1443f1f..86cce385af 100644 --- a/neutron/db/migration/__init__.py +++ b/neutron/db/migration/__init__.py @@ -12,11 +12,13 @@ # License for the specific language governing permissions and limitations # under the License. +import contextlib import functools from alembic import context from alembic import op import sqlalchemy as sa +from sqlalchemy.engine import reflection def skip_if_offline(func): @@ -122,3 +124,35 @@ def create_table_if_not_exist_psql(table_name, values): "WHERE NOT table_exist(%(name)r);" % {'name': table_name, 'columns': values}) + + +def remove_foreign_keys(table, foreign_keys): + for fk in foreign_keys: + op.drop_constraint( + name=fk['name'], + table_name=table, + type_='foreignkey' + ) + + +def create_foreign_keys(table, foreign_keys): + for fk in foreign_keys: + op.create_foreign_key( + name=fk['name'], + source=table, + referent=fk['referred_table'], + local_cols=fk['constrained_columns'], + remote_cols=fk['referred_columns'], + ondelete='CASCADE' + ) + + +@contextlib.contextmanager +def remove_fks_from_table(table): + try: + inspector = reflection.Inspector.from_engine(op.get_bind()) + foreign_keys = inspector.get_foreign_keys(table) + remove_foreign_keys(table, foreign_keys) + yield + finally: + create_foreign_keys(table, foreign_keys) diff --git a/neutron/db/migration/alembic_migrations/versions/31d7f831a591_add_constraint_for_routerid.py b/neutron/db/migration/alembic_migrations/versions/31d7f831a591_add_constraint_for_routerid.py index 0ba5f58be7..232156748e 100644 --- a/neutron/db/migration/alembic_migrations/versions/31d7f831a591_add_constraint_for_routerid.py +++ b/neutron/db/migration/alembic_migrations/versions/31d7f831a591_add_constraint_for_routerid.py @@ -27,22 +27,12 @@ down_revision = '37f322991f59' from alembic import op import sqlalchemy as sa -from sqlalchemy.engine import reflection + +from neutron.db import migration TABLE_NAME = 'routerl3agentbindings' PK_NAME = 'pk_routerl3agentbindings' -fk_names = {'postgresql': - {'router_id': - 'routerl3agentbindings_router_id_fkey', - 'l3_agent_id': - 'routerl3agentbindings_l3_agent_id_fkey'}, - 'mysql': - {'router_id': - 'routerl3agentbindings_ibfk_2', - 'l3_agent_id': - 'routerl3agentbindings_ibfk_1'}} - def upgrade(): # In order to sanitize the data during migration, @@ -66,60 +56,32 @@ def upgrade(): op.drop_column(TABLE_NAME, 'id') - # DB2 doesn't support nullable column in primary key - if context.bind.dialect.name == 'ibm_db_sa': - op.alter_column( - table_name=TABLE_NAME, - column_name='router_id', - nullable=False - ) - op.alter_column( + with migration.remove_fks_from_table(TABLE_NAME): + # DB2 doesn't support nullable column in primary key + if context.bind.dialect.name == 'ibm_db_sa': + op.alter_column( + table_name=TABLE_NAME, + column_name='router_id', + nullable=False + ) + op.alter_column( + table_name=TABLE_NAME, + column_name='l3_agent_id', + nullable=False + ) + + op.create_primary_key( + name=PK_NAME, table_name=TABLE_NAME, - column_name='l3_agent_id', - nullable=False + cols=['router_id', 'l3_agent_id'] ) - op.create_primary_key( - name=PK_NAME, - table_name=TABLE_NAME, - cols=['router_id', 'l3_agent_id'] - ) - def downgrade(): context = op.get_context() dialect = context.bind.dialect.name - # Drop the existed foreign key constraints - # In order to perform primary key changes - db2fks = {} - if dialect == 'ibm_db_sa': - # NOTE(mriedem): In DB2 the foreign key names are randomly generated - # if you didn't originally explicitly name them, so the name is like - # SQLxxxxx where the suffix is a random integer. Therefore we go - # through and just drop all of the foreign keys and save them so we - # can re-create them later after the primary key is dropped. - inspector = reflection.Inspector.from_engine(op.get_bind().engine) - db2fks = inspector.get_foreign_keys(TABLE_NAME) - for fk in db2fks: - op.drop_constraint( - name=fk.get('name'), - table_name=TABLE_NAME, - type_='foreignkey' - ) - else: - op.drop_constraint( - name=fk_names[dialect]['l3_agent_id'], - table_name=TABLE_NAME, - type_='foreignkey' - ) - op.drop_constraint( - name=fk_names[dialect]['router_id'], - table_name=TABLE_NAME, - type_='foreignkey' - ) - op.drop_constraint( name=PK_NAME, table_name=TABLE_NAME, @@ -139,38 +101,9 @@ def downgrade(): nullable=False ) - op.create_primary_key( - name=PK_NAME, - table_name=TABLE_NAME, - cols=['id'] - ) - - # Restore the foreign key constraints - if dialect == 'ibm_db_sa': - for fk in db2fks: - op.create_foreign_key( - name=fk.get('name'), - source=TABLE_NAME, - referent=fk.get('referred_table'), - local_cols=fk.get('constrained_columns'), - remote_cols=fk.get('referred_columns'), - ondelete='CASCADE' - ) - else: - op.create_foreign_key( - name=fk_names[dialect]['router_id'], - source=TABLE_NAME, - referent='routers', - local_cols=['router_id'], - remote_cols=['id'], - ondelete='CASCADE' - ) - - op.create_foreign_key( - name=fk_names[dialect]['l3_agent_id'], - source=TABLE_NAME, - referent='agents', - local_cols=['l3_agent_id'], - remote_cols=['id'], - ondelete='CASCADE' + with migration.remove_fks_from_table(TABLE_NAME): + op.create_primary_key( + name=PK_NAME, + table_name=TABLE_NAME, + cols=['id'] ) diff --git a/neutron/db/securitygroups_db.py b/neutron/db/securitygroups_db.py index 23b5c80cb1..9237cf31f2 100644 --- a/neutron/db/securitygroups_db.py +++ b/neutron/db/securitygroups_db.py @@ -296,7 +296,11 @@ class SecurityGroupDbMixin(ext_sg.SecurityGroupPluginBase): def _get_ip_proto_number(self, protocol): if protocol is None: return - return IP_PROTOCOL_MAP.get(protocol, protocol) + # According to bug 1381379, protocol is always set to string to avoid + # problems with comparing int and string in PostgreSQL. Here this + # string is converted to int to give an opportunity to use it as + # before. + return int(IP_PROTOCOL_MAP.get(protocol, protocol)) def _validate_port_range(self, rule): """Check that port_range is valid.""" diff --git a/neutron/extensions/securitygroup.py b/neutron/extensions/securitygroup.py index 89b9d8a74b..3524117ee9 100644 --- a/neutron/extensions/securitygroup.py +++ b/neutron/extensions/securitygroup.py @@ -116,7 +116,10 @@ def convert_protocol(value): try: val = int(value) if val >= 0 and val <= 255: - return value + # Set value of protocol number to string due to bug 1381379, + # PostgreSQL fails when it tries to compare integer with string, + # that exists in db. + return str(value) raise SecurityGroupRuleInvalidProtocol( protocol=value, values=sg_supported_protocols) except (ValueError, TypeError): diff --git a/neutron/plugins/cisco/db/n1kv_db_v2.py b/neutron/plugins/cisco/db/n1kv_db_v2.py index d694b23676..ed0b5fdbdd 100644 --- a/neutron/plugins/cisco/db/n1kv_db_v2.py +++ b/neutron/plugins/cisco/db/n1kv_db_v2.py @@ -957,14 +957,22 @@ def _get_profile_bindings(db_session, profile_type=None): If profile type is None, return profile-tenant binding for all profile types. """ - LOG.debug(_("_get_profile_bindings()")) if profile_type: - profile_bindings = (db_session.query(n1kv_models_v2.ProfileBinding). - filter_by(profile_type=profile_type)) - return profile_bindings + return (db_session.query(n1kv_models_v2.ProfileBinding). + filter_by(profile_type=profile_type)) return db_session.query(n1kv_models_v2.ProfileBinding) +def _get_profile_bindings_by_uuid(db_session, profile_id): + """ + Retrieve a list of profile bindings. + + Get all profile-tenant bindings based on profile UUID. + """ + return (db_session.query(n1kv_models_v2.ProfileBinding). + filter_by(profile_id=profile_id)) + + class NetworkProfile_db_mixin(object): """Network Profile Mixin.""" @@ -1099,8 +1107,10 @@ class NetworkProfile_db_mixin(object): original_net_p = get_network_profile(context.session, id) # Update network profile to tenant id binding. if context.is_admin and c_const.ADD_TENANTS in p: - if context.tenant_id not in p[c_const.ADD_TENANTS]: - p[c_const.ADD_TENANTS].append(context.tenant_id) + profile_bindings = _get_profile_bindings_by_uuid(context.session, + profile_id=id) + for bindings in profile_bindings: + p[c_const.ADD_TENANTS].append(bindings.tenant_id) update_profile_binding(context.session, id, p[c_const.ADD_TENANTS], c_const.NETWORK) is_updated = True diff --git a/neutron/plugins/linuxbridge/agent/linuxbridge_neutron_agent.py b/neutron/plugins/linuxbridge/agent/linuxbridge_neutron_agent.py index 8011c0d4bd..d9f7f686f5 100755 --- a/neutron/plugins/linuxbridge/agent/linuxbridge_neutron_agent.py +++ b/neutron/plugins/linuxbridge/agent/linuxbridge_neutron_agent.py @@ -27,6 +27,7 @@ import eventlet eventlet.monkey_patch() from oslo.config import cfg +from six import moves from neutron.agent import l2population_rpc as l2pop_rpc from neutron.agent.linux import ip_lib @@ -523,7 +524,7 @@ class LinuxBridgeManager: 'command': 'bridge fdb', 'mode': 'VXLAN UCAST'}) return False - for segmentation_id in range(1, constants.MAX_VXLAN_VNI + 1): + for segmentation_id in moves.xrange(1, constants.MAX_VXLAN_VNI + 1): if not ip_lib.device_exists( self.get_vxlan_device_name(segmentation_id)): break diff --git a/neutron/tests/unit/cisco/n1kv/test_n1kv_plugin.py b/neutron/tests/unit/cisco/n1kv/test_n1kv_plugin.py index 0a64ba1090..09d0e942e1 100644 --- a/neutron/tests/unit/cisco/n1kv/test_n1kv_plugin.py +++ b/neutron/tests/unit/cisco/n1kv/test_n1kv_plugin.py @@ -612,7 +612,7 @@ class TestN1kvNetworkProfiles(N1kvPluginTestCase): net_p['network_profile']['id']) update_req.environ['neutron.context'] = context.Context('', self.tenant_id, - is_admin = True) + is_admin=True) update_res = update_req.get_response(self.ext_api) self.assertEqual(200, update_res.status_int) db_session = db.get_session() @@ -623,7 +623,7 @@ class TestN1kvNetworkProfiles(N1kvPluginTestCase): net_p['network_profile']['id']) self.assertRaises(c_exc.ProfileTenantBindingNotFound, n1kv_db_v2.get_profile_binding, - db_session, 'tenant2', + db_session, 'tenant4', net_p['network_profile']['id']) tenant3 = n1kv_db_v2.get_profile_binding(db_session, 'tenant3', net_p['network_profile']['id']) @@ -637,24 +637,39 @@ class TestN1kvNetworkProfiles(N1kvPluginTestCase): net_p['network_profile']['id']) update_req.environ['neutron.context'] = context.Context('', self.tenant_id, - is_admin = True) + is_admin=True) update_res = update_req.get_response(self.ext_api) self.assertEqual(200, update_res.status_int) # current tenant_id should always present tenant_id = n1kv_db_v2.get_profile_binding(db_session, self.tenant_id, net_p['network_profile']['id']) + self.assertIsNotNone(tenant_id) self.assertRaises(c_exc.ProfileTenantBindingNotFound, n1kv_db_v2.get_profile_binding, db_session, 'tenant1', net_p['network_profile']['id']) self.assertRaises(c_exc.ProfileTenantBindingNotFound, n1kv_db_v2.get_profile_binding, - db_session, 'tenant2', + db_session, 'tenant4', net_p['network_profile']['id']) tenant3 = n1kv_db_v2.get_profile_binding(db_session, 'tenant3', net_p['network_profile']['id']) - self.assertIsNotNone(tenant_id) self.assertIsNotNone(tenant3) + # Add new tenant4 to network profile and make sure existing tenants + # are not deleted. + data = {'network_profile': {c_const.ADD_TENANTS: + ['tenant4']}} + update_req = self.new_update_request('network_profiles', + data, + net_p['network_profile']['id']) + update_req.environ['neutron.context'] = context.Context('', + self.tenant_id, + is_admin=True) + update_res = update_req.get_response(self.ext_api) + self.assertEqual(200, update_res.status_int) + tenant4 = n1kv_db_v2.get_profile_binding(db_session, 'tenant4', + net_p['network_profile']['id']) + self.assertIsNotNone(tenant4) class TestN1kvBasicGet(test_plugin.TestBasicGet, diff --git a/neutron/tests/unit/test_api_v2_resource.py b/neutron/tests/unit/test_api_v2_resource.py index 91e24de711..ae3dad5a7c 100644 --- a/neutron/tests/unit/test_api_v2_resource.py +++ b/neutron/tests/unit/test_api_v2_resource.py @@ -94,6 +94,16 @@ class RequestTestCase(base.BaseTestCase): def test_context_without_neutron_context(self): self.assertTrue(self.req.context.is_admin) + def test_request_context_elevated(self): + user_context = context.Context( + 'fake_user', 'fake_project', admin=False) + self.assertFalse(user_context.is_admin) + admin_context = user_context.elevated() + self.assertFalse(user_context.is_admin) + self.assertTrue(admin_context.is_admin) + self.assertNotIn('admin', user_context.roles) + self.assertIn('admin', admin_context.roles) + def test_best_match_language(self): # Test that we are actually invoking language negotiation by webop request = wsgi.Request.blank('/') diff --git a/neutron/tests/unit/test_dhcp_agent.py b/neutron/tests/unit/test_dhcp_agent.py index 5e02428b0d..c9c1d28769 100644 --- a/neutron/tests/unit/test_dhcp_agent.py +++ b/neutron/tests/unit/test_dhcp_agent.py @@ -116,6 +116,13 @@ fake_network_ipv6 = dhcp.NetModel(True, dict( admin_state_up=True, subnets=[fake_ipv6_subnet])) +fake_network_ipv6_ipv4 = dhcp.NetModel(True, dict( + id='12345678-1234-5678-1234567890ab', + tenant_id='aaaaaaaa-aaaa-aaaa-aaaaaaaaaaaa', + admin_state_up=True, + subnets=[fake_ipv6_subnet, fake_subnet1], + ports=[fake_port1])) + isolated_network = dhcp.NetModel( True, dict( id='12345678-1234-5678-1234567890ab', @@ -564,6 +571,26 @@ class TestDhcpAgentEventHandler(base.BaseTestCase): enable_isolated_metadata=True, is_isolated_network=True) + def test_enable_dhcp_helper_enable_metadata_ipv6_ipv4_network(self): + self._enable_dhcp_helper(fake_network_ipv6_ipv4, + enable_isolated_metadata=True, + is_isolated_network=True) + + def test_enable_dhcp_helper_driver_failure_ipv6_ipv4_network(self): + self.plugin.get_network_info.return_value = fake_network_ipv6_ipv4 + self.call_driver.return_value = False + cfg.CONF.set_override('enable_isolated_metadata', True) + with mock.patch.object( + self.dhcp, 'enable_isolated_metadata_proxy') as enable_metadata: + self.dhcp.enable_dhcp_helper(fake_network_ipv6_ipv4.id) + self.plugin.assert_has_calls( + [mock.call.get_network_info(fake_network_ipv6_ipv4.id)]) + self.call_driver.assert_called_once_with('enable', + fake_network_ipv6_ipv4) + self.assertFalse(self.cache.called) + self.assertFalse(enable_metadata.called) + self.assertFalse(self.external_process.called) + def test_enable_dhcp_helper(self): self._enable_dhcp_helper(fake_network) diff --git a/neutron/tests/unit/test_extension_security_group.py b/neutron/tests/unit/test_extension_security_group.py index 4f52ba0807..07a5cb0b39 100644 --- a/neutron/tests/unit/test_extension_security_group.py +++ b/neutron/tests/unit/test_extension_security_group.py @@ -1446,6 +1446,9 @@ class TestConvertProtocol(base.BaseTestCase): self.assertRaises(ext_sg.SecurityGroupRuleInvalidProtocol, ext_sg.convert_protocol, val) + def test_convert_numeric_protocol_to_string(self): + self.assertIsInstance(ext_sg.convert_protocol(2), str) + class TestSecurityGroupsXML(TestSecurityGroups): fmt = 'xml' |