Update Cisco N1KV plugin to VSM REST api calls

Modify the existing REST calls from the plugin to VSM to update the
attributes and use UUIDs as index, instead of string names, for all
the resources.

Change-Id: Icb4950ea7c6f036e9a25ee79e3f5fe30d40f47de
Closes-Bug: 1233802
This commit is contained in:
Abhishek Raut 2013-10-02 23:32:02 -07:00
parent 8ed9b2c2c0
commit ba242d91c5
7 changed files with 319 additions and 211 deletions

View File

@ -105,6 +105,7 @@ MAPPING = 'mapping'
SEGMENTS = 'segments'
SEGMENT = 'segment'
BRIDGE_DOMAIN_SUFFIX = '_bd'
LOGICAL_NETWORK_SUFFIX = '_log_net'
ENCAPSULATION_PROFILE_SUFFIX = '_profile'
UUID_LENGTH = 36

View File

@ -849,6 +849,7 @@ def create_network_profile(db_session, network_profile):
kwargs["multicast_ip_range"] = network_profile[
"multicast_ip_range"]
kwargs["segment_range"] = network_profile["segment_range"]
kwargs["sub_type"] = network_profile["sub_type"]
elif network_profile["segment_type"] == c_const.NETWORK_TYPE_TRUNK:
kwargs["sub_type"] = network_profile["sub_type"]
net_profile = n1kv_models_v2.NetworkProfile(**kwargs)

View File

