Assign Cisco nw profile to multi-tenants in single request
Currently with Cisco N1kv plugin, user can assign cisco network profile to only one tenant in a request. So user has to send multiple requests to assign a cisco network profile to multiple tenants. This fix is going to add the support to assign to multiple tenants in a single request This fix has corresponding changes in neutron, python-neutronclient and horizon. All the changes should be committed at the same time Change-Id: I42ffbd17a80f741d9cf1094dc79b588444bd9d4b Implements: blueprint cisco-network-profile-multi-tenants-support
This commit is contained in:
parent
540e2c34ca
commit
ab1f12cf3d
@ -115,3 +115,7 @@ AGENT_TYPE_CFG = 'Cisco cfg agent'
|
|||||||
CFG_AGENT = 'cisco_cfg_agent'
|
CFG_AGENT = 'cisco_cfg_agent'
|
||||||
# Topic for routing service helper in Cisco configuration agent
|
# Topic for routing service helper in Cisco configuration agent
|
||||||
CFG_AGENT_L3_ROUTING = 'cisco_cfg_agent_l3_routing'
|
CFG_AGENT_L3_ROUTING = 'cisco_cfg_agent_l3_routing'
|
||||||
|
|
||||||
|
# Values for network profile fields
|
||||||
|
ADD_TENANTS = 'add_tenants'
|
||||||
|
REMOVE_TENANTS = 'remove_tenants'
|
||||||
|
@ -903,7 +903,9 @@ def create_profile_binding(db_session, tenant_id, profile_id, profile_type):
|
|||||||
|
|
||||||
|
|
||||||
def _profile_binding_exists(db_session, tenant_id, profile_id, profile_type):
|
def _profile_binding_exists(db_session, tenant_id, profile_id, profile_type):
|
||||||
|
"""Check if the profile-tenant binding exists."""
|
||||||
LOG.debug(_("_profile_binding_exists()"))
|
LOG.debug(_("_profile_binding_exists()"))
|
||||||
|
db_session = db_session or db.get_session()
|
||||||
return (db_session.query(n1kv_models_v2.ProfileBinding).
|
return (db_session.query(n1kv_models_v2.ProfileBinding).
|
||||||
filter_by(tenant_id=tenant_id, profile_id=profile_id,
|
filter_by(tenant_id=tenant_id, profile_id=profile_id,
|
||||||
profile_type=profile_type).first())
|
profile_type=profile_type).first())
|
||||||
@ -934,6 +936,23 @@ def delete_profile_binding(db_session, tenant_id, profile_id):
|
|||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def update_profile_binding(db_session, profile_id, tenants, profile_type):
|
||||||
|
"""Updating Profile Binding."""
|
||||||
|
LOG.debug('update_profile_binding()')
|
||||||
|
if profile_type not in ("network", "policy"):
|
||||||
|
raise n_exc.NeutronException(_("Invalid profile type"))
|
||||||
|
db_session = db_session or db.get_session()
|
||||||
|
with db_session.begin(subtransactions=True):
|
||||||
|
db_session.query(n1kv_models_v2.ProfileBinding).filter_by(
|
||||||
|
profile_id=profile_id, profile_type=profile_type).delete()
|
||||||
|
new_tenants_set = set(tenants)
|
||||||
|
for tenant_id in new_tenants_set:
|
||||||
|
tenant = n1kv_models_v2.ProfileBinding(profile_type = profile_type,
|
||||||
|
tenant_id = tenant_id,
|
||||||
|
profile_id = profile_id)
|
||||||
|
db_session.add(tenant)
|
||||||
|
|
||||||
|
|
||||||
def _get_profile_bindings(db_session, profile_type=None):
|
def _get_profile_bindings(db_session, profile_type=None):
|
||||||
"""
|
"""
|
||||||
Retrieve a list of profile bindings.
|
Retrieve a list of profile bindings.
|
||||||
@ -1044,10 +1063,11 @@ class NetworkProfile_db_mixin(object):
|
|||||||
context.tenant_id,
|
context.tenant_id,
|
||||||
net_profile.id,
|
net_profile.id,
|
||||||
c_const.NETWORK)
|
c_const.NETWORK)
|
||||||
if p.get("add_tenant"):
|
if p.get(c_const.ADD_TENANTS):
|
||||||
self.add_network_profile_tenant(context.session,
|
for tenant in p[c_const.ADD_TENANTS]:
|
||||||
net_profile.id,
|
self.add_network_profile_tenant(context.session,
|
||||||
p["add_tenant"])
|
net_profile.id,
|
||||||
|
tenant)
|
||||||
return self._make_network_profile_dict(net_profile)
|
return self._make_network_profile_dict(net_profile)
|
||||||
|
|
||||||
def delete_network_profile(self, context, id):
|
def delete_network_profile(self, context, id):
|
||||||
@ -1082,12 +1102,17 @@ class NetworkProfile_db_mixin(object):
|
|||||||
p = network_profile["network_profile"]
|
p = network_profile["network_profile"]
|
||||||
original_net_p = get_network_profile(context.session, id)
|
original_net_p = get_network_profile(context.session, id)
|
||||||
# Update network profile to tenant id binding.
|
# Update network profile to tenant id binding.
|
||||||
if context.is_admin and "add_tenant" in p:
|
if context.is_admin and c_const.ADD_TENANTS in p:
|
||||||
self.add_network_profile_tenant(context.session, id,
|
if context.tenant_id not in p[c_const.ADD_TENANTS]:
|
||||||
p["add_tenant"])
|
p[c_const.ADD_TENANTS].append(context.tenant_id)
|
||||||
|
update_profile_binding(context.session, id,
|
||||||
|
p[c_const.ADD_TENANTS], c_const.NETWORK)
|
||||||
is_updated = True
|
is_updated = True
|
||||||
if context.is_admin and "remove_tenant" in p:
|
if context.is_admin and c_const.REMOVE_TENANTS in p:
|
||||||
delete_profile_binding(context.session, p["remove_tenant"], id)
|
for remove_tenant in p[c_const.REMOVE_TENANTS]:
|
||||||
|
if remove_tenant == context.tenant_id:
|
||||||
|
continue
|
||||||
|
delete_profile_binding(context.session, remove_tenant, id)
|
||||||
is_updated = True
|
is_updated = True
|
||||||
if original_net_p.segment_type == c_const.NETWORK_TYPE_TRUNK:
|
if original_net_p.segment_type == c_const.NETWORK_TYPE_TRUNK:
|
||||||
#TODO(abhraut): Remove check when Trunk supports segment range.
|
#TODO(abhraut): Remove check when Trunk supports segment range.
|
||||||
|
@ -46,10 +46,14 @@ RESOURCE_ATTRIBUTE_MAP = {
|
|||||||
'is_visible': True, 'default': ''},
|
'is_visible': True, 'default': ''},
|
||||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
'tenant_id': {'allow_post': True, 'allow_put': False,
|
||||||
'is_visible': False, 'default': ''},
|
'is_visible': False, 'default': ''},
|
||||||
'add_tenant': {'allow_post': True, 'allow_put': True,
|
'add_tenants': {'allow_post': True, 'allow_put': True,
|
||||||
'is_visible': True, 'default': None},
|
'is_visible': True, 'default': None,
|
||||||
'remove_tenant': {'allow_post': True, 'allow_put': True,
|
'convert_to': attributes.convert_none_to_empty_list},
|
||||||
'is_visible': True, 'default': None},
|
'remove_tenants': {
|
||||||
|
'allow_post': True, 'allow_put': True,
|
||||||
|
'is_visible': True, 'default': None,
|
||||||
|
'convert_to': attributes.convert_none_to_empty_list,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'network_profile_bindings': {
|
'network_profile_bindings': {
|
||||||
'profile_id': {'allow_post': False, 'allow_put': False,
|
'profile_id': {'allow_post': False, 'allow_put': False,
|
||||||
|
@ -805,6 +805,27 @@ class ProfileBindingTests(testlib_api.SqlTestCase,
|
|||||||
except s_exc.NoResultFound:
|
except s_exc.NoResultFound:
|
||||||
self.fail("Could not create Profile Binding")
|
self.fail("Could not create Profile Binding")
|
||||||
|
|
||||||
|
def test_update_profile_binding(self):
|
||||||
|
test_tenant_id = "d434dd90-76ec-11e2-bcfd-0800200c9a66"
|
||||||
|
test_profile_id = "dd7b9741-76ec-11e2-bcfd-0800200c9a66"
|
||||||
|
test_profile_type = "network"
|
||||||
|
n1kv_db_v2.create_profile_binding(self.session,
|
||||||
|
test_tenant_id,
|
||||||
|
test_profile_id,
|
||||||
|
test_profile_type)
|
||||||
|
new_tenants = ['d434dd90-76ec-11e2-bcfd-0800200c9a67',
|
||||||
|
'd434dd90-76ec-11e2-bcfd-0800200c9a68',
|
||||||
|
'd434dd90-76ec-11e2-bcfd-0800200c9a69']
|
||||||
|
n1kv_db_v2.update_profile_binding(self.session,
|
||||||
|
test_profile_id,
|
||||||
|
new_tenants,
|
||||||
|
test_profile_type)
|
||||||
|
|
||||||
|
result = self.session.query(n1kv_models_v2.ProfileBinding).filter_by(
|
||||||
|
profile_type=test_profile_type,
|
||||||
|
profile_id=test_profile_id).all()
|
||||||
|
self.assertEqual(3, len(result))
|
||||||
|
|
||||||
def test_get_profile_binding(self):
|
def test_get_profile_binding(self):
|
||||||
test_tenant_id = "d434dd90-76ec-11e2-bcfd-0800200c9a66"
|
test_tenant_id = "d434dd90-76ec-11e2-bcfd-0800200c9a66"
|
||||||
test_profile_id = "dd7b9741-76ec-11e2-bcfd-0800200c9a66"
|
test_profile_id = "dd7b9741-76ec-11e2-bcfd-0800200c9a66"
|
||||||
|
@ -559,6 +559,89 @@ class TestN1kvNetworkProfiles(N1kvPluginTestCase):
|
|||||||
profile_type="network"))
|
profile_type="network"))
|
||||||
self.assertEqual(bindings.count(), 0)
|
self.assertEqual(bindings.count(), 0)
|
||||||
|
|
||||||
|
def test_create_network_profile_with_old_add_tenant_fail(self):
|
||||||
|
data = self._prepare_net_profile_data('vlan')
|
||||||
|
data['network_profile']['add_tenant'] = 'tenant1'
|
||||||
|
net_p_req = self.new_create_request('network_profiles', data)
|
||||||
|
res = net_p_req.get_response(self.ext_api)
|
||||||
|
self.assertEqual(400, res.status_int)
|
||||||
|
|
||||||
|
def test_create_network_profile_multi_tenants(self):
|
||||||
|
data = self._prepare_net_profile_data('vlan')
|
||||||
|
data['network_profile'][c_const.ADD_TENANTS] = ['tenant1', 'tenant2']
|
||||||
|
del data['network_profile']['tenant_id']
|
||||||
|
net_p_req = self.new_create_request('network_profiles', data)
|
||||||
|
net_p_req.environ['neutron.context'] = context.Context('',
|
||||||
|
self.tenant_id,
|
||||||
|
is_admin = True)
|
||||||
|
res = net_p_req.get_response(self.ext_api)
|
||||||
|
self.assertEqual(201, res.status_int)
|
||||||
|
net_p = self.deserialize(self.fmt, res)
|
||||||
|
db_session = db.get_session()
|
||||||
|
tenant_id = n1kv_db_v2.get_profile_binding(db_session, self.tenant_id,
|
||||||
|
net_p['network_profile']['id'])
|
||||||
|
tenant1 = n1kv_db_v2.get_profile_binding(db_session, 'tenant1',
|
||||||
|
net_p['network_profile']['id'])
|
||||||
|
tenant2 = n1kv_db_v2.get_profile_binding(db_session, 'tenant2',
|
||||||
|
net_p['network_profile']['id'])
|
||||||
|
self.assertIsNotNone(tenant_id)
|
||||||
|
self.assertIsNotNone(tenant1)
|
||||||
|
self.assertIsNotNone(tenant2)
|
||||||
|
return net_p
|
||||||
|
|
||||||
|
def test_update_network_profile_multi_tenants(self):
|
||||||
|
net_p = self.test_create_network_profile_multi_tenants()
|
||||||
|
data = {'network_profile': {c_const.ADD_TENANTS:
|
||||||
|
['tenant1', 'tenant3']}}
|
||||||
|
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)
|
||||||
|
db_session = db.get_session()
|
||||||
|
# current tenant_id should always present
|
||||||
|
tenant_id = n1kv_db_v2.get_profile_binding(db_session, self.tenant_id,
|
||||||
|
net_p['network_profile']['id'])
|
||||||
|
tenant1 = 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',
|
||||||
|
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(tenant1)
|
||||||
|
self.assertIsNotNone(tenant3)
|
||||||
|
data = {'network_profile': {c_const.REMOVE_TENANTS: [self.tenant_id,
|
||||||
|
'tenant1']}}
|
||||||
|
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)
|
||||||
|
# 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.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',
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
class TestN1kvBasicGet(test_plugin.TestBasicGet,
|
class TestN1kvBasicGet(test_plugin.TestBasicGet,
|
||||||
N1kvPluginTestCase):
|
N1kvPluginTestCase):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user