diff --git a/neutron/plugins/cisco/common/cisco_constants.py b/neutron/plugins/cisco/common/cisco_constants.py index ca2b8b8ddb..3b0d59b056 100644 --- a/neutron/plugins/cisco/common/cisco_constants.py +++ b/neutron/plugins/cisco/common/cisco_constants.py @@ -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 diff --git a/neutron/plugins/cisco/db/n1kv_db_v2.py b/neutron/plugins/cisco/db/n1kv_db_v2.py index 8fe347de77..7cf36d0d09 100644 --- a/neutron/plugins/cisco/db/n1kv_db_v2.py +++ b/neutron/plugins/cisco/db/n1kv_db_v2.py @@ -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) diff --git a/neutron/plugins/cisco/extensions/n1kv_profile.py b/neutron/plugins/cisco/extensions/n1kv_profile.py index fdf89e2a38..58287b0988 100644 --- a/neutron/plugins/cisco/extensions/n1kv_profile.py +++ b/neutron/plugins/cisco/extensions/n1kv_profile.py @@ -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} diff --git a/neutron/plugins/cisco/extensions/network_profile.py b/neutron/plugins/cisco/extensions/network_profile.py index aef5c925f9..64795c1062 100644 --- a/neutron/plugins/cisco/extensions/network_profile.py +++ b/neutron/plugins/cisco/extensions/network_profile.py @@ -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': ''}, diff --git a/neutron/plugins/cisco/n1kv/n1kv_client.py b/neutron/plugins/cisco/n1kv/n1kv_client.py index 1334b161ac..f6efd6b5e0 100644 --- a/neutron/plugins/cisco/n1kv/n1kv_client.py +++ b/neutron/plugins/cisco/n1kv/n1kv_client.py @@ -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) diff --git a/neutron/plugins/cisco/n1kv/n1kv_neutron_plugin.py b/neutron/plugins/cisco/n1kv/n1kv_neutron_plugin.py index 896ce0ffe6..f2b9149aec 100644 --- a/neutron/plugins/cisco/n1kv/n1kv_neutron_plugin.py +++ b/neutron/plugins/cisco/n1kv/n1kv_neutron_plugin.py @@ -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 diff --git a/neutron/tests/unit/cisco/n1kv/test_n1kv_plugin.py b/neutron/tests/unit/cisco/n1kv/test_n1kv_plugin.py index e40cab0889..a3b43e806a 100644 --- a/neutron/tests/unit/cisco/n1kv/test_n1kv_plugin.py +++ b/neutron/tests/unit/cisco/n1kv/test_n1kv_plugin.py @@ -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):