@ -30,7 +30,7 @@ MEMBER_SEGMENTS = 'n1kv:member_segments'
EXTENDED_ATTRIBUTES_2_0 = {
'networks': {
PROFILE_ID: {'allow_post': True, 'allow_put': True,
PROFILE_ID: {'allow_post': True, 'allow_put': False,
'validate': {'type:regex': attributes.UUID_PATTERN},
'default': attributes.ATTR_NOT_SPECIFIED,
'is_visible': True},
@ -48,7 +48,7 @@ EXTENDED_ATTRIBUTES_2_0 = {
'is_visible': True},
},
'ports': {
PROFILE_ID: {'allow_post': True, 'allow_put': True,
PROFILE_ID: {'allow_post': True, 'allow_put': False,
'validate': {'type:regex': attributes.UUID_PATTERN},
'default': attributes.ATTR_NOT_SPECIFIED,
'is_visible': True}

View File

@ -32,20 +32,18 @@ RESOURCE_ATTRIBUTE_MAP = {
'is_visible': True},
'name': {'allow_post': True, 'allow_put': True,
'is_visible': True, 'default': ''},
'segment_type': {'allow_post': True, 'allow_put': True,
'segment_type': {'allow_post': True, 'allow_put': False,
'is_visible': True, 'default': ''},
'sub_type': {'allow_post': True, 'allow_put': True,
'sub_type': {'allow_post': True, 'allow_put': False,
'is_visible': True,
'default': attributes.ATTR_NOT_SPECIFIED},
'segment_range': {'allow_post': True, 'allow_put': True,
'is_visible': True, 'default': ''},
'sub_type': {'allow_post': True, 'allow_put': True,
'is_visible': True, 'default': ''},
'multicast_ip_range': {'allow_post': True, 'allow_put': True,
'is_visible': True, 'default': '0.0.0.0'},
'multicast_ip_index': {'allow_post': False, 'allow_put': False,
'is_visible': False, 'default': '0'},
'physical_network': {'allow_post': True, 'allow_put': True,
'physical_network': {'allow_post': True, 'allow_put': False,
'is_visible': True, 'default': ''},
'tenant_id': {'allow_post': True, 'allow_put': False,
'is_visible': False, 'default': ''},

View File

@ -126,11 +126,8 @@ class Client(object):
# Define paths for the URI where the client connects for HTTP requests.
port_profiles_path = "/virtual-port-profile"
network_segments_path = "/network-segment"
network_segment_path = "/network-segment/%s"
network_segment_pools_path = "/network-segment-pool"
network_segment_pool_path = "/network-segment-pool/%s"
ip_pools_path = "/ip-pool-template"
ip_pool_path = "/ip-pool-template/%s"
ports_path = "/kvm/vm-network/%s/ports"
port_path = "/kvm/vm-network/%s/ports/%s"
@ -138,7 +135,6 @@ class Client(object):
vm_network_path = "/kvm/vm-network/%s"
bridge_domains_path = "/kvm/bridge-domain"
bridge_domain_path = "/kvm/bridge-domain/%s"
logical_networks_path = "/logical-network"
logical_network_path = "/logical-network/%s"
events_path = "/kvm/events"
clusters_path = "/cluster"
@ -179,9 +175,10 @@ class Client(object):
:param network: network dict
:param overlay_subtype: string representing subtype of overlay network
"""
body = {'name': network['name'] + c_const.BRIDGE_DOMAIN_SUFFIX,
body = {'name': network['id'] + c_const.BRIDGE_DOMAIN_SUFFIX,
'segmentId': network[providernet.SEGMENTATION_ID],
'subType': overlay_subtype}
'subType': overlay_subtype,
'tenantId': network['tenant_id']}
if overlay_subtype == c_const.NETWORK_SUBTYPE_NATIVE_VXLAN:
body['groupIp'] = network[n1kv_profile.MULTICAST_IP]
return self._post(self.bridge_domains_path,
@ -193,7 +190,7 @@ class Client(object):
:param name: name of the bridge domain to be deleted
"""
return self._delete(self.bridge_domain_path % (name))
return self._delete(self.bridge_domain_path % name)
def create_network_segment(self, network, network_profile):
"""
@ -202,14 +199,15 @@ class Client(object):
:param network: network dict
:param network_profile: network profile dict
"""
body = {'name': network['name'],
body = {'publishName': network['name'],
'description': network['name'],
'id': network['id'],
'mode': 'access',
'networkSegmentPool': network_profile['name'], }
'tenantId': network['tenant_id'],
'networkSegmentPool': network_profile['id'], }
if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_VLAN:
body['vlan'] = network[providernet.SEGMENTATION_ID]
elif network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_OVERLAY:
body['bridgeDomain'] = (network['name'] +
body['bridgeDomain'] = (network['id'] +
c_const.BRIDGE_DOMAIN_SUFFIX)
if network_profile['segment_type'] == c_const.NETWORK_TYPE_TRUNK:
body['mode'] = c_const.NETWORK_TYPE_TRUNK
@ -218,88 +216,99 @@ class Client(object):
body['addSegments'] = network['add_segment_list']
body['delSegments'] = network['del_segment_list']
else:
body['encapProfile'] = (network['name'] +
body['encapProfile'] = (network['id'] +
c_const.ENCAPSULATION_PROFILE_SUFFIX)
else:
body['mode'] = 'access'
body['segmentType'] = network_profile['segment_type']
return self._post(self.network_segments_path,
return self._post(self.network_segment_path % network['id'],
body=body)
def update_network_segment(self, network_segment_name, body):
def update_network_segment(self, network_segment_id, body):
"""
Update a network segment on the VSM.
Network segment on VSM can be updated to associate it with an ip-pool
or update its description and segment id.
:param network_segment_name: name of the network segment
:param network_segment_id: UUID representing the network segment
:param body: dict of arguments to be updated
"""
return self._post(self.network_segment_path % (network_segment_name),
return self._post(self.network_segment_path % network_segment_id,
body=body)
def delete_network_segment(self, network_segment_name):
def delete_network_segment(self, network_segment_id):
"""
Delete a network segment on the VSM.
:param network_segment_name: name of the network segment
:param network_segment_id: UUID representing the network segment
"""
return self._delete(self.network_segment_path % (network_segment_name))
return self._delete(self.network_segment_path % network_segment_id)
def create_logical_network(self, network_profile):
def create_logical_network(self, network_profile, tenant_id):
"""
Create a logical network on the VSM.
:param network_profile: network profile dict
:param tenant_id: UUID representing the tenant
"""
LOG.debug(_("Logical network"))
body = {'name': network_profile['name']}
return self._post(self.logical_networks_path,
body = {'description': network_profile['name'],
'tenantId': tenant_id}
logical_network_name = (network_profile['id'] +
c_const.LOGICAL_NETWORK_SUFFIX)
return self._post(self.logical_network_path % logical_network_name,
body=body)
def delete_logical_network(self, network_profile):
def delete_logical_network(self, logical_network_name):
"""
Delete a logical network on VSM.
:param network_profile: network profile dict
:param logical_network_name: string representing name of the logical
network
"""
return self._delete(
self.logical_network_path % (network_profile['name']))
self.logical_network_path % logical_network_name)
def create_network_segment_pool(self, network_profile):
def create_network_segment_pool(self, network_profile, tenant_id):
"""
Create a network segment pool on the VSM.
:param network_profile: network profile dict
:param tenant_id: UUID representing the tenant
"""
LOG.debug(_("network_segment_pool"))
logical_network_name = (network_profile['id'] +
c_const.LOGICAL_NETWORK_SUFFIX)
body = {'name': network_profile['name'],
'description': network_profile['name'],
'id': network_profile['id'],
'logicalNetwork': network_profile['name']}
return self._post(self.network_segment_pools_path,
body=body)
'logicalNetwork': logical_network_name,
'tenantId': tenant_id}
return self._post(
self.network_segment_pool_path % network_profile['id'],
body=body)
def update_network_segment_pool(self, network_segment_pool, body):
def update_network_segment_pool(self, network_profile):
"""
Update a network segment pool on the VSM.
:param network_segment_pool: string representing the name of network
segment pool to be updated
:param body: dictionary representing key values of network segment
pool which need to be updated
:param network_profile: network profile dict
"""
body = {'name': network_profile['name'],
'description': network_profile['name']}
return self._post(self.network_segment_pool_path %
(network_segment_pool), body=body)
network_profile['id'], body=body)
def delete_network_segment_pool(self, network_segment_pool_name):
def delete_network_segment_pool(self, network_segment_pool_id):
"""
Delete a network segment pool on the VSM.
:param network_segment_pool_name: name of the network segment pool
:param network_segment_pool_id: UUID representing the network
segment pool
"""
return self._delete(self.network_segment_pool_path %
(network_segment_pool_name))
network_segment_pool_id)
def create_ip_pool(self, subnet):
"""
@ -328,38 +337,38 @@ class Client(object):
body = {'addressRangeStart': address_range_start,
'addressRangeEnd': address_range_end,
'ipAddressSubnet': netmask,
'name': subnet['name'],
'description': subnet['name'],
'gateway': subnet['gateway_ip'],
'networkAddress': network_address}
return self._post(self.ip_pools_path,
'networkAddress': network_address,
'tenantId': subnet['tenant_id']}
return self._post(self.ip_pool_path % subnet['id'],
body=body)
def delete_ip_pool(self, subnet_name):
def delete_ip_pool(self, subnet_id):
"""
Delete an ip-pool on the VSM.
:param subnet_name: name of the subnet
:param subnet_id: UUID representing the subnet
"""
return self._delete(self.ip_pool_path % (subnet_name))
return self._delete(self.ip_pool_path % subnet_id)
def create_vm_network(self,
port,
vm_network_name,
policy_profile,
network_name):
policy_profile):
"""
Create a VM network on the VSM.
:param port: port dict
:param vm_network_name: name of the VM network
:param policy_profile: policy profile dict
:param network_name: string representing the name of the network
"""
body = {'name': vm_network_name,
'networkSegmentId': port['network_id'],
'networkSegment': network_name,
'networkSegment': port['network_id'],
'portProfile': policy_profile['name'],
'portProfileId': policy_profile['id'],
'tenantId': port['tenant_id'],
}
return self._post(self.vm_networks_path,
body=body)
@ -370,7 +379,7 @@ class Client(object):
:param vm_network_name: name of the VM network
"""
return self._delete(self.vm_network_path % (vm_network_name))
return self._delete(self.vm_network_path % vm_network_name)
def create_n1kv_port(self, port, vm_network_name):
"""
@ -381,7 +390,9 @@ class Client(object):
"""
body = {'id': port['id'],
'macAddress': port['mac_address']}
return self._post(self.ports_path % (vm_network_name),
if port.get('fixed_ips'):
body['ipAddress'] = port['fixed_ips'][0]['ip_address']
return self._post(self.ports_path % vm_network_name,
body=body)
def update_n1kv_port(self, vm_network_name, port_id, body):
@ -394,7 +405,7 @@ class Client(object):
:param port_id: UUID of the port
:param body: dict of the arguments to be updated
"""
return self._post(self.port_path % ((vm_network_name), (port_id)),
return self._post(self.port_path % (vm_network_name, port_id),
body=body)
def delete_n1kv_port(self, vm_network_name, port_id):
@ -404,7 +415,7 @@ class Client(object):
:param vm_network_name: name of the VM network which imports this port
:param port_id: UUID of the port
"""
return self._delete(self.port_path % ((vm_network_name), (port_id)))
return self._delete(self.port_path % (vm_network_name, port_id))
def _do_request(self, method, action, body=None,
headers=None):
@ -484,7 +495,7 @@ class Client(object):
"""
if not format:
format = self.format
return "application/%s" % (format)
return "application/%s" % format
def _delete(self, action, body=None, headers=None):
return self._do_request("DELETE", action, body=body,
@ -548,7 +559,7 @@ class Client(object):
:param body: mapping dictionary
"""
return self._post(self.encap_profile_path
% (profile_name), body=body)
% profile_name, body=body)
def delete_encapsulation_profile(self, name):
"""
@ -556,4 +567,4 @@ class Client(object):
:param name: name of the encapsulation profile to be deleted
"""
return self._delete(self.encap_profile_path % (name))
return self._delete(self.encap_profile_path % name)

View File

@ -697,15 +697,16 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
return profile_id
def _send_create_logical_network_request(self, network_profile):
def _send_create_logical_network_request(self, network_profile, tenant_id):
"""
Send create logical network request to VSM.
:param network_profile: network profile dictionary
:param tenant_id: UUID representing the tenant
"""
LOG.debug(_('_send_create_logical_network'))
n1kvclient = n1kv_client.Client()
n1kvclient.create_logical_network(network_profile)
n1kvclient.create_logical_network(network_profile, tenant_id)
def _send_delete_logical_network_request(self, network_profile):
"""
@ -715,7 +716,9 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
"""
LOG.debug('_send_delete_logical_network')
n1kvclient = n1kv_client.Client()
n1kvclient.delete_logical_network(network_profile)
logical_network_name = (network_profile['id'] +
c_const.LOGICAL_NETWORK_SUFFIX)
n1kvclient.delete_logical_network(logical_network_name)
def _send_create_network_profile_request(self, context, profile):
"""
@ -726,7 +729,17 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
"""
LOG.debug(_('_send_create_network_profile_request: %s'), profile['id'])
n1kvclient = n1kv_client.Client()
n1kvclient.create_network_segment_pool(profile)
n1kvclient.create_network_segment_pool(profile, context.tenant_id)
def _send_update_network_profile_request(self, profile):
"""
Send update network profile request to VSM.
:param profile: network profile dictionary
"""
LOG.debug(_('_send_update_network_profile_request: %s'), profile['id'])
n1kvclient = n1kv_client.Client()
n1kvclient.update_network_segment_pool(profile)
def _send_delete_network_profile_request(self, profile):
"""
@ -737,7 +750,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
LOG.debug(_('_send_delete_network_profile_request: %s'),
profile['name'])
n1kvclient = n1kv_client.Client()
n1kvclient.delete_network_segment_pool(profile['name'])
n1kvclient.delete_network_segment_pool(profile['id'])
def _send_create_network_request(self, context, network, segment_pairs):
"""
@ -786,9 +799,9 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
profile = n1kv_db_v2.get_network_profile(
db_session, network[n1kv_profile.PROFILE_ID])
n1kvclient = n1kv_client.Client()
body = {'name': network['name'],
body = {'publishName': network['name'],
'id': network['id'],
'networkDefinition': profile['name'],
'networkSegmentPool': profile['id'],
'vlan': network[providernet.SEGMENTATION_ID],
'mode': 'access',
'segmentType': profile['segment_type'],
@ -806,7 +819,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
LOG.debug(_('add_segments=%s'), body['addSegments'])
LOG.debug(_('del_segments=%s'), body['delSegments'])
if profile['sub_type'] == c_const.NETWORK_TYPE_OVERLAY:
encap_profile = (network['name'] +
encap_profile = (network['id'] +
c_const.ENCAPSULATION_PROFILE_SUFFIX)
encap_dict = {'name': encap_profile,
'addMappings': (
@ -817,7 +830,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
del_segments))}
n1kvclient.update_encapsulation_profile(context, encap_profile,
encap_dict)
n1kvclient.update_network_segment(network['name'], body)
n1kvclient.update_network_segment(network['id'], body)
def _send_delete_network_request(self, context, network):
"""
@ -832,13 +845,13 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
n1kvclient = n1kv_client.Client()
session = context.session
if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_OVERLAY:
name = network['name'] + c_const.BRIDGE_DOMAIN_SUFFIX
name = network['id'] + c_const.BRIDGE_DOMAIN_SUFFIX
n1kvclient.delete_bridge_domain(name)
elif network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_TRUNK:
profile = self.get_network_profile(
context, network[n1kv_profile.PROFILE_ID])
if profile['sub_type'] == c_const.NETWORK_TYPE_OVERLAY:
profile_name = (network['name'] +
profile_name = (network['id'] +
c_const.ENCAPSULATION_PROFILE_SUFFIX)
n1kvclient.delete_encapsulation_profile(profile_name)
elif (network[providernet.NETWORK_TYPE] ==
@ -859,7 +872,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
profile_dict['delSegments'].append(mapping_dict)
n1kvclient.update_encapsulation_profile(context, profile,
profile_dict)
n1kvclient.delete_network_segment(network['name'])
n1kvclient.delete_network_segment(network['id'])
def _send_create_subnet_request(self, context, subnet):
"""
@ -869,11 +882,10 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
:param subnet: subnet dictionary
"""
LOG.debug(_('_send_create_subnet_request: %s'), subnet['id'])
network = self.get_network(context, subnet['network_id'])
n1kvclient = n1kv_client.Client()
n1kvclient.create_ip_pool(subnet)
body = {'ipPoolName': subnet['name']}
n1kvclient.update_network_segment(network['name'], body=body)
body = {'ipPool': subnet['id']}
n1kvclient.update_network_segment(subnet['network_id'], body=body)
def _send_delete_subnet_request(self, context, subnet):
"""
@ -883,11 +895,10 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
:param subnet: subnet dictionary
"""
LOG.debug(_('_send_delete_subnet_request: %s'), subnet['name'])
network = self.get_network(context, subnet['network_id'])
body = {'ipPoolName': subnet['name'], 'deleteSubnet': True}
body = {'ipPool': subnet['id'], 'deleteSubnet': True}
n1kvclient = n1kv_client.Client()
n1kvclient.update_network_segment(network['name'], body=body)
n1kvclient.delete_ip_pool(subnet['name'])
n1kvclient.update_network_segment(subnet['network_id'], body=body)
n1kvclient.delete_ip_pool(subnet['id'])
def _send_create_port_request(self, context, port):
"""
@ -908,7 +919,6 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
except cisco_exceptions.VMNetworkNotFound:
policy_profile = n1kv_db_v2.get_policy_profile(
context.session, port[n1kv_profile.PROFILE_ID])
network = self.get_network(context, port['network_id'])
vm_network_name = (c_const.VM_NETWORK_NAME_PREFIX +
str(port[n1kv_profile.PROFILE_ID]) +
"_" + str(port['network_id']))
@ -921,8 +931,7 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
n1kvclient = n1kv_client.Client()
n1kvclient.create_vm_network(port,
vm_network_name,
policy_profile,
network['name'])
policy_profile)
n1kvclient.create_n1kv_port(port, vm_network_name)
else:
vm_network_name = vm_network['name']
@ -994,7 +1003,6 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
(network_type, physical_network,
segmentation_id) = self._process_provider_create(context,
network['network'])
self._add_dummy_profile_only_if_testing(network)
profile_id = self._process_network_profile(context, network['network'])
segment_pairs = None
LOG.debug(_('Create network: profile_id=%s'), profile_id)
@ -1219,8 +1227,6 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
:param port: port dictionary
:returns: port object
"""
self._add_dummy_profile_only_if_testing(port)
if ('device_id' in port['port'] and port['port']['device_owner'] in
['network:dhcp', 'network:router_interface']):
p_profile_name = c_conf.CISCO_N1K.network_node_policy_profile
@ -1259,15 +1265,6 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
LOG.debug(_("Created port: %s"), pt)
return pt
def _add_dummy_profile_only_if_testing(self, obj):
"""
Method to be patched by the test_n1kv_plugin module to
inject n1kv:profile_id into the network/port object, since the plugin
tests for its existence. This method does not affect
the plugin code in any way.
"""
pass
def update_port(self, context, id, port):
"""
Update port parameters.
@ -1449,7 +1446,8 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
n1kv_db_v2.sync_vxlan_allocations(context.session,
self.vxlan_id_ranges)
try:
self._send_create_logical_network_request(_network_profile)
self._send_create_logical_network_request(_network_profile,
context.tenant_id)
except(cisco_exceptions.VSMError,
cisco_exceptions.VSMConnectionFailed):
super(N1kvNeutronPluginV2, self).delete_network_profile(
@ -1489,3 +1487,20 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
n1kv_db_v2.delete_vxlan_allocations(context.session,
self.delete_vxlan_ranges)
self._send_delete_network_profile_request(_network_profile)
def update_network_profile(self, context, net_profile_id, network_profile):
"""
Update a network profile.
:param context: neutron api request context
:param net_profile_id: UUID of the network profile to update
:param network_profile: dictionary containing network profile object
"""
session = context.session
with session.begin(subtransactions=True):
net_p = (super(N1kvNeutronPluginV2, self).
update_network_profile(context,
net_profile_id,
network_profile))
self._send_update_network_profile_request(net_p)
return net_p

View File

@ -18,16 +18,22 @@
# @author: Abhishek Raut, Cisco Systems Inc.
from mock import patch
import os
from oslo.config import cfg
from neutron.api.v2 import attributes
from neutron.common.test_lib import test_config
from neutron import context
import neutron.db.api as db
from neutron.plugins.cisco.db import n1kv_db_v2
from neutron.plugins.cisco.db import n1kv_models_v2
from neutron.plugins.cisco.db import network_db_v2 as cdb
from neutron.plugins.cisco import extensions
from neutron.plugins.cisco.extensions import n1kv_profile
from neutron.plugins.cisco.extensions import network_profile
from neutron.plugins.cisco.n1kv import n1kv_client
from neutron.plugins.cisco.n1kv import n1kv_neutron_plugin
from neutron.tests import base
from neutron.tests.unit import test_api_v2
from neutron.tests.unit import test_db_plugin as test_plugin
@ -51,41 +57,30 @@ class FakeResponse(object):
return self.buffer
def _fake_add_dummy_profile_for_test(self, obj):
"""
Replacement for a function in the N1KV neutron plugin module.
Since VSM is not available at the time of tests, we have no
policy profiles. Hence we inject a dummy policy/network profile into the
port/network object.
"""
dummy_profile_name = "dummy_profile"
dummy_tenant_id = "test-tenant"
db_session = db.get_session()
if 'port' in obj:
dummy_profile_id = "00000000-1111-1111-1111-000000000000"
self._add_policy_profile(dummy_profile_name,
dummy_profile_id,
dummy_tenant_id)
obj['port'][n1kv_profile.PROFILE_ID] = dummy_profile_id
elif 'network' in obj:
profile = {'name': 'dummy_profile',
'segment_type': 'vlan',
'physical_network': 'phsy1',
'segment_range': '3968-4047'}
self.network_vlan_ranges = {profile[
'physical_network']: [(3968, 4047)]}
n1kv_db_v2.sync_vlan_allocations(db_session, self.network_vlan_ranges)
np = n1kv_db_v2.create_network_profile(db_session, profile)
obj['network'][n1kv_profile.PROFILE_ID] = np.id
def _fake_setup_vsm(self):
"""Fake establish Communication with Cisco Nexus1000V VSM."""
self.agent_vsm = True
self._poll_policies(event_type="port_profile")
class NetworkProfileTestExtensionManager(object):
def get_resources(self):
# Add the resources to the global attribute map
# This is done here as the setup process won't
# initialize the main API router which extends
# the global attribute map
attributes.RESOURCE_ATTRIBUTE_MAP.update(
network_profile.RESOURCE_ATTRIBUTE_MAP)
return network_profile.Network_profile.get_resources()
def get_actions(self):
return []
def get_request_extensions(self):
return []
class N1kvPluginTestCase(test_plugin.NeutronDbPluginV2TestCase):
_plugin_name = ('neutron.plugins.cisco.n1kv.'
@ -96,31 +91,38 @@ class N1kvPluginTestCase(test_plugin.NeutronDbPluginV2TestCase):
DEFAULT_RESP_BODY = ""
DEFAULT_RESP_CODE = 200
DEFAULT_CONTENT_TYPE = ""
fmt = "json"
def _make_test_policy_profile(self, id):
"""Create a policy profile record for testing purpose."""
profile = {'id': id,
'name': 'TestGrizzlyPP'}
profile_obj = n1kv_db_v2.create_policy_profile(profile)
return profile_obj
def _make_test_policy_profile(self, name='service_profile'):
"""
Create a policy profile record for testing purpose.
def _make_test_profile(self):
"""Create a profile record for testing purposes."""
alloc_obj = n1kv_models_v2.N1kvVlanAllocation(physical_network='foo',
vlan_id=123)
alloc_obj.allocated = False
segment_range = "100-900"
segment_type = 'vlan'
physical_network = 'phys1'
profile_obj = n1kv_models_v2.NetworkProfile(
name="test_np",
segment_type=segment_type,
segment_range=segment_range,
physical_network=physical_network)
session = db.get_session()
session.add(profile_obj)
session.flush()
return profile_obj
:param name: string representing the name of the policy profile to
create. Default argument value chosen to correspond to the
default name specified in config.py file.
"""
uuid = test_api_v2._uuid()
profile = {'id': uuid,
'name': name}
return n1kv_db_v2.create_policy_profile(profile)
def _make_test_profile(self, name='default_network_profile'):
"""
Create a profile record for testing purposes.
:param name: string representing the name of the network profile to
create. Default argument value chosen to correspond to the
default name specified in config.py file.
"""
db_session = db.get_session()
profile = {'name': name,
'segment_type': 'vlan',
'physical_network': 'phsy1',
'segment_range': '3968-4047'}
self.network_vlan_ranges = {profile[
'physical_network']: [(3968, 4047)]}
n1kv_db_v2.sync_vlan_allocations(db_session, self.network_vlan_ranges)
return n1kv_db_v2.create_network_profile(db_session, profile)
def setUp(self):
"""
@ -199,24 +201,39 @@ class N1kvPluginTestCase(test_plugin.NeutronDbPluginV2TestCase):
fake_get_cred_name.return_value = {"user_name": "admin",
"password": "admin_password"}
# Patch a dummy profile creation into the N1K plugin code. The original
# function in the plugin is a noop for production, but during test, we
# need it to return a dummy network profile.
(n1kv_neutron_plugin.N1kvNeutronPluginV2.
_add_dummy_profile_only_if_testing) = _fake_add_dummy_profile_for_test
n1kv_neutron_plugin.N1kvNeutronPluginV2._setup_vsm = _fake_setup_vsm
test_config['plugin_name_v2'] = self._plugin_name
cfg.CONF.set_override('api_extensions_path',
os.path.dirname(extensions.__file__))
self.addCleanup(cfg.CONF.reset)
ext_mgr = NetworkProfileTestExtensionManager()
test_config['extension_manager'] = ext_mgr
self.addCleanup(self.restore_test_config)
# Save the original RESOURCE_ATTRIBUTE_MAP
self.saved_attr_map = {}
for resource, attrs in attributes.RESOURCE_ATTRIBUTE_MAP.items():
self.saved_attr_map[resource] = attrs.copy()
# Update the RESOURCE_ATTRIBUTE_MAP with n1kv specific extended attrs.
attributes.RESOURCE_ATTRIBUTE_MAP["networks"].update(
n1kv_profile.EXTENDED_ATTRIBUTES_2_0["networks"])
attributes.RESOURCE_ATTRIBUTE_MAP["ports"].update(
n1kv_profile.EXTENDED_ATTRIBUTES_2_0["ports"])
self.addCleanup(self.restore_resource_attribute_map)
self.addCleanup(db.clear_db)
super(N1kvPluginTestCase, self).setUp(self._plugin_name)
# Create some of the database entries that we require.
profile_obj = self._make_test_profile()
policy_profile_obj = (self._make_test_policy_profile(
'41548d21-7f89-4da0-9131-3d4fd4e8BBB8'))
# Additional args for create_network(), create_port(), etc.
self.more_args = {
"network": {"n1kv:profile_id": profile_obj.id},
"port": {"n1kv:profile_id": policy_profile_obj.id}
}
self._make_test_profile()
self._make_test_policy_profile()
def restore_resource_attribute_map(self):
# Restore the original RESOURCE_ATTRIBUTE_MAP
attributes.RESOURCE_ATTRIBUTE_MAP = self.saved_attr_map
def restore_test_config(self):
# Restore the original test_config
del test_config['plugin_name_v2']
def test_plugin(self):
self._make_network('json',
@ -233,6 +250,56 @@ class N1kvPluginTestCase(test_plugin.NeutronDbPluginV2TestCase):
self.assertIn('tenant_id', body['networks'][0])
class TestN1kvNetworkProfiles(N1kvPluginTestCase):
def _prepare_net_profile_data(self, segment_type):
netp = {'network_profile': {'name': 'netp1',
'segment_type': segment_type,
'tenant_id': self.tenant_id}}
if segment_type == 'vlan':
netp['network_profile']['segment_range'] = '100-200'
netp['network_profile']['physical_network'] = 'phys1'
elif segment_type == 'overlay':
netp['network_profile']['segment_range'] = '10000-10010'
netp['network_profile']['sub_type'] = 'enhanced'
return netp
def test_create_network_profile_plugin(self):
data = self._prepare_net_profile_data('vlan')
net_p_req = self.new_create_request('network_profiles', data)
res = net_p_req.get_response(self.ext_api)
self.assertEqual(res.status_int, 201)
def test_update_network_profile_physical_network_fail(self):
net_p = self._make_test_profile(name='netp1')
data = {'network_profile': {'physical_network': 'some-phys-net'}}
net_p_req = self.new_update_request('network_profiles',
data,
net_p['id'])
res = net_p_req.get_response(self.ext_api)
self.assertEqual(res.status_int, 400)
def test_update_network_profile_segment_type_fail(self):
net_p = self._make_test_profile(name='netp1')
data = {'network_profile': {'segment_type': 'overlay'}}
net_p_req = self.new_update_request('network_profiles',
data,
net_p['id'])
res = net_p_req.get_response(self.ext_api)
self.assertEqual(res.status_int, 400)
def test_update_network_profile_sub_type_fail(self):
net_p_dict = self._prepare_net_profile_data('overlay')
net_p_req = self.new_create_request('network_profiles', net_p_dict)
net_p = self.deserialize(self.fmt,
net_p_req.get_response(self.ext_api))
data = {'network_profile': {'sub_type': 'vlan'}}
update_req = self.new_update_request('network_profiles',
data,
net_p['network_profile']['id'])
update_res = update_req.get_response(self.ext_api)
self.assertEqual(update_res.status_int, 400)
class TestN1kvBasicGet(test_plugin.TestBasicGet,
N1kvPluginTestCase):
@ -248,61 +315,76 @@ class TestN1kvHTTPResponse(test_plugin.TestV2HTTPResponse,
class TestN1kvPorts(test_plugin.TestPortsV2,
N1kvPluginTestCase):
def _make_other_tenant_profile(self):
"""Underlying test uses other tenant Id for tests."""
profile_obj = self._make_test_profile()
policy_profile_obj = self._make_test_policy_profile(
'41548d21-7f89-4da0-9131-3d4fd4e8BBB9')
self.more_args = {
"network": {"n1kv:profile_id": profile_obj.id},
"port": {"n1kv:profile_id": policy_profile_obj.id}
}
def test_create_port_with_default_n1kv_profile_id(self):
"""Test port create without passing policy profile id."""
with self.port() as port:
db_session = db.get_session()
pp = n1kv_db_v2.get_policy_profile(
db_session, port['port'][n1kv_profile.PROFILE_ID])
self.assertEqual(pp['name'], 'service_profile')
def test_create_port_public_network(self):
# The underlying test function needs a profile for a different tenant.
self._make_other_tenant_profile()
super(TestN1kvPorts, self).test_create_port_public_network()
def test_create_port_with_n1kv_profile_id(self):
"""Test port create with policy profile id."""
profile_obj = self._make_test_policy_profile(name='test_profile')
with self.network() as network:
data = {'port': {n1kv_profile.PROFILE_ID: profile_obj.id,
'tenant_id': self.tenant_id,
'network_id': network['network']['id']}}
port_req = self.new_create_request('ports', data)
port = self.deserialize(self.fmt,
port_req.get_response(self.api))
self.assertEqual(port['port'][n1kv_profile.PROFILE_ID],
profile_obj.id)
self._delete('ports', port['port']['id'])
def test_create_port_public_network_with_ip(self):
# The underlying test function needs a profile for a different tenant.
self._make_other_tenant_profile()
super(TestN1kvPorts, self).test_create_port_public_network_with_ip()
def test_create_ports_bulk_emulated(self):
# The underlying test function needs a profile for a different tenant.
self._make_other_tenant_profile()
super(TestN1kvPorts,
self).test_create_ports_bulk_emulated()
def test_create_ports_bulk_emulated_plugin_failure(self):
# The underlying test function needs a profile for a different tenant.
self._make_other_tenant_profile()
super(TestN1kvPorts,
self).test_create_ports_bulk_emulated_plugin_failure()
def test_delete_port_public_network(self):
self._make_other_tenant_profile()
super(TestN1kvPorts, self).test_delete_port_public_network()
def test_update_port_with_n1kv_profile_id(self):
"""Test port update failure while updating policy profile id."""
with self.port() as port:
data = {'port': {n1kv_profile.PROFILE_ID: 'some-profile-uuid'}}
port_req = self.new_update_request('ports',
data,
port['port']['id'])
res = port_req.get_response(self.api)
# Port update should fail to update policy profile id.
self.assertEqual(res.status_int, 400)
class TestN1kvNetworks(test_plugin.TestNetworksV2,
N1kvPluginTestCase):
_default_tenant = "somebody_else" # Tenant-id determined by underlying
# DB-plugin test cases. Need to use this
# one for profile creation
def _prepare_net_data(self, net_profile_id):
return {'network': {'name': 'net1',
n1kv_profile.PROFILE_ID: net_profile_id,
'tenant_id': self.tenant_id}}
def test_update_network_set_not_shared_single_tenant(self):
# The underlying test function needs a profile for a different tenant.
profile_obj = self._make_test_profile()
policy_profile_obj = self._make_test_policy_profile(
'41548d21-7f89-4da0-9131-3d4fd4e8BBB9')
self.more_args = {
"network": {"n1kv:profile_id": profile_obj.id},
"port": {"n1kv:profile_id": policy_profile_obj.id}
}
super(TestN1kvNetworks,
self).test_update_network_set_not_shared_single_tenant()
def test_create_network_with_default_n1kv_profile_id(self):
"""Test network create without passing network profile id."""
with self.network() as network:
db_session = db.get_session()
np = n1kv_db_v2.get_network_profile(
db_session, network['network'][n1kv_profile.PROFILE_ID])
self.assertEqual(np['name'], 'default_network_profile')
def test_create_network_with_n1kv_profile_id(self):
"""Test network create with network profile id."""
profile_obj = self._make_test_profile(name='test_profile')
data = self._prepare_net_data(profile_obj.id)
network_req = self.new_create_request('networks', data)
network = self.deserialize(self.fmt,
network_req.get_response(self.api))
self.assertEqual(network['network'][n1kv_profile.PROFILE_ID],
profile_obj.id)
def test_update_network_with_n1kv_profile_id(self):
"""Test network update failure while updating network profile id."""
with self.network() as network:
data = {'network': {n1kv_profile.PROFILE_ID: 'some-profile-uuid'}}
network_req = self.new_update_request('networks',
data,
network['network']['id'])
res = network_req.get_response(self.api)
# Network update should fail to update network profile id.
self.assertEqual(res.status_int, 400)
class TestN1kvNonDbTest(base.BaseTestCase):