CSCO:Tenants not to access unshared n/w profiles
Ensure that a n1kv tenant who has no access to a network profile belonging to some other tenant, is not allowed to modify that profile. Currently, a tenant can create networks on any network profile if he has the network profile id. Change-Id: I53d767acceaa5e2c08e75e6f18847f659cda8d8b Closes-Bug: 1365727
This commit is contained in:
parent
faaf73e95c
commit
dfb716b2c2
@ -98,3 +98,10 @@
|
||||
# (IntOpt) Timeout duration in seconds for the http request
|
||||
# Default value: 15
|
||||
# http_timeout = 15
|
||||
|
||||
# (BoolOpt) Specify whether tenants are restricted from accessing network
|
||||
# profiles belonging to other tenants.
|
||||
# Default value: True, indicating other tenants cannot access network
|
||||
# profiles belonging to a tenant.
|
||||
#
|
||||
# restrict_network_profiles = True
|
||||
|
@ -70,6 +70,10 @@ cisco_n1k_opts = [
|
||||
help=_("Number of threads to use to make HTTP requests")),
|
||||
cfg.IntOpt('http_timeout', default=15,
|
||||
help=_("N1K http timeout duration in seconds")),
|
||||
cfg.BoolOpt('restrict_network_profiles', default=True,
|
||||
help=_("Restrict tenants from accessing network profiles "
|
||||
"belonging to some other tenant")),
|
||||
|
||||
]
|
||||
|
||||
cfg.CONF.register_opts(cisco_opts, "CISCO")
|
||||
|
@ -516,7 +516,7 @@ def reserve_vxlan(db_session, network_profile):
|
||||
raise n_exc.NoNetworkAvailable()
|
||||
|
||||
|
||||
def alloc_network(db_session, network_profile_id):
|
||||
def alloc_network(db_session, network_profile_id, tenant_id):
|
||||
"""
|
||||
Allocate network using first available free segment ID in segment range.
|
||||
|
||||
@ -525,7 +525,7 @@ def alloc_network(db_session, network_profile_id):
|
||||
"""
|
||||
with db_session.begin(subtransactions=True):
|
||||
network_profile = get_network_profile(db_session,
|
||||
network_profile_id)
|
||||
network_profile_id, tenant_id)
|
||||
if network_profile.segment_type == c_const.NETWORK_TYPE_VLAN:
|
||||
return reserve_vlan(db_session, network_profile)
|
||||
if network_profile.segment_type == c_const.NETWORK_TYPE_OVERLAY:
|
||||
@ -785,12 +785,12 @@ def create_network_profile(db_session, network_profile):
|
||||
return net_profile
|
||||
|
||||
|
||||
def delete_network_profile(db_session, id):
|
||||
def delete_network_profile(db_session, id, tenant_id=None):
|
||||
"""Delete Network Profile."""
|
||||
LOG.debug("delete_network_profile()")
|
||||
with db_session.begin(subtransactions=True):
|
||||
try:
|
||||
network_profile = get_network_profile(db_session, id)
|
||||
network_profile = get_network_profile(db_session, id, tenant_id)
|
||||
db_session.delete(network_profile)
|
||||
(db_session.query(n1kv_models_v2.ProfileBinding).
|
||||
filter_by(profile_id=id).delete())
|
||||
@ -799,21 +799,27 @@ def delete_network_profile(db_session, id):
|
||||
raise c_exc.ProfileTenantBindingNotFound(profile_id=id)
|
||||
|
||||
|
||||
def update_network_profile(db_session, id, network_profile):
|
||||
def update_network_profile(db_session, id, network_profile, tenant_id=None):
|
||||
"""Update Network Profile."""
|
||||
LOG.debug("update_network_profile()")
|
||||
with db_session.begin(subtransactions=True):
|
||||
profile = get_network_profile(db_session, id)
|
||||
profile = get_network_profile(db_session, id, tenant_id)
|
||||
profile.update(network_profile)
|
||||
return profile
|
||||
|
||||
|
||||
def get_network_profile(db_session, id):
|
||||
def get_network_profile(db_session, id, tenant_id=None):
|
||||
"""Get Network Profile."""
|
||||
LOG.debug("get_network_profile()")
|
||||
if tenant_id and c_conf.CISCO_N1K.restrict_network_profiles:
|
||||
if _profile_binding_exists(db_session=db_session,
|
||||
tenant_id=tenant_id,
|
||||
profile_id=id,
|
||||
profile_type=c_const.NETWORK) is None:
|
||||
raise c_exc.ProfileTenantBindingNotFound(profile_id=id)
|
||||
try:
|
||||
return db_session.query(
|
||||
n1kv_models_v2.NetworkProfile).filter_by(id=id).one()
|
||||
return db_session.query(n1kv_models_v2.NetworkProfile).filter_by(
|
||||
id=id).one()
|
||||
except exc.NoResultFound:
|
||||
raise c_exc.NetworkProfileNotFound(profile=id)
|
||||
|
||||
@ -1085,10 +1091,12 @@ class NetworkProfile_db_mixin(object):
|
||||
"""
|
||||
# Check whether the network profile is in use.
|
||||
if self._segment_in_use(context.session,
|
||||
get_network_profile(context.session, id)):
|
||||
get_network_profile(context.session, id,
|
||||
context.tenant_id)):
|
||||
raise c_exc.NetworkProfileInUse(profile=id)
|
||||
# Delete and return the network profile if it is not in use.
|
||||
_profile = delete_network_profile(context.session, id)
|
||||
_profile = delete_network_profile(context.session, id,
|
||||
context.tenant_id)
|
||||
return self._make_network_profile_dict(_profile)
|
||||
|
||||
def update_network_profile(self, context, id, network_profile):
|
||||
@ -1105,7 +1113,8 @@ class NetworkProfile_db_mixin(object):
|
||||
# Flag to check whether network profile is updated or not.
|
||||
is_updated = False
|
||||
p = network_profile["network_profile"]
|
||||
original_net_p = get_network_profile(context.session, id)
|
||||
original_net_p = get_network_profile(context.session, id,
|
||||
context.tenant_id)
|
||||
# Update network profile to tenant id binding.
|
||||
if context.is_admin and c_const.ADD_TENANTS in p:
|
||||
profile_bindings = _get_profile_bindings_by_uuid(context.session,
|
||||
@ -1138,7 +1147,8 @@ class NetworkProfile_db_mixin(object):
|
||||
p.get("segment_range") != original_net_p.segment_range):
|
||||
if not self._segment_in_use(context.session, original_net_p):
|
||||
delete_segment_allocations(context.session, original_net_p)
|
||||
updated_net_p = update_network_profile(context.session, id, p)
|
||||
updated_net_p = update_network_profile(context.session, id, p,
|
||||
context.tenant_id)
|
||||
self._validate_segment_range_uniqueness(context,
|
||||
updated_net_p, id)
|
||||
if original_net_p.segment_type == c_const.NETWORK_TYPE_VLAN:
|
||||
@ -1163,7 +1173,8 @@ class NetworkProfile_db_mixin(object):
|
||||
# Return network profile if it is successfully updated.
|
||||
if is_updated:
|
||||
return self._make_network_profile_dict(
|
||||
update_network_profile(context.session, id, p))
|
||||
update_network_profile(context.session, id, p,
|
||||
context.tenant_id))
|
||||
|
||||
def get_network_profile(self, context, id, fields=None):
|
||||
"""
|
||||
@ -1175,7 +1186,7 @@ class NetworkProfile_db_mixin(object):
|
||||
profile dictionary. Only these fields will be returned
|
||||
:returns: network profile dictionary
|
||||
"""
|
||||
profile = get_network_profile(context.session, id)
|
||||
profile = get_network_profile(context.session, id, context.tenant_id)
|
||||
return self._make_network_profile_dict(profile, fields)
|
||||
|
||||
def get_network_profiles(self, context, filters=None, fields=None):
|
||||
@ -1230,7 +1241,7 @@ class NetworkProfile_db_mixin(object):
|
||||
:returns: true if network profile exist else False
|
||||
"""
|
||||
try:
|
||||
get_network_profile(context.session, id)
|
||||
get_network_profile(context.session, id, context.tenant_id)
|
||||
return True
|
||||
except c_exc.NetworkProfileNotFound(profile=id):
|
||||
return False
|
||||
|
@ -683,7 +683,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
LOG.debug('_send_update_network_request: %s', network['id'])
|
||||
db_session = context.session
|
||||
profile = n1kv_db_v2.get_network_profile(
|
||||
db_session, network[n1kv.PROFILE_ID])
|
||||
db_session, network[n1kv.PROFILE_ID], context.tenant_id)
|
||||
n1kvclient = n1kv_client.Client()
|
||||
body = {'description': network['name'],
|
||||
'id': network['id'],
|
||||
@ -882,7 +882,8 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
# tenant network
|
||||
(physical_network, network_type, segmentation_id,
|
||||
multicast_ip) = n1kv_db_v2.alloc_network(session,
|
||||
profile_id)
|
||||
profile_id,
|
||||
context.tenant_id)
|
||||
LOG.debug('Physical_network %(phy_net)s, '
|
||||
'seg_type %(net_type)s, '
|
||||
'seg_id %(seg_id)s, '
|
||||
|
@ -44,6 +44,8 @@ from neutron.tests.unit import test_l3_schedulers
|
||||
PHYS_NET = 'some-phys-net'
|
||||
VLAN_MIN = 100
|
||||
VLAN_MAX = 110
|
||||
TENANT_NOT_ADMIN = 'not_admin'
|
||||
TENANT_TEST = 'test'
|
||||
|
||||
|
||||
class FakeResponse(object):
|
||||
@ -159,6 +161,12 @@ class N1kvPluginTestCase(test_plugin.NeutronDbPluginV2TestCase):
|
||||
profile['physical_network'] = PHYS_NET
|
||||
net_p = n1kv_db_v2.create_network_profile(db_session, profile)
|
||||
n1kv_db_v2.sync_vlan_allocations(db_session, net_p)
|
||||
n1kv_db_v2.create_profile_binding(db_session, self.tenant_id,
|
||||
net_p['id'], c_const.NETWORK)
|
||||
n1kv_db_v2.create_profile_binding(db_session, TENANT_NOT_ADMIN,
|
||||
net_p['id'], c_const.NETWORK)
|
||||
n1kv_db_v2.create_profile_binding(db_session, TENANT_TEST,
|
||||
net_p['id'], c_const.NETWORK)
|
||||
return net_p
|
||||
|
||||
def setUp(self, ext_mgr=NetworkProfileTestExtensionManager()):
|
||||
@ -557,7 +565,7 @@ class TestN1kvNetworkProfiles(N1kvPluginTestCase):
|
||||
self.new_create_request('network_profiles', net_p_dict)
|
||||
bindings = (db_session.query(n1kv_models_v2.ProfileBinding).filter_by(
|
||||
profile_type="network"))
|
||||
self.assertEqual(bindings.count(), 0)
|
||||
self.assertEqual(3, bindings.count())
|
||||
|
||||
def test_create_network_profile_with_old_add_tenant_fail(self):
|
||||
data = self._prepare_net_profile_data('vlan')
|
||||
@ -657,6 +665,52 @@ class TestN1kvNetworkProfiles(N1kvPluginTestCase):
|
||||
net_p['network_profile']['id'])
|
||||
self.assertIsNotNone(tenant4)
|
||||
|
||||
def test_get_network_profile_restricted(self):
|
||||
c_conf.CONF.set_override('restrict_network_profiles', True,
|
||||
'CISCO_N1K')
|
||||
ctx1 = context.Context(user_id='admin',
|
||||
tenant_id='tenant1',
|
||||
is_admin=True)
|
||||
sess1 = db.get_session()
|
||||
net_p = self._make_test_profile(name='netp1')
|
||||
n1kv_db_v2.create_profile_binding(sess1, ctx1.tenant_id,
|
||||
net_p['id'], c_const.NETWORK)
|
||||
#network profile binding with creator tenant should always exist
|
||||
profile = n1kv_db_v2.get_network_profile(sess1, net_p['id'],
|
||||
ctx1.tenant_id)
|
||||
self.assertIsNotNone(profile)
|
||||
ctx2 = context.Context(user_id='non_admin',
|
||||
tenant_id='tenant2',
|
||||
is_admin=False)
|
||||
sess2 = db.get_session()
|
||||
self.assertRaises(c_exc.ProfileTenantBindingNotFound,
|
||||
n1kv_db_v2.get_network_profile,
|
||||
sess2, net_p['id'], ctx2.tenant_id)
|
||||
|
||||
def test_get_network_profile_unrestricted(self):
|
||||
c_conf.CONF.set_override('restrict_network_profiles', False,
|
||||
'CISCO_N1K')
|
||||
ctx1 = context.Context(user_id='admin',
|
||||
tenant_id='tenant1',
|
||||
is_admin=True)
|
||||
sess1 = db.get_session()
|
||||
net_p = self._make_test_profile(name='netp1')
|
||||
n1kv_db_v2.create_profile_binding(sess1, ctx1.tenant_id,
|
||||
net_p['id'], c_const.NETWORK)
|
||||
# network profile binding with creator tenant should always exist
|
||||
profile = n1kv_db_v2.get_network_profile(sess1, net_p['id'],
|
||||
ctx1.tenant_id)
|
||||
self.assertIsNotNone(profile)
|
||||
ctx2 = context.Context(user_id='non_admin',
|
||||
tenant_id='tenant2',
|
||||
is_admin=False)
|
||||
sess2 = db.get_session()
|
||||
profile = n1kv_db_v2.get_network_profile(sess2, net_p['id'],
|
||||
ctx2.tenant_id)
|
||||
#network profile will be returned even though the profile is
|
||||
#not bound to tenant of sess2
|
||||
self.assertIsNotNone(profile)
|
||||
|
||||
|
||||
class TestN1kvBasicGet(test_plugin.TestBasicGet,
|
||||
N1kvPluginTestCase):
|
||||
|
Loading…
Reference in New Issue
Block a user