Merge "Delete VLAN on delete_vserver in Netapp cmode" into stable/mitaka

This commit is contained in:
Jenkins 2016-09-13 18:19:25 +00:00 committed by Gerrit Code Review
commit ba7512f7ed
7 changed files with 189 additions and 18 deletions

View File

@ -17,6 +17,7 @@
import copy
import hashlib
import re
import time
from oslo_log import log
@ -522,6 +523,34 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
msg_args = {'vlan': vlan, 'port': port, 'err_msg': e.message}
raise exception.NetAppException(msg % msg_args)
@na_utils.trace
def delete_vlan(self, node, port, vlan):
try:
api_args = {
'vlan-info': {
'parent-interface': port,
'node': node,
'vlanid': vlan,
},
}
self.send_request('net-vlan-delete', api_args)
except netapp_api.NaApiError as e:
p = re.compile('port already has a lif bound.*', re.IGNORECASE)
if (e.code == netapp_api.EAPIERROR and re.match(p, e.message)):
LOG.debug('VLAN %(vlan)s on port %(port)s node %(node)s '
'still used by LIF and cannot be deleted.',
{'vlan': vlan, 'port': port, 'node': node})
else:
msg = _('Failed to delete VLAN %(vlan)s on '
'port %(port)s node %(node)s: %(err_msg)s')
msg_args = {
'vlan': vlan,
'port': port,
'node': node,
'err_msg': e.message
}
raise exception.NetAppException(msg % msg_args)
@na_utils.trace
def _ensure_broadcast_domain_for_port(self, node, port,
domain=DEFAULT_BROADCAST_DOMAIN,

View File

@ -107,19 +107,26 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
@na_utils.trace
def setup_server(self, network_info, metadata=None):
"""Creates and configures new Vserver."""
LOG.debug('Creating server %s', network_info['server_id'])
self._validate_network_type(network_info)
vserver_name = self._get_vserver_name(network_info['server_id'])
server_details = {'vserver_name': vserver_name}
vlan = network_info['segmentation_id']
try:
self._create_vserver(vserver_name, network_info)
except Exception as e:
e.detail_data = {'server_details': server_details}
raise
@utils.synchronized('netapp-VLAN-%s' % vlan, external=True)
def setup_server_with_lock():
LOG.debug('Creating server %s', network_info['server_id'])
self._validate_network_type(network_info)
return server_details
vserver_name = self._get_vserver_name(network_info['server_id'])
server_details = {'vserver_name': vserver_name}
try:
self._create_vserver(vserver_name, network_info)
except Exception as e:
e.detail_data = {'server_details': server_details}
raise
return server_details
return setup_server_with_lock()
@na_utils.trace
def _validate_network_type(self, network_info):
@ -311,10 +318,34 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
ipspace_name = self._client.get_vserver_ipspace(vserver)
vserver_client = self._get_api_client(vserver=vserver)
self._client.delete_vserver(vserver,
vserver_client,
security_services=security_services)
network_interfaces = vserver_client.get_network_interfaces()
if ipspace_name and not self._client.ipspace_has_data_vservers(
ipspace_name):
self._client.delete_ipspace(ipspace_name)
home_port = network_interfaces[0]['home-port']
vlan = home_port.split('-')[1]
@utils.synchronized('netapp-VLAN-%s' % vlan, external=True)
def _delete_vserver_with_lock():
self._client.delete_vserver(vserver,
vserver_client,
security_services=security_services)
if ipspace_name and not self._client.ipspace_has_data_vservers(
ipspace_name):
self._client.delete_ipspace(ipspace_name)
self._delete_vserver_vlan(network_interfaces)
return _delete_vserver_with_lock()
@na_utils.trace
def _delete_vserver_vlan(self, vserver_network_interfaces):
"""Delete Vserver's VLAN configuration from ports"""
for interface in vserver_network_interfaces:
try:
home_port = interface['home-port']
port, vlan = home_port.split('-')
node = interface['home-node']
self._client.delete_vlan(node, port, vlan)
except exception.NetAppException:
LOG.exception(_LE("Deleting Vserver VLAN failed."))

View File

@ -82,6 +82,15 @@ SM_SOURCE_VOLUME = 'fake_source_volume'
SM_DEST_VSERVER = 'fake_destination_vserver'
SM_DEST_VOLUME = 'fake_destination_volume'
NETWORK_INTERFACES = [{
'interface_name': 'fake_interface',
'address': IP_ADDRESS,
'vserver': VSERVER_NAME,
'netmask': NETMASK,
'role': 'data',
'home-node': NODE_NAME,
'home-port': VLAN_PORT
}]
IPSPACES = [{
'uuid': 'fake_uuid',

View File

@ -61,8 +61,9 @@ class NetAppClientCmodeTestCase(test.TestCase):
self.vserver_client.set_vserver(fake.VSERVER_NAME)
self.vserver_client.connection = mock.MagicMock()
def _mock_api_error(self, code='fake'):
return mock.Mock(side_effect=netapp_api.NaApiError(code=code))
def _mock_api_error(self, code='fake', message='fake'):
return mock.Mock(side_effect=netapp_api.NaApiError(code=code,
message=message))
def test_init_features_ontapi_1_21(self):
@ -932,6 +933,53 @@ class NetAppClientCmodeTestCase(test.TestCase):
fake.PORT,
fake.VLAN)
def test_delete_vlan(self):
self.mock_object(self.client, 'send_request')
vlan_delete_args = {
'vlan-info': {
'parent-interface': fake.PORT,
'node': fake.NODE_NAME,
'vlanid': fake.VLAN
}
}
self.client.delete_vlan(fake.NODE_NAME, fake.PORT, fake.VLAN)
self.client.send_request.assert_has_calls([
mock.call('net-vlan-delete', vlan_delete_args)])
def test_delete_vlan_still_used(self):
self.mock_object(self.client,
'send_request',
self._mock_api_error(code=netapp_api.EAPIERROR,
message='Port already has a '
'lif bound. '))
vlan_delete_args = {
'vlan-info': {
'parent-interface': fake.PORT,
'node': fake.NODE_NAME,
'vlanid': fake.VLAN
}
}
self.client.delete_vlan(fake.NODE_NAME, fake.PORT, fake.VLAN)
self.client.send_request.assert_has_calls([
mock.call('net-vlan-delete', vlan_delete_args)])
self.assertEqual(1, client_cmode.LOG.debug.call_count)
def test_delete_vlan_api_error(self):
self.mock_object(self.client, 'send_request', self._mock_api_error())
self.assertRaises(exception.NetAppException,
self.client.delete_vlan,
fake.NODE_NAME,
fake.PORT,
fake.VLAN)
def test_ensure_broadcast_domain_for_port_domain_match(self):
port_info = {

View File

@ -28,6 +28,7 @@ from manila.share.drivers.netapp.dataontap.cluster_mode import lib_base
from manila.share.drivers.netapp.dataontap.cluster_mode import lib_multi_svm
from manila.share.drivers.netapp import utils as na_utils
from manila import test
from manila.tests.share.drivers.netapp.dataontap.client import fakes as c_fake
from manila.tests.share.drivers.netapp.dataontap import fakes as fake
@ -649,6 +650,11 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
self.mock_object(self.library,
'_get_api_client',
mock.Mock(return_value=vserver_client))
mock_delete_vserver_vlan = self.mock_object(self.library,
'_delete_vserver_vlan')
self.mock_object(vserver_client,
'get_network_interfaces',
mock.Mock(return_value=c_fake.NETWORK_INTERFACES))
security_services = fake.NETWORK_INFO['security_services']
self.library._delete_vserver(fake.VSERVER1,
@ -659,6 +665,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
self.library._client.delete_vserver.assert_called_once_with(
fake.VSERVER1, vserver_client, security_services=security_services)
self.assertFalse(self.library._client.delete_ipspace.called)
mock_delete_vserver_vlan.assert_called_once_with(
c_fake.NETWORK_INTERFACES)
def test_delete_vserver_ipspace_has_data_vservers(self):
@ -672,6 +680,11 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
self.mock_object(self.library._client,
'ipspace_has_data_vservers',
mock.Mock(return_value=True))
mock_delete_vserver_vlan = self.mock_object(self.library,
'_delete_vserver_vlan')
self.mock_object(vserver_client,
'get_network_interfaces',
mock.Mock(return_value=c_fake.NETWORK_INTERFACES))
security_services = fake.NETWORK_INFO['security_services']
self.library._delete_vserver(fake.VSERVER1,
@ -682,6 +695,8 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
self.library._client.delete_vserver.assert_called_once_with(
fake.VSERVER1, vserver_client, security_services=security_services)
self.assertFalse(self.library._client.delete_ipspace.called)
mock_delete_vserver_vlan.assert_called_once_with(
c_fake.NETWORK_INTERFACES)
def test_delete_vserver_with_ipspace(self):
@ -695,6 +710,12 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
self.mock_object(self.library._client,
'ipspace_has_data_vservers',
mock.Mock(return_value=False))
mock_delete_vserver_vlan = self.mock_object(self.library,
'_delete_vserver_vlan')
self.mock_object(vserver_client,
'get_network_interfaces',
mock.Mock(return_value=c_fake.NETWORK_INTERFACES))
security_services = fake.NETWORK_INFO['security_services']
self.library._delete_vserver(fake.VSERVER1,
@ -706,3 +727,32 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
fake.VSERVER1, vserver_client, security_services=security_services)
self.library._client.delete_ipspace.assert_called_once_with(
fake.IPSPACE)
mock_delete_vserver_vlan.assert_called_once_with(
c_fake.NETWORK_INTERFACES)
def test_delete_vserver_vlan(self):
self.library._delete_vserver_vlan(c_fake.NETWORK_INTERFACES)
for interface in c_fake.NETWORK_INTERFACES:
home_port = interface['home-port']
port, vlan = home_port.split('-')
node = interface['home-node']
self.library._client.delete_vlan.assert_called_once_with(
node, port, vlan)
def test_delete_vserver_vlan_client_error(self):
mock_exception_log = self.mock_object(lib_multi_svm.LOG, 'exception')
self.mock_object(
self.library._client,
'delete_vlan',
mock.Mock(side_effect=exception.NetAppException("fake error")))
self.library._delete_vserver_vlan(c_fake.NETWORK_INTERFACES)
for interface in c_fake.NETWORK_INTERFACES:
home_port = interface['home-port']
port, vlan = home_port.split('-')
node = interface['home-node']
self.library._client.delete_vlan.assert_called_once_with(
node, port, vlan)
self.assertEqual(1, mock_exception_log.call_count)

View File

@ -247,6 +247,7 @@ NETWORK_INFO = {
'network_allocations': USER_NETWORK_ALLOCATIONS,
'admin_network_allocations': ADMIN_NETWORK_ALLOCATIONS,
'neutron_subnet_id': '62bf1c2c-18eb-421b-8983-48a6d39aafe0',
'segmentation_id': '1000',
}
NETWORK_INFO_NETMASK = '255.255.255.0'

View File

@ -0,0 +1,3 @@
---
features:
- NetApp cMode driver - configured VLAN will be deleted on Vserver removal