From: Abhishek Raut Date: Thu, 3 Oct 2013 06:32:02 +0000 (-0700) Subject: Update Cisco N1KV plugin to VSM REST api calls X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=ba242d91c54b36628e03332a91adfef40e32ac32;p=openstack-build%2Fneutron-build.git 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 --- diff --git a/neutron/plugins/cisco/common/cisco_constants.py b/neutron/plugins/cisco/common/cisco_constants.py index ca2b8b8dd..3b0d59b05 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 8fe347de7..7cf36d0d0 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 fdf89e2a3..58287b098 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 aef5c925f..64795c106 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 1334b161a..f6efd6b5e 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 896ce0ffe..f2b9149ae 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 e40cab088..a3b43e806 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, name='service_profile'): + """ + Create a policy profile record for testing purpose. - 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_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_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_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_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_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_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 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 _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_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):