summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--neutron/agent/dhcp_agent.py12
-rw-r--r--neutron/context.py2
-rw-r--r--neutron/db/migration/__init__.py34
-rw-r--r--neutron/db/migration/alembic_migrations/versions/31d7f831a591_add_constraint_for_routerid.py115
-rw-r--r--neutron/db/securitygroups_db.py6
-rw-r--r--neutron/extensions/securitygroup.py5
-rw-r--r--neutron/plugins/cisco/db/n1kv_db_v2.py22
-rwxr-xr-xneutron/plugins/linuxbridge/agent/linuxbridge_neutron_agent.py3
-rw-r--r--neutron/tests/unit/cisco/n1kv/test_n1kv_plugin.py25
-rw-r--r--neutron/tests/unit/test_api_v2_resource.py10
-rw-r--r--neutron/tests/unit/test_dhcp_agent.py27
-rw-r--r--neutron/tests/unit/test_extension_security_group.py3
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'