Implement IPv6 support for Dell EMC VNX driver
Major changes: * Support to create/delete/extend/access NFS and CIFS share/snapshot in the IPv6 network which created by Neutron * Support to connect VNX management interface using IPv6 address Change-Id: Ibe7620f9548d5f57780e49c08214dc627b91a945 Implements: blueprint vnx-manila-ipv6-support
This commit is contained in:
parent
c8cceebf8e
commit
e691879fcf
|
@ -189,6 +189,7 @@ for the VNX driver:
|
||||||
emc_nas_pool_name = <pool name>
|
emc_nas_pool_name = <pool name>
|
||||||
emc_interface_ports = <Comma separated ports list>
|
emc_interface_ports = <Comma separated ports list>
|
||||||
share_driver = manila.share.drivers.dell_emc.driver.EMCShareDriver
|
share_driver = manila.share.drivers.dell_emc.driver.EMCShareDriver
|
||||||
|
driver_handles_share_servers = True
|
||||||
|
|
||||||
- `emc_share_backend` is the plugin name. Set it to `vnx` for the VNX driver.
|
- `emc_share_backend` is the plugin name. Set it to `vnx` for the VNX driver.
|
||||||
- `emc_nas_server` is the control station IP address of the VNX system to be
|
- `emc_nas_server` is the control station IP address of the VNX system to be
|
||||||
|
@ -204,10 +205,36 @@ for the VNX driver:
|
||||||
Members of the list can be Unix-style glob expressions (supports Unix shell-style
|
Members of the list can be Unix-style glob expressions (supports Unix shell-style
|
||||||
wildcards). This list is optional. In the absence of this option, any of the ports
|
wildcards). This list is optional. In the absence of this option, any of the ports
|
||||||
on the Data Mover can be used.
|
on the Data Mover can be used.
|
||||||
|
- `driver_handles_share_servers` must be True, the driver will choose a port
|
||||||
|
from port list which configured in emc_interface_ports.
|
||||||
|
|
||||||
Restart of :term:`manila-share` service is needed for the configuration changes to take
|
Restart of :term:`manila-share` service is needed for the configuration changes to take
|
||||||
effect.
|
effect.
|
||||||
|
|
||||||
|
IPv6 support
|
||||||
|
------------
|
||||||
|
|
||||||
|
IPv6 support for VNX driver is introduced in Queens release. The feature is divided
|
||||||
|
into two parts:
|
||||||
|
|
||||||
|
1. The driver is able to manage share or snapshot in the Neutron IPv6 network.
|
||||||
|
2. The driver is able to connect VNX management interface using its IPv6 address.
|
||||||
|
|
||||||
|
Pre-Configurations for IPv6 support
|
||||||
|
===================================
|
||||||
|
|
||||||
|
The following parameters need to be configured in `/etc/manila/manila.conf`
|
||||||
|
for the VNX driver:
|
||||||
|
|
||||||
|
network_plugin_ipv6_enabled = True
|
||||||
|
|
||||||
|
- `network_plugin_ipv6_enabled` indicates IPv6 is enabled.
|
||||||
|
|
||||||
|
If you want to connect VNX using IPv6 address, you should configure IPv6 address
|
||||||
|
by `nas_cs` command for VNX and specify the address in `/etc/manila/manila.conf`:
|
||||||
|
|
||||||
|
emc_nas_server = <IPv6 address>
|
||||||
|
|
||||||
Restrictions
|
Restrictions
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,7 @@ Mapping of share drivers and share access rules support
|
||||||
+----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
|
+----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
|
||||||
| EMC VMAX | NFS (O) | \- | CIFS (O) | \- | \- | NFS (O) | \- | CIFS (O) | \- | \- |
|
| EMC VMAX | NFS (O) | \- | CIFS (O) | \- | \- | NFS (O) | \- | CIFS (O) | \- | \- |
|
||||||
+----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
|
+----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
|
||||||
| EMC VNX | NFS (J) | \- | CIFS (J) | \- | \- | NFS (L) | \- | CIFS (L) | \- | \- |
|
| EMC VNX | NFS (J) | NFS (Q) | CIFS (J) | \- | \- | NFS (L) | NFS (Q) | CIFS (L) | \- | \- |
|
||||||
+----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
|
+----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
|
||||||
| EMC Unity | NFS (N) | \- | CIFS (N) | \- | \- | NFS (N) | \- | CIFS (N) | \- | \- |
|
| EMC Unity | NFS (N) | \- | CIFS (N) | \- | \- | NFS (N) | \- | CIFS (N) | \- | \- |
|
||||||
+----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
|
+----------------------------------------+--------------+--------------+----------------+------------+--------------+--------------+--------------+----------------+------------+------------+
|
||||||
|
@ -224,7 +224,7 @@ More information: :ref:`capabilities_and_extra_specs`
|
||||||
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+
|
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+
|
||||||
| EMC VMAX | O | \- | \- | \- | \- | O | \- | O | \- | \- | P | \- |
|
| EMC VMAX | O | \- | \- | \- | \- | O | \- | O | \- | \- | P | \- |
|
||||||
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+
|
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+
|
||||||
| EMC VNX | J | \- | \- | \- | \- | L | \- | J | \- | \- | P | \- |
|
| EMC VNX | J | \- | \- | \- | \- | L | \- | J | \- | \- | P | Q |
|
||||||
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+
|
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+
|
||||||
| EMC Unity | N | \- | \- | \- | N | \- | \- | N | \- | \- | P | \- |
|
| EMC Unity | N | \- | \- | \- | N | \- | \- | N | \- | \- | P | \- |
|
||||||
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+
|
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+
|
||||||
|
|
|
@ -35,7 +35,8 @@ LOG = log.getLogger(__name__)
|
||||||
class XMLAPIConnector(object):
|
class XMLAPIConnector(object):
|
||||||
def __init__(self, configuration, debug=True):
|
def __init__(self, configuration, debug=True):
|
||||||
super(XMLAPIConnector, self).__init__()
|
super(XMLAPIConnector, self).__init__()
|
||||||
self.storage_ip = configuration.emc_nas_server
|
self.storage_ip = enas_utils.convert_ipv6_format_if_needed(
|
||||||
|
configuration.emc_nas_server)
|
||||||
self.username = configuration.emc_nas_login
|
self.username = configuration.emc_nas_login
|
||||||
self.password = configuration.emc_nas_password
|
self.password = configuration.emc_nas_password
|
||||||
self.debug = debug
|
self.debug = debug
|
||||||
|
|
|
@ -18,6 +18,7 @@ import types
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
from oslo_utils import fnmatch
|
from oslo_utils import fnmatch
|
||||||
|
from oslo_utils import netutils
|
||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
import ssl
|
import ssl
|
||||||
|
|
||||||
|
@ -103,3 +104,78 @@ def create_ssl_context(configuration):
|
||||||
'version of Python, ssl verification is disabled.')
|
'version of Python, ssl verification is disabled.')
|
||||||
context = None
|
context = None
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
def parse_ipaddr(text):
|
||||||
|
"""Parse the output of VNX server_export command, get IPv4/IPv6 addresses.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
input: 192.168.100.102:[fdf8:f53b:82e4::57]:[fdf8:f53b:82e4::54]
|
||||||
|
output: ['192.168.100.102', '[fdf8:f53b:82e4::57]', '[fdf8:f53b:82e4::54]']
|
||||||
|
|
||||||
|
:param text: The output of VNX server_export command.
|
||||||
|
:return: The list of IPv4/IPv6 addresses. The IPv6 address enclosed by [].
|
||||||
|
"""
|
||||||
|
rst = []
|
||||||
|
stk = []
|
||||||
|
|
||||||
|
ipaddr = ''
|
||||||
|
it = iter(text)
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
i = next(it)
|
||||||
|
if i == ':' and not stk and ipaddr:
|
||||||
|
rst.append(ipaddr)
|
||||||
|
ipaddr = ''
|
||||||
|
elif i == ':' and not ipaddr:
|
||||||
|
continue
|
||||||
|
elif i == '[':
|
||||||
|
stk.append(i)
|
||||||
|
elif i == ']':
|
||||||
|
rst.append('[%s]' % ipaddr)
|
||||||
|
stk.pop()
|
||||||
|
ipaddr = ''
|
||||||
|
else:
|
||||||
|
ipaddr += i
|
||||||
|
except StopIteration:
|
||||||
|
if ipaddr:
|
||||||
|
rst.append(ipaddr)
|
||||||
|
|
||||||
|
return rst
|
||||||
|
|
||||||
|
|
||||||
|
def convert_ipv6_format_if_needed(ip_addr):
|
||||||
|
"""Convert IPv6 address format if needed. The IPv6 address enclosed by [].
|
||||||
|
|
||||||
|
For the invalid IPv6 cidr, its format will not be changed.
|
||||||
|
|
||||||
|
:param ip_addr: IPv6 address.
|
||||||
|
:return: Converted IPv6 address.
|
||||||
|
"""
|
||||||
|
if netutils.is_valid_ipv6_cidr(ip_addr):
|
||||||
|
ip_addr = '[%s]' % ip_addr
|
||||||
|
return ip_addr
|
||||||
|
|
||||||
|
|
||||||
|
def export_unc_path(ip_addr):
|
||||||
|
"""Convert IPv6 address to valid UNC path.
|
||||||
|
|
||||||
|
In Microsoft Windows OS, UNC (Uniform Naming Convention) specifies a
|
||||||
|
common syntax to describe the location of a network resource.
|
||||||
|
|
||||||
|
The colon which used by IPv6 is an illegal character in a UNC path name.
|
||||||
|
So the IPv6 address need to be converted to valid UNC path.
|
||||||
|
|
||||||
|
References:
|
||||||
|
- https://en.wikipedia.org/wiki/IPv6_address
|
||||||
|
#Literal_IPv6_addresses_in_UNC_path_names
|
||||||
|
- https://en.wikipedia.org/wiki/Path_(computing)#Uniform_Naming_Convention
|
||||||
|
|
||||||
|
:param ip_addr: IPv6 address.
|
||||||
|
:return: UNC path.
|
||||||
|
"""
|
||||||
|
unc_suffix = '.ipv6-literal.net'
|
||||||
|
if netutils.is_valid_ipv6(ip_addr):
|
||||||
|
ip_addr = ip_addr.replace(':', '-') + unc_suffix
|
||||||
|
return ip_addr
|
||||||
|
|
|
@ -78,6 +78,9 @@ class EMCShareDriver(driver.ShareDriver):
|
||||||
super(EMCShareDriver, self).__init__(
|
super(EMCShareDriver, self).__init__(
|
||||||
self.plugin.driver_handles_share_servers, *args, **kwargs)
|
self.plugin.driver_handles_share_servers, *args, **kwargs)
|
||||||
|
|
||||||
|
if hasattr(self.plugin, 'ipv6_implemented'):
|
||||||
|
self.ipv6_implemented = self.plugin.ipv6_implemented
|
||||||
|
|
||||||
def create_share(self, context, share, share_server=None):
|
def create_share(self, context, share, share_server=None):
|
||||||
"""Is called to create share."""
|
"""Is called to create share."""
|
||||||
location = self.plugin.create_share(context, share, share_server)
|
location = self.plugin.create_share(context, share, share_server)
|
||||||
|
@ -159,3 +162,9 @@ class EMCShareDriver(driver.ShareDriver):
|
||||||
def _teardown_server(self, server_details, security_services=None):
|
def _teardown_server(self, server_details, security_services=None):
|
||||||
"""Teardown share server."""
|
"""Teardown share server."""
|
||||||
return self.plugin.teardown_server(server_details, security_services)
|
return self.plugin.teardown_server(server_details, security_services)
|
||||||
|
|
||||||
|
def get_configured_ip_versions(self):
|
||||||
|
if self.ipv6_implemented:
|
||||||
|
return [4, 6]
|
||||||
|
else:
|
||||||
|
return [4]
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
import random
|
import random
|
||||||
|
import six
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
|
@ -37,8 +38,9 @@ from manila import utils
|
||||||
2.0.0 - Bumped the version for Mitaka
|
2.0.0 - Bumped the version for Mitaka
|
||||||
3.0.0 - Bumped the version for Ocata
|
3.0.0 - Bumped the version for Ocata
|
||||||
4.0.0 - Bumped the version for Pike
|
4.0.0 - Bumped the version for Pike
|
||||||
|
5.0.0 - Bumped the version for Queens
|
||||||
"""
|
"""
|
||||||
VERSION = "4.0.0"
|
VERSION = "5.0.0"
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -79,6 +81,7 @@ class VNXStorageConnection(driver.StorageConnection):
|
||||||
self.reserved_percentage = None
|
self.reserved_percentage = None
|
||||||
self.driver_handles_share_servers = True
|
self.driver_handles_share_servers = True
|
||||||
self.port_conf = None
|
self.port_conf = None
|
||||||
|
self.ipv6_implemented = True
|
||||||
|
|
||||||
def create_share(self, context, share, share_server=None):
|
def create_share(self, context, share, share_server=None):
|
||||||
"""Create a share and export it based on protocol used."""
|
"""Create a share and export it based on protocol used."""
|
||||||
|
@ -179,7 +182,7 @@ class VNXStorageConnection(driver.StorageConnection):
|
||||||
LOG.error(message)
|
LOG.error(message)
|
||||||
raise exception.EMCVnxXMLAPIError(err=message)
|
raise exception.EMCVnxXMLAPIError(err=message)
|
||||||
|
|
||||||
interface = server['interfaces'][0]
|
interface = enas_utils.export_unc_path(server['interfaces'][0])
|
||||||
|
|
||||||
self._get_context('CIFSShare').create(share_name, server['name'],
|
self._get_context('CIFSShare').create(share_name, server['name'],
|
||||||
vdm_name)
|
vdm_name)
|
||||||
|
@ -199,8 +202,11 @@ class VNXStorageConnection(driver.StorageConnection):
|
||||||
|
|
||||||
self._get_context('NFSShare').create(share_name, vdm_name)
|
self._get_context('NFSShare').create(share_name, vdm_name)
|
||||||
|
|
||||||
|
nfs_if = enas_utils.convert_ipv6_format_if_needed(
|
||||||
|
share_server['backend_details']['nfs_if'])
|
||||||
|
|
||||||
return ('%(nfs_if)s:/%(share_name)s'
|
return ('%(nfs_if)s:/%(share_name)s'
|
||||||
% {'nfs_if': share_server['backend_details']['nfs_if'],
|
% {'nfs_if': nfs_if,
|
||||||
'share_name': share_name})
|
'share_name': share_name})
|
||||||
|
|
||||||
def create_share_from_snapshot(self, context, share, snapshot,
|
def create_share_from_snapshot(self, context, share, snapshot,
|
||||||
|
@ -228,10 +234,13 @@ class VNXStorageConnection(driver.StorageConnection):
|
||||||
self._allocate_container_from_snapshot(
|
self._allocate_container_from_snapshot(
|
||||||
share, snapshot, share_server, pool_name)
|
share, snapshot, share_server, pool_name)
|
||||||
|
|
||||||
|
nfs_if = enas_utils.convert_ipv6_format_if_needed(
|
||||||
|
share_server['backend_details']['nfs_if'])
|
||||||
|
|
||||||
if share_proto == 'NFS':
|
if share_proto == 'NFS':
|
||||||
self._create_nfs_share(share_name, share_server)
|
self._create_nfs_share(share_name, share_server)
|
||||||
location = ('%(nfs_if)s:/%(share_name)s'
|
location = ('%(nfs_if)s:/%(share_name)s'
|
||||||
% {'nfs_if': share_server['backend_details']['nfs_if'],
|
% {'nfs_if': nfs_if,
|
||||||
'share_name': share_name})
|
'share_name': share_name})
|
||||||
elif share_proto == 'CIFS':
|
elif share_proto == 'CIFS':
|
||||||
location = self._create_cifs_share(share_name, share_server)
|
location = self._create_cifs_share(share_name, share_server)
|
||||||
|
@ -243,9 +252,9 @@ class VNXStorageConnection(driver.StorageConnection):
|
||||||
share_name = snapshot['share_id']
|
share_name = snapshot['share_id']
|
||||||
status, filesystem = self._get_context('FileSystem').get(share_name)
|
status, filesystem = self._get_context('FileSystem').get(share_name)
|
||||||
if status != constants.STATUS_OK:
|
if status != constants.STATUS_OK:
|
||||||
message = (_("File System %s not found.") % share_name)
|
message = (_("File System %s not found.") % share_name)
|
||||||
LOG.error(message)
|
LOG.error(message)
|
||||||
raise exception.EMCVnxXMLAPIError(err=message)
|
raise exception.EMCVnxXMLAPIError(err=message)
|
||||||
|
|
||||||
pool_id = filesystem['pools_id'][0]
|
pool_id = filesystem['pools_id'][0]
|
||||||
|
|
||||||
|
@ -371,9 +380,9 @@ class VNXStorageConnection(driver.StorageConnection):
|
||||||
status, server = self._get_context('CIFSServer').get(server_name,
|
status, server = self._get_context('CIFSServer').get(server_name,
|
||||||
vdm_name)
|
vdm_name)
|
||||||
if status != constants.STATUS_OK:
|
if status != constants.STATUS_OK:
|
||||||
message = (_("CIFS server %s not found.") % server_name)
|
message = (_("CIFS server %s not found.") % server_name)
|
||||||
LOG.error(message)
|
LOG.error(message)
|
||||||
raise exception.EMCVnxXMLAPIError(err=message)
|
raise exception.EMCVnxXMLAPIError(err=message)
|
||||||
|
|
||||||
self._get_context('CIFSShare').allow_share_access(
|
self._get_context('CIFSShare').allow_share_access(
|
||||||
vdm_name,
|
vdm_name,
|
||||||
|
@ -413,7 +422,9 @@ class VNXStorageConnection(driver.StorageConnection):
|
||||||
white_list = []
|
white_list = []
|
||||||
for rule in access_rules:
|
for rule in access_rules:
|
||||||
self.allow_access(context, share, rule, share_server)
|
self.allow_access(context, share, rule, share_server)
|
||||||
white_list.append(rule['access_to'])
|
white_list.append(
|
||||||
|
enas_utils.convert_ipv6_format_if_needed(
|
||||||
|
rule['access_to']))
|
||||||
self.clear_access(share, share_server, white_list)
|
self.clear_access(share, share_server, white_list)
|
||||||
|
|
||||||
def clear_access(self, share, share_server, white_list):
|
def clear_access(self, share, share_server, white_list):
|
||||||
|
@ -488,9 +499,9 @@ class VNXStorageConnection(driver.StorageConnection):
|
||||||
status, server = self._get_context('CIFSServer').get(server_name,
|
status, server = self._get_context('CIFSServer').get(server_name,
|
||||||
vdm_name)
|
vdm_name)
|
||||||
if status != constants.STATUS_OK:
|
if status != constants.STATUS_OK:
|
||||||
message = (_("CIFS server %s not found.") % server_name)
|
message = (_("CIFS server %s not found.") % server_name)
|
||||||
LOG.error(message)
|
LOG.error(message)
|
||||||
raise exception.EMCVnxXMLAPIError(err=message)
|
raise exception.EMCVnxXMLAPIError(err=message)
|
||||||
|
|
||||||
self._get_context('CIFSShare').deny_share_access(
|
self._get_context('CIFSShare').deny_share_access(
|
||||||
vdm_name,
|
vdm_name,
|
||||||
|
@ -509,7 +520,7 @@ class VNXStorageConnection(driver.StorageConnection):
|
||||||
reason = _('Only ip access type allowed.')
|
reason = _('Only ip access type allowed.')
|
||||||
raise exception.InvalidShareAccess(reason=reason)
|
raise exception.InvalidShareAccess(reason=reason)
|
||||||
|
|
||||||
host_ip = access['access_to']
|
host_ip = enas_utils.convert_ipv6_format_if_needed(access['access_to'])
|
||||||
|
|
||||||
self._get_context('NFSShare').deny_share_access(share['id'], host_ip,
|
self._get_context('NFSShare').deny_share_access(share['id'], host_ip,
|
||||||
vdm_name)
|
vdm_name)
|
||||||
|
@ -681,21 +692,29 @@ class VNXStorageConnection(driver.StorageConnection):
|
||||||
'share server...', vdm_name)
|
'share server...', vdm_name)
|
||||||
self._get_context('VDM').create(vdm_name, self.mover_name)
|
self._get_context('VDM').create(vdm_name, self.mover_name)
|
||||||
|
|
||||||
netmask = utils.cidr_to_netmask(network_info['cidr'])
|
|
||||||
|
|
||||||
devices = self.get_managed_ports()
|
devices = self.get_managed_ports()
|
||||||
|
|
||||||
for net_info in network_info['network_allocations']:
|
for net_info in network_info['network_allocations']:
|
||||||
random.shuffle(devices)
|
random.shuffle(devices)
|
||||||
|
|
||||||
|
ip_version = net_info['ip_version']
|
||||||
|
|
||||||
interface = {
|
interface = {
|
||||||
'name': net_info['id'][-12:],
|
'name': net_info['id'][-12:],
|
||||||
'device_name': devices[0],
|
'device_name': devices[0],
|
||||||
'ip': net_info['ip_address'],
|
'ip': net_info['ip_address'],
|
||||||
'mover_name': self.mover_name,
|
'mover_name': self.mover_name,
|
||||||
'net_mask': netmask,
|
|
||||||
'vlan_id': vlan_id if vlan_id else -1,
|
'vlan_id': vlan_id if vlan_id else -1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ip_version == 6:
|
||||||
|
interface['ip_version'] = ip_version
|
||||||
|
interface['net_mask'] = six.text_type(
|
||||||
|
utils.cidr_to_prefixlen(network_info['cidr']))
|
||||||
|
else:
|
||||||
|
interface['net_mask'] = utils.cidr_to_netmask(
|
||||||
|
network_info['cidr'])
|
||||||
|
|
||||||
self._get_context('MoverInterface').create(interface)
|
self._get_context('MoverInterface').create(interface)
|
||||||
|
|
||||||
allocated_interfaces.append(interface)
|
allocated_interfaces.append(interface)
|
||||||
|
|
|
@ -27,15 +27,15 @@ from manila import exception
|
||||||
from manila.i18n import _
|
from manila.i18n import _
|
||||||
from manila.share.drivers.dell_emc.common.enas import connector
|
from manila.share.drivers.dell_emc.common.enas import connector
|
||||||
from manila.share.drivers.dell_emc.common.enas import constants
|
from manila.share.drivers.dell_emc.common.enas import constants
|
||||||
from manila.share.drivers.dell_emc.common.enas import utils as vnx_utils
|
from manila.share.drivers.dell_emc.common.enas import utils as enas_utils
|
||||||
from manila.share.drivers.dell_emc.common.enas import xml_api_parser as parser
|
from manila.share.drivers.dell_emc.common.enas import xml_api_parser as parser
|
||||||
from manila import utils
|
from manila import utils
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@vnx_utils.decorate_all_methods(vnx_utils.log_enter_exit,
|
@enas_utils.decorate_all_methods(enas_utils.log_enter_exit,
|
||||||
debug_only=True)
|
debug_only=True)
|
||||||
class StorageObjectManager(object):
|
class StorageObjectManager(object):
|
||||||
def __init__(self, configuration):
|
def __init__(self, configuration):
|
||||||
self.context = dict()
|
self.context = dict()
|
||||||
|
@ -211,8 +211,8 @@ class StorageObject(object):
|
||||||
return self.manager.getStorageContext(type)
|
return self.manager.getStorageContext(type)
|
||||||
|
|
||||||
|
|
||||||
@vnx_utils.decorate_all_methods(vnx_utils.log_enter_exit,
|
@enas_utils.decorate_all_methods(enas_utils.log_enter_exit,
|
||||||
debug_only=True)
|
debug_only=True)
|
||||||
class FileSystem(StorageObject):
|
class FileSystem(StorageObject):
|
||||||
def __init__(self, conn, elt_maker, xml_parser, manager):
|
def __init__(self, conn, elt_maker, xml_parser, manager):
|
||||||
super(FileSystem, self).__init__(conn, elt_maker, xml_parser, manager)
|
super(FileSystem, self).__init__(conn, elt_maker, xml_parser, manager)
|
||||||
|
@ -479,8 +479,8 @@ class FileSystem(StorageObject):
|
||||||
self._execute_cmd(rw_mount_cmd)
|
self._execute_cmd(rw_mount_cmd)
|
||||||
|
|
||||||
|
|
||||||
@vnx_utils.decorate_all_methods(vnx_utils.log_enter_exit,
|
@enas_utils.decorate_all_methods(enas_utils.log_enter_exit,
|
||||||
debug_only=True)
|
debug_only=True)
|
||||||
class StoragePool(StorageObject):
|
class StoragePool(StorageObject):
|
||||||
def __init__(self, conn, elt_maker, xml_parser, manager):
|
def __init__(self, conn, elt_maker, xml_parser, manager):
|
||||||
super(StoragePool, self).__init__(conn, elt_maker, xml_parser, manager)
|
super(StoragePool, self).__init__(conn, elt_maker, xml_parser, manager)
|
||||||
|
@ -541,8 +541,8 @@ class StoragePool(StorageObject):
|
||||||
return out['id']
|
return out['id']
|
||||||
|
|
||||||
|
|
||||||
@vnx_utils.decorate_all_methods(vnx_utils.log_enter_exit,
|
@enas_utils.decorate_all_methods(enas_utils.log_enter_exit,
|
||||||
debug_only=True)
|
debug_only=True)
|
||||||
class MountPoint(StorageObject):
|
class MountPoint(StorageObject):
|
||||||
def __init__(self, conn, elt_maker, xml_parser, manager):
|
def __init__(self, conn, elt_maker, xml_parser, manager):
|
||||||
super(MountPoint, self).__init__(conn, elt_maker, xml_parser, manager)
|
super(MountPoint, self).__init__(conn, elt_maker, xml_parser, manager)
|
||||||
|
@ -682,8 +682,8 @@ class MountPoint(StorageObject):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@vnx_utils.decorate_all_methods(vnx_utils.log_enter_exit,
|
@enas_utils.decorate_all_methods(enas_utils.log_enter_exit,
|
||||||
debug_only=True)
|
debug_only=True)
|
||||||
class Mover(StorageObject):
|
class Mover(StorageObject):
|
||||||
def __init__(self, conn, elt_maker, xml_parser, manager):
|
def __init__(self, conn, elt_maker, xml_parser, manager):
|
||||||
super(Mover, self).__init__(conn, elt_maker, xml_parser, manager)
|
super(Mover, self).__init__(conn, elt_maker, xml_parser, manager)
|
||||||
|
@ -847,8 +847,8 @@ class Mover(StorageObject):
|
||||||
return physical_network_devices
|
return physical_network_devices
|
||||||
|
|
||||||
|
|
||||||
@vnx_utils.decorate_all_methods(vnx_utils.log_enter_exit,
|
@enas_utils.decorate_all_methods(enas_utils.log_enter_exit,
|
||||||
debug_only=True)
|
debug_only=True)
|
||||||
class VDM(StorageObject):
|
class VDM(StorageObject):
|
||||||
def __init__(self, conn, elt_maker, xml_parser, manager):
|
def __init__(self, conn, elt_maker, xml_parser, manager):
|
||||||
super(VDM, self).__init__(conn, elt_maker, xml_parser, manager)
|
super(VDM, self).__init__(conn, elt_maker, xml_parser, manager)
|
||||||
|
@ -1022,8 +1022,8 @@ class VDM(StorageObject):
|
||||||
return interfaces
|
return interfaces
|
||||||
|
|
||||||
|
|
||||||
@vnx_utils.decorate_all_methods(vnx_utils.log_enter_exit,
|
@enas_utils.decorate_all_methods(enas_utils.log_enter_exit,
|
||||||
debug_only=True)
|
debug_only=True)
|
||||||
class Snapshot(StorageObject):
|
class Snapshot(StorageObject):
|
||||||
def __init__(self, conn, elt_maker, xml_parser, manager):
|
def __init__(self, conn, elt_maker, xml_parser, manager):
|
||||||
super(Snapshot, self).__init__(conn, elt_maker, xml_parser, manager)
|
super(Snapshot, self).__init__(conn, elt_maker, xml_parser, manager)
|
||||||
|
@ -1137,8 +1137,8 @@ class Snapshot(StorageObject):
|
||||||
return self.snap_map[name]['id']
|
return self.snap_map[name]['id']
|
||||||
|
|
||||||
|
|
||||||
@vnx_utils.decorate_all_methods(vnx_utils.log_enter_exit,
|
@enas_utils.decorate_all_methods(enas_utils.log_enter_exit,
|
||||||
debug_only=True)
|
debug_only=True)
|
||||||
class MoverInterface(StorageObject):
|
class MoverInterface(StorageObject):
|
||||||
def __init__(self, conn, elt_maker, xml_parser, manager):
|
def __init__(self, conn, elt_maker, xml_parser, manager):
|
||||||
super(MoverInterface, self).__init__(conn, elt_maker, xml_parser,
|
super(MoverInterface, self).__init__(conn, elt_maker, xml_parser,
|
||||||
|
@ -1159,18 +1159,21 @@ class MoverInterface(StorageObject):
|
||||||
|
|
||||||
mover_id = self._get_mover_id(mover_name, False)
|
mover_id = self._get_mover_id(mover_name, False)
|
||||||
|
|
||||||
|
params = dict(device=device_name,
|
||||||
|
ipAddress=six.text_type(ip_addr),
|
||||||
|
mover=mover_id,
|
||||||
|
name=name,
|
||||||
|
netMask=net_mask,
|
||||||
|
vlanid=six.text_type(vlan_id))
|
||||||
|
|
||||||
|
if interface.get('ip_version') == 6:
|
||||||
|
params['ipVersion'] = 'IPv6'
|
||||||
|
|
||||||
if self.xml_retry:
|
if self.xml_retry:
|
||||||
self.xml_retry = False
|
self.xml_retry = False
|
||||||
|
|
||||||
request = self._build_task_package(
|
request = self._build_task_package(
|
||||||
self.elt_maker.NewMoverInterface(
|
self.elt_maker.NewMoverInterface(**params)
|
||||||
device=device_name,
|
|
||||||
ipAddress=six.text_type(ip_addr),
|
|
||||||
mover=mover_id,
|
|
||||||
name=name,
|
|
||||||
netMask=net_mask,
|
|
||||||
vlanid=six.text_type(vlan_id)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
response = self._send_request(request)
|
response = self._send_request(request)
|
||||||
|
@ -1261,8 +1264,8 @@ class MoverInterface(StorageObject):
|
||||||
raise exception.EMCVnxXMLAPIError(err=message)
|
raise exception.EMCVnxXMLAPIError(err=message)
|
||||||
|
|
||||||
|
|
||||||
@vnx_utils.decorate_all_methods(vnx_utils.log_enter_exit,
|
@enas_utils.decorate_all_methods(enas_utils.log_enter_exit,
|
||||||
debug_only=True)
|
debug_only=True)
|
||||||
class DNSDomain(StorageObject):
|
class DNSDomain(StorageObject):
|
||||||
def __init__(self, conn, elt_maker, xml_parser, manager):
|
def __init__(self, conn, elt_maker, xml_parser, manager):
|
||||||
super(DNSDomain, self).__init__(conn, elt_maker, xml_parser, manager)
|
super(DNSDomain, self).__init__(conn, elt_maker, xml_parser, manager)
|
||||||
|
@ -1323,8 +1326,8 @@ class DNSDomain(StorageObject):
|
||||||
{'name': name, 'err': response['problems']})
|
{'name': name, 'err': response['problems']})
|
||||||
|
|
||||||
|
|
||||||
@vnx_utils.decorate_all_methods(vnx_utils.log_enter_exit,
|
@enas_utils.decorate_all_methods(enas_utils.log_enter_exit,
|
||||||
debug_only=True)
|
debug_only=True)
|
||||||
class CIFSServer(StorageObject):
|
class CIFSServer(StorageObject):
|
||||||
def __init__(self, conn, elt_maker, xml_parser, manager):
|
def __init__(self, conn, elt_maker, xml_parser, manager):
|
||||||
super(CIFSServer, self).__init__(conn, elt_maker, xml_parser, manager)
|
super(CIFSServer, self).__init__(conn, elt_maker, xml_parser, manager)
|
||||||
|
@ -1544,8 +1547,8 @@ class CIFSServer(StorageObject):
|
||||||
self.cifs_server_map[mover_name].pop(computer_name)
|
self.cifs_server_map[mover_name].pop(computer_name)
|
||||||
|
|
||||||
|
|
||||||
@vnx_utils.decorate_all_methods(vnx_utils.log_enter_exit,
|
@enas_utils.decorate_all_methods(enas_utils.log_enter_exit,
|
||||||
debug_only=True)
|
debug_only=True)
|
||||||
class CIFSShare(StorageObject):
|
class CIFSShare(StorageObject):
|
||||||
def __init__(self, conn, elt_maker, xml_parser, manager):
|
def __init__(self, conn, elt_maker, xml_parser, manager):
|
||||||
super(CIFSShare, self).__init__(conn, elt_maker, xml_parser, manager)
|
super(CIFSShare, self).__init__(conn, elt_maker, xml_parser, manager)
|
||||||
|
@ -1771,8 +1774,8 @@ class CIFSShare(StorageObject):
|
||||||
return users_to_remove
|
return users_to_remove
|
||||||
|
|
||||||
|
|
||||||
@vnx_utils.decorate_all_methods(vnx_utils.log_enter_exit,
|
@enas_utils.decorate_all_methods(enas_utils.log_enter_exit,
|
||||||
debug_only=True)
|
debug_only=True)
|
||||||
class NFSShare(StorageObject):
|
class NFSShare(StorageObject):
|
||||||
def __init__(self, conn, elt_maker, xml_parser, manager):
|
def __init__(self, conn, elt_maker, xml_parser, manager):
|
||||||
super(NFSShare, self).__init__(conn, elt_maker, xml_parser, manager)
|
super(NFSShare, self).__init__(conn, elt_maker, xml_parser, manager)
|
||||||
|
@ -1872,13 +1875,14 @@ class NFSShare(StorageObject):
|
||||||
for field in fields:
|
for field in fields:
|
||||||
field = field.strip()
|
field = field.strip()
|
||||||
if field.startswith('rw='):
|
if field.startswith('rw='):
|
||||||
nfs_share['RwHosts'] = field[3:].split(":")
|
nfs_share['RwHosts'] = enas_utils.parse_ipaddr(field[3:])
|
||||||
elif field.startswith('access='):
|
elif field.startswith('access='):
|
||||||
nfs_share['AccessHosts'] = field[7:].split(":")
|
nfs_share['AccessHosts'] = enas_utils.parse_ipaddr(
|
||||||
|
field[7:])
|
||||||
elif field.startswith('root='):
|
elif field.startswith('root='):
|
||||||
nfs_share['RootHosts'] = field[5:].split(":")
|
nfs_share['RootHosts'] = enas_utils.parse_ipaddr(field[5:])
|
||||||
elif field.startswith('ro='):
|
elif field.startswith('ro='):
|
||||||
nfs_share['RoHosts'] = field[3:].split(":")
|
nfs_share['RoHosts'] = enas_utils.parse_ipaddr(field[3:])
|
||||||
|
|
||||||
self.nfs_share_map[name] = nfs_share
|
self.nfs_share_map[name] = nfs_share
|
||||||
else:
|
else:
|
||||||
|
@ -1899,6 +1903,9 @@ class NFSShare(StorageObject):
|
||||||
changed = False
|
changed = False
|
||||||
rwhosts = share['RwHosts']
|
rwhosts = share['RwHosts']
|
||||||
rohosts = share['RoHosts']
|
rohosts = share['RoHosts']
|
||||||
|
|
||||||
|
host_ip = enas_utils.convert_ipv6_format_if_needed(host_ip)
|
||||||
|
|
||||||
if access_level == const.ACCESS_LEVEL_RW:
|
if access_level == const.ACCESS_LEVEL_RW:
|
||||||
if host_ip not in rwhosts:
|
if host_ip not in rwhosts:
|
||||||
rwhosts.append(host_ip)
|
rwhosts.append(host_ip)
|
||||||
|
@ -1942,7 +1949,6 @@ class NFSShare(StorageObject):
|
||||||
do_allow_access(share_name, host_ip, mover_name, access_level)
|
do_allow_access(share_name, host_ip, mover_name, access_level)
|
||||||
|
|
||||||
def deny_share_access(self, share_name, host_ip, mover_name):
|
def deny_share_access(self, share_name, host_ip, mover_name):
|
||||||
|
|
||||||
@utils.synchronized('emc-shareaccess-' + share_name)
|
@utils.synchronized('emc-shareaccess-' + share_name)
|
||||||
def do_deny_access(share_name, host_ip, mover_name):
|
def do_deny_access(share_name, host_ip, mover_name):
|
||||||
status, share = self.get(share_name, mover_name)
|
status, share = self.get(share_name, mover_name)
|
||||||
|
|
|
@ -18,6 +18,7 @@ from oslo_utils import units
|
||||||
|
|
||||||
from manila.common import constants as const
|
from manila.common import constants as const
|
||||||
from manila.share import configuration as conf
|
from manila.share import configuration as conf
|
||||||
|
from manila.share.drivers.dell_emc.common.enas import utils
|
||||||
from manila.tests import fake_share
|
from manila.tests import fake_share
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,15 +78,26 @@ class FakeData(object):
|
||||||
# Share network information
|
# Share network information
|
||||||
share_network_id = 'c5b3a865-56d0-4d88-abe5-879965e099c9'
|
share_network_id = 'c5b3a865-56d0-4d88-abe5-879965e099c9'
|
||||||
cidr = '192.168.1.0/24'
|
cidr = '192.168.1.0/24'
|
||||||
|
cidr_v6 = 'fdf8:f53b:82e1::/64'
|
||||||
segmentation_id = 100
|
segmentation_id = 100
|
||||||
network_allocations_id1 = '132dbb10-9a36-46f2-8d89-3d909830c356'
|
network_allocations_id1 = '132dbb10-9a36-46f2-8d89-3d909830c356'
|
||||||
network_allocations_id2 = '7eabdeed-bad2-46ea-bd0f-a33884c869e0'
|
network_allocations_id2 = '7eabdeed-bad2-46ea-bd0f-a33884c869e0'
|
||||||
|
network_allocations_id3 = '98c9e490-a842-4e59-b59a-a6042069d35b'
|
||||||
|
network_allocations_id4 = '6319a917-ab95-4b65-a498-773ae33c5550'
|
||||||
network_allocations_ip1 = '192.168.1.1'
|
network_allocations_ip1 = '192.168.1.1'
|
||||||
network_allocations_ip2 = '192.168.1.2'
|
network_allocations_ip2 = '192.168.1.2'
|
||||||
|
network_allocations_ip3 = 'fdf8:f53b:82e1::1'
|
||||||
|
network_allocations_ip4 = 'fdf8:f53b:82e1::2'
|
||||||
|
|
||||||
|
network_allocations_ip_version1 = 4
|
||||||
|
network_allocations_ip_version2 = 4
|
||||||
|
network_allocations_ip_version3 = 6
|
||||||
|
network_allocations_ip_version4 = 6
|
||||||
domain_name = 'fake_domain'
|
domain_name = 'fake_domain'
|
||||||
domain_user = 'administrator'
|
domain_user = 'administrator'
|
||||||
domain_password = 'password'
|
domain_password = 'password'
|
||||||
dns_ip_address = '192.168.1.200'
|
dns_ip_address = '192.168.1.200'
|
||||||
|
dns_ipv6_address = 'fdf8:f53b:82e1::f'
|
||||||
|
|
||||||
# Share server information
|
# Share server information
|
||||||
share_server_id = '56aafd02-4d44-43d7-b784-57fc88167224'
|
share_server_id = '56aafd02-4d44-43d7-b784-57fc88167224'
|
||||||
|
@ -104,8 +116,11 @@ class FakeData(object):
|
||||||
mover_id = 'fake_mover_id'
|
mover_id = 'fake_mover_id'
|
||||||
interface_name1 = network_allocations_id1[-12:]
|
interface_name1 = network_allocations_id1[-12:]
|
||||||
interface_name2 = network_allocations_id2[-12:]
|
interface_name2 = network_allocations_id2[-12:]
|
||||||
|
interface_name3 = network_allocations_id3[-12:]
|
||||||
|
interface_name4 = network_allocations_id4[-12:]
|
||||||
long_interface_name = network_allocations_id1
|
long_interface_name = network_allocations_id1
|
||||||
net_mask = '255.255.255.0'
|
net_mask = '255.255.255.0'
|
||||||
|
net_mask_v6 = 64
|
||||||
device_name = 'cge-1-0'
|
device_name = 'cge-1-0'
|
||||||
interconnect_id = '2001'
|
interconnect_id = '2001'
|
||||||
|
|
||||||
|
@ -123,6 +138,9 @@ class FakeData(object):
|
||||||
rw_hosts = ['192.168.1.1', '192.168.1.2']
|
rw_hosts = ['192.168.1.1', '192.168.1.2']
|
||||||
ro_hosts = ['192.168.1.3', '192.168.1.4']
|
ro_hosts = ['192.168.1.3', '192.168.1.4']
|
||||||
nfs_host_ip = '192.168.1.5'
|
nfs_host_ip = '192.168.1.5'
|
||||||
|
rw_hosts_ipv6 = ['fdf8:f53b:82e1::1', 'fdf8:f53b:82e1::2']
|
||||||
|
ro_hosts_ipv6 = ['fdf8:f53b:82e1::3', 'fdf8:f53b:82e1::4']
|
||||||
|
nfs_host_ipv6 = 'fdf8:f53b:82e1::5'
|
||||||
|
|
||||||
fake_output = ''
|
fake_output = ''
|
||||||
|
|
||||||
|
@ -175,10 +193,15 @@ class StorageObjectTestData(object):
|
||||||
|
|
||||||
self.interface_name1 = FakeData.interface_name1
|
self.interface_name1 = FakeData.interface_name1
|
||||||
self.interface_name2 = FakeData.interface_name2
|
self.interface_name2 = FakeData.interface_name2
|
||||||
|
self.interface_name3 = FakeData.interface_name3
|
||||||
|
self.interface_name4 = FakeData.interface_name4
|
||||||
self.long_interface_name = FakeData.long_interface_name
|
self.long_interface_name = FakeData.long_interface_name
|
||||||
self.ip_address1 = FakeData.network_allocations_ip1
|
self.ip_address1 = FakeData.network_allocations_ip1
|
||||||
self.ip_address2 = FakeData.network_allocations_ip2
|
self.ip_address2 = FakeData.network_allocations_ip2
|
||||||
|
self.ip_address3 = FakeData.network_allocations_ip3
|
||||||
|
self.ip_address4 = FakeData.network_allocations_ip4
|
||||||
self.net_mask = FakeData.net_mask
|
self.net_mask = FakeData.net_mask
|
||||||
|
self.net_mask_v6 = FakeData.net_mask_v6
|
||||||
self.vlan_id = FakeData.segmentation_id
|
self.vlan_id = FakeData.segmentation_id
|
||||||
|
|
||||||
self.cifs_server_name = FakeData.vdm_name
|
self.cifs_server_name = FakeData.vdm_name
|
||||||
|
@ -196,6 +219,10 @@ class StorageObjectTestData(object):
|
||||||
self.ro_hosts = FakeData.ro_hosts
|
self.ro_hosts = FakeData.ro_hosts
|
||||||
self.nfs_host_ip = FakeData.nfs_host_ip
|
self.nfs_host_ip = FakeData.nfs_host_ip
|
||||||
|
|
||||||
|
self.rw_hosts_ipv6 = FakeData.rw_hosts_ipv6
|
||||||
|
self.ro_hosts_ipv6 = FakeData.ro_hosts_ipv6
|
||||||
|
self.nfs_host_ipv6 = FakeData.nfs_host_ipv6
|
||||||
|
|
||||||
self.fake_output = FakeData.fake_output
|
self.fake_output = FakeData.fake_output
|
||||||
|
|
||||||
@response
|
@response
|
||||||
|
@ -710,10 +737,16 @@ class VDMTestData(StorageObjectTestData):
|
||||||
return '<VdmQueryParams/>'
|
return '<VdmQueryParams/>'
|
||||||
|
|
||||||
@response
|
@response
|
||||||
def resp_get_succeed(self, name=None):
|
def resp_get_succeed(self, name=None, interface1=None, interface2=None):
|
||||||
if not name:
|
if name is None:
|
||||||
name = self.vdm_name
|
name = self.vdm_name
|
||||||
|
|
||||||
|
if interface1 is None:
|
||||||
|
interface1 = self.interface_name1
|
||||||
|
|
||||||
|
if interface2 is None:
|
||||||
|
interface2 = self.interface_name2
|
||||||
|
|
||||||
return (
|
return (
|
||||||
'<QueryStatus maxSeverity="ok"/>'
|
'<QueryStatus maxSeverity="ok"/>'
|
||||||
'<Vdm name="%(vdm_name)s" state="loaded" mover="%(mover_id)s" '
|
'<Vdm name="%(vdm_name)s" state="loaded" mover="%(mover_id)s" '
|
||||||
|
@ -724,8 +757,8 @@ class VDMTestData(StorageObjectTestData):
|
||||||
{'vdm_name': name,
|
{'vdm_name': name,
|
||||||
'vdm_id': self.vdm_id,
|
'vdm_id': self.vdm_id,
|
||||||
'mover_id': self.mover_id,
|
'mover_id': self.mover_id,
|
||||||
'interface1': self.interface_name1,
|
'interface1': interface1,
|
||||||
'interface2': self.interface_name2}
|
'interface2': interface2}
|
||||||
)
|
)
|
||||||
|
|
||||||
@response
|
@response
|
||||||
|
@ -738,11 +771,14 @@ class VDMTestData(StorageObjectTestData):
|
||||||
def req_delete(self):
|
def req_delete(self):
|
||||||
return '<DeleteVdm vdm="%(vdmid)s"/>' % {'vdmid': self.vdm_id}
|
return '<DeleteVdm vdm="%(vdmid)s"/>' % {'vdmid': self.vdm_id}
|
||||||
|
|
||||||
def cmd_attach_nfs_interface(self):
|
def cmd_attach_nfs_interface(self, interface=None):
|
||||||
|
if interface is None:
|
||||||
|
interface = self.interface_name2
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'env', 'NAS_DB=/nas', '/nas/bin/nas_server',
|
'env', 'NAS_DB=/nas', '/nas/bin/nas_server',
|
||||||
'-vdm', self.vdm_name,
|
'-vdm', self.vdm_name,
|
||||||
'-attach', self.interface_name2,
|
'-attach', interface,
|
||||||
]
|
]
|
||||||
|
|
||||||
def cmd_detach_nfs_interface(self):
|
def cmd_detach_nfs_interface(self):
|
||||||
|
@ -967,6 +1003,23 @@ class MoverTestData(StorageObjectTestData):
|
||||||
'net_mask': self.net_mask}
|
'net_mask': self.net_mask}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@start_task
|
||||||
|
def req_create_interface_with_ipv6(self,
|
||||||
|
if_name=FakeData.interface_name3,
|
||||||
|
ip=FakeData.network_allocations_ip3):
|
||||||
|
return (
|
||||||
|
'<NewMoverInterface name="%(if_name)s" vlanid="%(vlan)s" '
|
||||||
|
'ipVersion="IPv6" netMask="%(net_mask)s" '
|
||||||
|
'device="%(device_name)s" '
|
||||||
|
'mover="%(mover_id)s" ipAddress="%(ip)s"/>'
|
||||||
|
% {'if_name': if_name,
|
||||||
|
'vlan': self.vlan_id,
|
||||||
|
'ip': ip,
|
||||||
|
'mover_id': self.mover_id,
|
||||||
|
'device_name': self.device_name,
|
||||||
|
'net_mask': self.net_mask_v6}
|
||||||
|
)
|
||||||
|
|
||||||
@response
|
@response
|
||||||
def resp_create_interface_but_name_already_exist(self):
|
def resp_create_interface_but_name_already_exist(self):
|
||||||
return (
|
return (
|
||||||
|
@ -1087,13 +1140,16 @@ class DNSDomainTestData(StorageObjectTestData):
|
||||||
super(DNSDomainTestData, self).__init__()
|
super(DNSDomainTestData, self).__init__()
|
||||||
|
|
||||||
@start_task
|
@start_task
|
||||||
def req_create(self):
|
def req_create(self, ip_addr=None):
|
||||||
|
if ip_addr is None:
|
||||||
|
ip_addr = self.dns_ip_address
|
||||||
|
|
||||||
return (
|
return (
|
||||||
'<NewMoverDnsDomain mover="%(mover_id)s" protocol="udp" '
|
'<NewMoverDnsDomain mover="%(mover_id)s" protocol="udp" '
|
||||||
'name="%(domain_name)s" servers="%(server_ips)s"/>' %
|
'name="%(domain_name)s" servers="%(server_ips)s"/>' %
|
||||||
{'mover_id': self.mover_id,
|
{'mover_id': self.mover_id,
|
||||||
'domain_name': self.domain_name,
|
'domain_name': self.domain_name,
|
||||||
'server_ips': self.dns_ip_address}
|
'server_ips': ip_addr}
|
||||||
)
|
)
|
||||||
|
|
||||||
@start_task
|
@start_task
|
||||||
|
@ -1111,7 +1167,10 @@ class CIFSServerTestData(StorageObjectTestData):
|
||||||
super(CIFSServerTestData, self).__init__()
|
super(CIFSServerTestData, self).__init__()
|
||||||
|
|
||||||
@start_task
|
@start_task
|
||||||
def req_create(self, mover_id, is_vdm=True):
|
def req_create(self, mover_id, is_vdm=True, ip_addr=None):
|
||||||
|
if ip_addr is None:
|
||||||
|
ip_addr = self.ip_address1
|
||||||
|
|
||||||
return (
|
return (
|
||||||
'<NewW2KCifsServer interfaces="%(ip)s" compName="%(comp_name)s" '
|
'<NewW2KCifsServer interfaces="%(ip)s" compName="%(comp_name)s" '
|
||||||
'name="%(name)s" domain="%(domain)s">'
|
'name="%(name)s" domain="%(domain)s">'
|
||||||
|
@ -1120,7 +1179,7 @@ class CIFSServerTestData(StorageObjectTestData):
|
||||||
'<JoinDomain userName="%(domain_user)s" '
|
'<JoinDomain userName="%(domain_user)s" '
|
||||||
'password="%(domain_password)s"/>'
|
'password="%(domain_password)s"/>'
|
||||||
'</NewW2KCifsServer>'
|
'</NewW2KCifsServer>'
|
||||||
% {'ip': self.ip_address1,
|
% {'ip': ip_addr,
|
||||||
'comp_name': self.cifs_server_name,
|
'comp_name': self.cifs_server_name,
|
||||||
'name': self.cifs_server_name[-14:],
|
'name': self.cifs_server_name[-14:],
|
||||||
'mover_id': mover_id,
|
'mover_id': mover_id,
|
||||||
|
@ -1143,9 +1202,14 @@ class CIFSServerTestData(StorageObjectTestData):
|
||||||
|
|
||||||
@response
|
@response
|
||||||
def resp_get_succeed(self, mover_id, is_vdm, join_domain,
|
def resp_get_succeed(self, mover_id, is_vdm, join_domain,
|
||||||
cifs_server_name=None):
|
cifs_server_name=None,
|
||||||
|
ip_addr=None):
|
||||||
if cifs_server_name is None:
|
if cifs_server_name is None:
|
||||||
cifs_server_name = self.cifs_server_name
|
cifs_server_name = self.cifs_server_name
|
||||||
|
|
||||||
|
if ip_addr is None:
|
||||||
|
ip_addr = self.ip_address1
|
||||||
|
|
||||||
return (
|
return (
|
||||||
'<QueryStatus maxSeverity="ok"/>'
|
'<QueryStatus maxSeverity="ok"/>'
|
||||||
'<CifsServer interfaces="%(ip)s" type="W2K" '
|
'<CifsServer interfaces="%(ip)s" type="W2K" '
|
||||||
|
@ -1156,7 +1220,7 @@ class CIFSServerTestData(StorageObjectTestData):
|
||||||
'domainJoined="%(join_domain)s"/></CifsServer>'
|
'domainJoined="%(join_domain)s"/></CifsServer>'
|
||||||
% {'mover_id': mover_id,
|
% {'mover_id': mover_id,
|
||||||
'cifsserver': self.cifs_server_name[-14:],
|
'cifsserver': self.cifs_server_name[-14:],
|
||||||
'ip': self.ip_address1,
|
'ip': ip_addr,
|
||||||
'is_vdm': 'true' if is_vdm else 'false',
|
'is_vdm': 'true' if is_vdm else 'false',
|
||||||
'alias': self.cifs_server_name[-12:],
|
'alias': self.cifs_server_name[-12:],
|
||||||
'domain': self.domain_name,
|
'domain': self.domain_name,
|
||||||
|
@ -1405,6 +1469,11 @@ class NFSShareTestData(StorageObjectTestData):
|
||||||
]
|
]
|
||||||
|
|
||||||
def output_get_succeed(self, rw_hosts, ro_hosts):
|
def output_get_succeed(self, rw_hosts, ro_hosts):
|
||||||
|
rw_hosts = [utils.convert_ipv6_format_if_needed(ip_addr) for ip_addr in
|
||||||
|
rw_hosts]
|
||||||
|
ro_hosts = [utils.convert_ipv6_format_if_needed(ip_addr) for ip_addr in
|
||||||
|
ro_hosts]
|
||||||
|
|
||||||
if rw_hosts and ro_hosts:
|
if rw_hosts and ro_hosts:
|
||||||
return (
|
return (
|
||||||
'%(mover_name)s :\nexport "%(path)s" '
|
'%(mover_name)s :\nexport "%(path)s" '
|
||||||
|
@ -1466,6 +1535,11 @@ class NFSShareTestData(StorageObjectTestData):
|
||||||
% self.vdm_name)
|
% self.vdm_name)
|
||||||
|
|
||||||
def cmd_set_access(self, rw_hosts, ro_hosts):
|
def cmd_set_access(self, rw_hosts, ro_hosts):
|
||||||
|
rw_hosts = [utils.convert_ipv6_format_if_needed(ip_addr) for ip_addr in
|
||||||
|
rw_hosts]
|
||||||
|
ro_hosts = [utils.convert_ipv6_format_if_needed(ip_addr) for ip_addr in
|
||||||
|
ro_hosts]
|
||||||
|
|
||||||
access_str = ("access=-0.0.0.0/0.0.0.0:%(access_hosts)s,"
|
access_str = ("access=-0.0.0.0/0.0.0.0:%(access_hosts)s,"
|
||||||
"root=%(root_hosts)s,rw=%(rw_hosts)s,ro=%(ro_hosts)s" %
|
"root=%(root_hosts)s,rw=%(rw_hosts)s,ro=%(ro_hosts)s" %
|
||||||
{'rw_hosts': ":".join(rw_hosts),
|
{'rw_hosts': ":".join(rw_hosts),
|
||||||
|
@ -1531,11 +1605,21 @@ NFS_RW_ACCESS = fake_share.fake_access(
|
||||||
access_to=FakeData.nfs_host_ip,
|
access_to=FakeData.nfs_host_ip,
|
||||||
access_level='rw')
|
access_level='rw')
|
||||||
|
|
||||||
|
NFS_RW_ACCESS_IPV6 = fake_share.fake_access(
|
||||||
|
access_type='ip',
|
||||||
|
access_to=FakeData.nfs_host_ipv6,
|
||||||
|
access_level='rw')
|
||||||
|
|
||||||
NFS_RO_ACCESS = fake_share.fake_access(
|
NFS_RO_ACCESS = fake_share.fake_access(
|
||||||
access_type='ip',
|
access_type='ip',
|
||||||
access_to=FakeData.nfs_host_ip,
|
access_to=FakeData.nfs_host_ip,
|
||||||
access_level='ro')
|
access_level='ro')
|
||||||
|
|
||||||
|
NFS_RO_ACCESS_IPV6 = fake_share.fake_access(
|
||||||
|
access_type='ip',
|
||||||
|
access_to=FakeData.nfs_host_ipv6,
|
||||||
|
access_level='ro')
|
||||||
|
|
||||||
SHARE_SERVER = {
|
SHARE_SERVER = {
|
||||||
'id': FakeData.share_server_id,
|
'id': FakeData.share_server_id,
|
||||||
'share_network': {
|
'share_network': {
|
||||||
|
@ -1550,12 +1634,32 @@ SHARE_SERVER = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SHARE_SERVER_IPV6 = {
|
||||||
|
'id': FakeData.share_server_id,
|
||||||
|
'share_network': {
|
||||||
|
'name': 'fake_share_network',
|
||||||
|
'id': FakeData.share_network_id
|
||||||
|
},
|
||||||
|
'share_network_id': FakeData.share_network_id,
|
||||||
|
'backend_details': {
|
||||||
|
'share_server_name': FakeData.vdm_name,
|
||||||
|
'cifs_if': FakeData.network_allocations_ip3,
|
||||||
|
'nfs_if': FakeData.network_allocations_ip4,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SERVER_DETAIL = {
|
SERVER_DETAIL = {
|
||||||
'share_server_name': FakeData.vdm_name,
|
'share_server_name': FakeData.vdm_name,
|
||||||
'cifs_if': FakeData.network_allocations_ip1,
|
'cifs_if': FakeData.network_allocations_ip1,
|
||||||
'nfs_if': FakeData.network_allocations_ip2,
|
'nfs_if': FakeData.network_allocations_ip2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SERVER_DETAIL_IPV6 = {
|
||||||
|
'share_server_name': FakeData.vdm_name,
|
||||||
|
'cifs_if': FakeData.network_allocations_ip3,
|
||||||
|
'nfs_if': FakeData.network_allocations_ip4,
|
||||||
|
}
|
||||||
|
|
||||||
SECURITY_SERVICE = [
|
SECURITY_SERVICE = [
|
||||||
{
|
{
|
||||||
'type': 'active_directory',
|
'type': 'active_directory',
|
||||||
|
@ -1566,6 +1670,16 @@ SECURITY_SERVICE = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
SECURITY_SERVICE_IPV6 = [
|
||||||
|
{
|
||||||
|
'type': 'active_directory',
|
||||||
|
'domain': FakeData.domain_name,
|
||||||
|
'dns_ip': FakeData.dns_ipv6_address,
|
||||||
|
'user': FakeData.domain_user,
|
||||||
|
'password': FakeData.domain_password
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
NETWORK_INFO = {
|
NETWORK_INFO = {
|
||||||
'server_id': FakeData.share_server_id,
|
'server_id': FakeData.share_server_id,
|
||||||
'cidr': FakeData.cidr,
|
'cidr': FakeData.cidr,
|
||||||
|
@ -1580,9 +1694,33 @@ NETWORK_INFO = {
|
||||||
'network_type': 'vlan',
|
'network_type': 'vlan',
|
||||||
'network_allocations': [
|
'network_allocations': [
|
||||||
{'id': FakeData.network_allocations_id1,
|
{'id': FakeData.network_allocations_id1,
|
||||||
'ip_address': FakeData.network_allocations_ip1},
|
'ip_address': FakeData.network_allocations_ip1,
|
||||||
|
'ip_version': FakeData.network_allocations_ip_version1},
|
||||||
{'id': FakeData.network_allocations_id2,
|
{'id': FakeData.network_allocations_id2,
|
||||||
'ip_address': FakeData.network_allocations_ip2}
|
'ip_address': FakeData.network_allocations_ip2,
|
||||||
|
'ip_version': FakeData.network_allocations_ip_version2}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
NETWORK_INFO_IPV6 = {
|
||||||
|
'server_id': FakeData.share_server_id,
|
||||||
|
'cidr': FakeData.cidr_v6,
|
||||||
|
'security_services': [
|
||||||
|
{'type': 'active_directory',
|
||||||
|
'domain': FakeData.domain_name,
|
||||||
|
'dns_ip': FakeData.dns_ipv6_address,
|
||||||
|
'user': FakeData.domain_user,
|
||||||
|
'password': FakeData.domain_password},
|
||||||
|
],
|
||||||
|
'segmentation_id': FakeData.segmentation_id,
|
||||||
|
'network_type': 'vlan',
|
||||||
|
'network_allocations': [
|
||||||
|
{'id': FakeData.network_allocations_id3,
|
||||||
|
'ip_address': FakeData.network_allocations_ip3,
|
||||||
|
'ip_version': FakeData.network_allocations_ip_version3},
|
||||||
|
{'id': FakeData.network_allocations_id4,
|
||||||
|
'ip_address': FakeData.network_allocations_ip4,
|
||||||
|
'ip_version': FakeData.network_allocations_ip_version4}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,3 +71,71 @@ class SslContextTestCase(test.TestCase):
|
||||||
mock.Mock(side_effect=AttributeError))
|
mock.Mock(side_effect=AttributeError))
|
||||||
context = utils.create_ssl_context(configuration)
|
context = utils.create_ssl_context(configuration)
|
||||||
self.assertIsNone(context)
|
self.assertIsNone(context)
|
||||||
|
|
||||||
|
|
||||||
|
@ddt.ddt
|
||||||
|
class ParseIpaddrTestCase(test.TestCase):
|
||||||
|
|
||||||
|
@ddt.data({'lst_ipaddr': ['192.168.100.101',
|
||||||
|
'192.168.100.102',
|
||||||
|
'192.168.100.103']},
|
||||||
|
{'lst_ipaddr': ['[fdf8:f53b:82e4::57]',
|
||||||
|
'[fdf8:f53b:82e4::54]',
|
||||||
|
'[fdf8:f53b:82e4::55]']},
|
||||||
|
{'lst_ipaddr': ['[fdf8:f53b:82e4::57]',
|
||||||
|
'[fdf8:f53b:82e4::54]',
|
||||||
|
'192.168.100.103',
|
||||||
|
'[fdf8:f53b:82e4::55]']},
|
||||||
|
{'lst_ipaddr': ['192.168.100.101',
|
||||||
|
'[fdf8:f53b:82e4::57]',
|
||||||
|
'[fdf8:f53b:82e4::54]',
|
||||||
|
'192.168.100.101',
|
||||||
|
'[fdf8:f53b:82e4::55]',
|
||||||
|
'192.168.100.102']},)
|
||||||
|
@ddt.unpack
|
||||||
|
def test_parse_ipv4_addr(self, lst_ipaddr):
|
||||||
|
self.assertEqual(lst_ipaddr, utils.parse_ipaddr(':'.join(lst_ipaddr)))
|
||||||
|
|
||||||
|
|
||||||
|
@ddt.ddt
|
||||||
|
class ConvertIPv6FormatTestCase(test.TestCase):
|
||||||
|
|
||||||
|
@ddt.data({'ip_addr': 'fdf8:f53b:82e4::55'},
|
||||||
|
{'ip_addr': 'fdf8:f53b:82e4::55/64'},
|
||||||
|
{'ip_addr': 'fdf8:f53b:82e4::55/128'})
|
||||||
|
@ddt.unpack
|
||||||
|
def test_ipv6_addr(self, ip_addr):
|
||||||
|
expected_ip_addr = '[%s]' % ip_addr
|
||||||
|
self.assertEqual(expected_ip_addr,
|
||||||
|
utils.convert_ipv6_format_if_needed(ip_addr))
|
||||||
|
|
||||||
|
@ddt.data({'ip_addr': '192.168.1.100'},
|
||||||
|
{'ip_addr': '192.168.1.100/24'},
|
||||||
|
{'ip_addr': '192.168.1.100/32'},
|
||||||
|
{'ip_addr': '[fdf8:f53b:82e4::55]'})
|
||||||
|
@ddt.unpack
|
||||||
|
def test_invalid_ipv6_addr(self, ip_addr):
|
||||||
|
self.assertEqual(ip_addr, utils.convert_ipv6_format_if_needed(ip_addr))
|
||||||
|
|
||||||
|
|
||||||
|
@ddt.ddt
|
||||||
|
class ExportUncPathTestCase(test.TestCase):
|
||||||
|
|
||||||
|
@ddt.data({'ip_addr': 'fdf8:f53b:82e4::55'},
|
||||||
|
{'ip_addr': 'fdf8:f53b:82e4::'},
|
||||||
|
{'ip_addr': '2018::'})
|
||||||
|
@ddt.unpack
|
||||||
|
def test_ipv6_addr(self, ip_addr):
|
||||||
|
expected_ip_addr = '%s.ipv6-literal.net' % ip_addr.replace(':', '-')
|
||||||
|
self.assertEqual(expected_ip_addr,
|
||||||
|
utils.export_unc_path(ip_addr))
|
||||||
|
|
||||||
|
@ddt.data({'ip_addr': '192.168.1.100'},
|
||||||
|
{'ip_addr': '192.168.1.100/24'},
|
||||||
|
{'ip_addr': '192.168.1.100/32'},
|
||||||
|
{'ip_addr': 'fdf8:f53b:82e4::55/64'},
|
||||||
|
{'ip_addr': 'fdf8:f53b:82e4::55/128'},
|
||||||
|
{'ip_addr': '[fdf8:f53b:82e4::55]'})
|
||||||
|
@ddt.unpack
|
||||||
|
def test_invalid_ipv6_addr(self, ip_addr):
|
||||||
|
self.assertEqual(ip_addr, utils.export_unc_path(ip_addr))
|
||||||
|
|
|
@ -173,7 +173,51 @@ class StorageConnectionTestCase(test.TestCase):
|
||||||
ssh_calls = [mock.call(self.cifs_share.cmd_disable_access(), True)]
|
ssh_calls = [mock.call(self.cifs_share.cmd_disable_access(), True)]
|
||||||
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
self.assertEqual(location, r'\\192.168.1.1\%s' % share['name'],
|
self.assertEqual(location, r'\\%s\%s' %
|
||||||
|
(fakes.FakeData.network_allocations_ip1,
|
||||||
|
share['name']),
|
||||||
|
'CIFS export path is incorrect')
|
||||||
|
|
||||||
|
def test_create_cifs_share_with_ipv6(self):
|
||||||
|
share_server = fakes.SHARE_SERVER_IPV6
|
||||||
|
share = fakes.CIFS_SHARE
|
||||||
|
|
||||||
|
hook = utils.RequestSideEffect()
|
||||||
|
hook.append(self.vdm.resp_get_succeed(
|
||||||
|
interface1=fakes.FakeData.interface_name3,
|
||||||
|
interface2=fakes.FakeData.interface_name4))
|
||||||
|
hook.append(self.cifs_server.resp_get_succeed(
|
||||||
|
mover_id=self.vdm.vdm_id, is_vdm=True, join_domain=True,
|
||||||
|
ip_addr=fakes.FakeData.network_allocations_ip3))
|
||||||
|
hook.append(self.pool.resp_get_succeed())
|
||||||
|
hook.append(self.fs.resp_task_succeed())
|
||||||
|
hook.append(self.cifs_share.resp_task_succeed())
|
||||||
|
xml_req_mock = utils.EMCMock(side_effect=hook)
|
||||||
|
self.connection.manager.connectors['XML'].request = xml_req_mock
|
||||||
|
|
||||||
|
ssh_hook = utils.SSHSideEffect()
|
||||||
|
ssh_hook.append()
|
||||||
|
ssh_cmd_mock = mock.Mock(side_effect=ssh_hook)
|
||||||
|
self.connection.manager.connectors['SSH'].run_ssh = ssh_cmd_mock
|
||||||
|
|
||||||
|
location = self.connection.create_share(None, share, share_server)
|
||||||
|
|
||||||
|
expected_calls = [
|
||||||
|
mock.call(self.vdm.req_get()),
|
||||||
|
mock.call(self.cifs_server.req_get(self.vdm.vdm_id)),
|
||||||
|
mock.call(self.pool.req_get()),
|
||||||
|
mock.call(self.fs.req_create_on_vdm()),
|
||||||
|
mock.call(self.cifs_share.req_create(self.vdm.vdm_id)),
|
||||||
|
]
|
||||||
|
xml_req_mock.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
|
ssh_calls = [mock.call(self.cifs_share.cmd_disable_access(), True)]
|
||||||
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
|
self.assertEqual(location, r'\\%s.ipv6-literal.net\%s' %
|
||||||
|
(fakes.FakeData.network_allocations_ip3.replace(':',
|
||||||
|
'-'),
|
||||||
|
share['name']),
|
||||||
'CIFS export path is incorrect')
|
'CIFS export path is incorrect')
|
||||||
|
|
||||||
def test_create_nfs_share(self):
|
def test_create_nfs_share(self):
|
||||||
|
@ -207,6 +251,41 @@ class StorageConnectionTestCase(test.TestCase):
|
||||||
self.assertEqual(location, '192.168.1.2:/%s' % share['name'],
|
self.assertEqual(location, '192.168.1.2:/%s' % share['name'],
|
||||||
'NFS export path is incorrect')
|
'NFS export path is incorrect')
|
||||||
|
|
||||||
|
def test_create_nfs_share_with_ipv6(self):
|
||||||
|
share_server = fakes.SHARE_SERVER_IPV6
|
||||||
|
share = fakes.NFS_SHARE
|
||||||
|
|
||||||
|
hook = utils.RequestSideEffect()
|
||||||
|
hook.append(self.pool.resp_get_succeed())
|
||||||
|
hook.append(self.vdm.resp_get_succeed(
|
||||||
|
interface1=fakes.FakeData.interface_name3,
|
||||||
|
interface2=fakes.FakeData.interface_name4))
|
||||||
|
hook.append(self.fs.resp_task_succeed())
|
||||||
|
xml_req_mock = utils.EMCMock(side_effect=hook)
|
||||||
|
self.connection.manager.connectors['XML'].request = xml_req_mock
|
||||||
|
|
||||||
|
ssh_hook = utils.SSHSideEffect()
|
||||||
|
ssh_hook.append(self.nfs_share.output_create())
|
||||||
|
ssh_cmd_mock = mock.Mock(side_effect=ssh_hook)
|
||||||
|
self.connection.manager.connectors['SSH'].run_ssh = ssh_cmd_mock
|
||||||
|
|
||||||
|
location = self.connection.create_share(None, share, share_server)
|
||||||
|
|
||||||
|
expected_calls = [
|
||||||
|
mock.call(self.pool.req_get()),
|
||||||
|
mock.call(self.vdm.req_get()),
|
||||||
|
mock.call(self.fs.req_create_on_vdm()),
|
||||||
|
]
|
||||||
|
xml_req_mock.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
|
ssh_calls = [mock.call(self.nfs_share.cmd_create(), True)]
|
||||||
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
|
self.assertEqual(location, '[%s]:/%s' %
|
||||||
|
(fakes.FakeData.network_allocations_ip4,
|
||||||
|
share['name']),
|
||||||
|
'NFS export path is incorrect')
|
||||||
|
|
||||||
def test_create_cifs_share_without_share_server(self):
|
def test_create_cifs_share_without_share_server(self):
|
||||||
share = fakes.CIFS_SHARE
|
share = fakes.CIFS_SHARE
|
||||||
|
|
||||||
|
@ -336,6 +415,70 @@ class StorageConnectionTestCase(test.TestCase):
|
||||||
self.assertEqual(location, r'\\192.168.1.1\%s' % share['name'],
|
self.assertEqual(location, r'\\192.168.1.1\%s' % share['name'],
|
||||||
'CIFS export path is incorrect')
|
'CIFS export path is incorrect')
|
||||||
|
|
||||||
|
def test_create_cifs_share_from_snapshot_with_ipv6(self):
|
||||||
|
share_server = fakes.SHARE_SERVER_IPV6
|
||||||
|
share = fakes.CIFS_SHARE
|
||||||
|
snapshot = fake_share.fake_snapshot(
|
||||||
|
name=fakes.FakeData.src_snap_name,
|
||||||
|
share_name=fakes.FakeData.src_share_name,
|
||||||
|
share_id=fakes.FakeData.src_share_name,
|
||||||
|
id=fakes.FakeData.src_snap_name)
|
||||||
|
|
||||||
|
hook = utils.RequestSideEffect()
|
||||||
|
hook.append(self.fs.resp_get_succeed())
|
||||||
|
hook.append(self.vdm.resp_get_succeed(
|
||||||
|
interface1=fakes.FakeData.interface_name3,
|
||||||
|
interface2=fakes.FakeData.interface_name4))
|
||||||
|
hook.append(self.cifs_server.resp_get_succeed(
|
||||||
|
mover_id=self.vdm.vdm_id, is_vdm=True, join_domain=True,
|
||||||
|
ip_addr=fakes.FakeData.network_allocations_ip3))
|
||||||
|
hook.append(self.cifs_share.resp_task_succeed())
|
||||||
|
xml_req_mock = utils.EMCMock(side_effect=hook)
|
||||||
|
self.connection.manager.connectors['XML'].request = xml_req_mock
|
||||||
|
|
||||||
|
ssh_hook = utils.SSHSideEffect()
|
||||||
|
ssh_hook.append(self.mover.output_get_interconnect_id())
|
||||||
|
ssh_hook.append()
|
||||||
|
ssh_hook.append()
|
||||||
|
ssh_hook.append(self.fs.output_copy_ckpt)
|
||||||
|
ssh_hook.append(self.fs.output_info())
|
||||||
|
ssh_hook.append()
|
||||||
|
ssh_hook.append()
|
||||||
|
ssh_hook.append()
|
||||||
|
ssh_hook.append()
|
||||||
|
ssh_cmd_mock = mock.Mock(side_effect=ssh_hook)
|
||||||
|
self.connection.manager.connectors['SSH'].run_ssh = ssh_cmd_mock
|
||||||
|
|
||||||
|
location = self.connection.create_share_from_snapshot(
|
||||||
|
None, share, snapshot, share_server)
|
||||||
|
|
||||||
|
expected_calls = [
|
||||||
|
mock.call(self.fs.req_get()),
|
||||||
|
mock.call(self.vdm.req_get()),
|
||||||
|
mock.call(self.cifs_server.req_get(self.vdm.vdm_id)),
|
||||||
|
mock.call(self.cifs_share.req_create(self.vdm.vdm_id)),
|
||||||
|
]
|
||||||
|
xml_req_mock.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
|
ssh_calls = [
|
||||||
|
mock.call(self.mover.cmd_get_interconnect_id(), False),
|
||||||
|
mock.call(self.fs.cmd_create_from_ckpt(), False),
|
||||||
|
mock.call(self.mount.cmd_server_mount('ro'), False),
|
||||||
|
mock.call(self.fs.cmd_copy_ckpt(), True),
|
||||||
|
mock.call(self.fs.cmd_nas_fs_info(), False),
|
||||||
|
mock.call(self.mount.cmd_server_umount(), False),
|
||||||
|
mock.call(self.fs.cmd_delete(), False),
|
||||||
|
mock.call(self.mount.cmd_server_mount('rw'), False),
|
||||||
|
mock.call(self.cifs_share.cmd_disable_access(), True),
|
||||||
|
]
|
||||||
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
|
self.assertEqual(location, r'\\%s.ipv6-literal.net\%s' %
|
||||||
|
(fakes.FakeData.network_allocations_ip3.replace(':',
|
||||||
|
'-'),
|
||||||
|
share['name']),
|
||||||
|
'CIFS export path is incorrect')
|
||||||
|
|
||||||
def test_create_nfs_share_from_snapshot(self):
|
def test_create_nfs_share_from_snapshot(self):
|
||||||
share_server = fakes.SHARE_SERVER
|
share_server = fakes.SHARE_SERVER
|
||||||
share = fakes.NFS_SHARE
|
share = fakes.NFS_SHARE
|
||||||
|
@ -385,6 +528,57 @@ class StorageConnectionTestCase(test.TestCase):
|
||||||
self.assertEqual(location, '192.168.1.2:/%s' % share['name'],
|
self.assertEqual(location, '192.168.1.2:/%s' % share['name'],
|
||||||
'NFS export path is incorrect')
|
'NFS export path is incorrect')
|
||||||
|
|
||||||
|
def test_create_nfs_share_from_snapshot_with_ipv6(self):
|
||||||
|
share_server = fakes.SHARE_SERVER_IPV6
|
||||||
|
share = fakes.NFS_SHARE
|
||||||
|
snapshot = fake_share.fake_snapshot(
|
||||||
|
name=fakes.FakeData.src_snap_name,
|
||||||
|
share_name=fakes.FakeData.src_share_name,
|
||||||
|
share_id=fakes.FakeData.src_share_name,
|
||||||
|
id=fakes.FakeData.src_snap_name)
|
||||||
|
|
||||||
|
hook = utils.RequestSideEffect()
|
||||||
|
hook.append(self.fs.resp_get_succeed())
|
||||||
|
xml_req_mock = utils.EMCMock(side_effect=hook)
|
||||||
|
self.connection.manager.connectors['XML'].request = xml_req_mock
|
||||||
|
|
||||||
|
ssh_hook = utils.SSHSideEffect()
|
||||||
|
ssh_hook.append(self.mover.output_get_interconnect_id())
|
||||||
|
ssh_hook.append()
|
||||||
|
ssh_hook.append()
|
||||||
|
ssh_hook.append(self.fs.output_copy_ckpt)
|
||||||
|
ssh_hook.append(self.fs.output_info())
|
||||||
|
ssh_hook.append()
|
||||||
|
ssh_hook.append()
|
||||||
|
ssh_hook.append()
|
||||||
|
ssh_hook.append(self.nfs_share.output_create())
|
||||||
|
ssh_cmd_mock = mock.Mock(side_effect=ssh_hook)
|
||||||
|
self.connection.manager.connectors['SSH'].run_ssh = ssh_cmd_mock
|
||||||
|
|
||||||
|
location = self.connection.create_share_from_snapshot(
|
||||||
|
None, share, snapshot, share_server)
|
||||||
|
|
||||||
|
expected_calls = [mock.call(self.fs.req_get())]
|
||||||
|
xml_req_mock.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
|
ssh_calls = [
|
||||||
|
mock.call(self.mover.cmd_get_interconnect_id(), False),
|
||||||
|
mock.call(self.fs.cmd_create_from_ckpt(), False),
|
||||||
|
mock.call(self.mount.cmd_server_mount('ro'), False),
|
||||||
|
mock.call(self.fs.cmd_copy_ckpt(), True),
|
||||||
|
mock.call(self.fs.cmd_nas_fs_info(), False),
|
||||||
|
mock.call(self.mount.cmd_server_umount(), False),
|
||||||
|
mock.call(self.fs.cmd_delete(), False),
|
||||||
|
mock.call(self.mount.cmd_server_mount('rw'), False),
|
||||||
|
mock.call(self.nfs_share.cmd_create(), True)
|
||||||
|
]
|
||||||
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
|
self.assertEqual(location, '[%s]:/%s' %
|
||||||
|
(fakes.FakeData.network_allocations_ip4,
|
||||||
|
share['name']),
|
||||||
|
'NFS export path is incorrect')
|
||||||
|
|
||||||
def test_create_share_with_incorrect_proto(self):
|
def test_create_share_with_incorrect_proto(self):
|
||||||
share_server = fakes.SHARE_SERVER
|
share_server = fakes.SHARE_SERVER
|
||||||
share = fake_share.fake_share(share_proto='FAKE_PROTO')
|
share = fake_share.fake_share(share_proto='FAKE_PROTO')
|
||||||
|
@ -440,6 +634,34 @@ class StorageConnectionTestCase(test.TestCase):
|
||||||
]
|
]
|
||||||
xml_req_mock.assert_has_calls(expected_calls)
|
xml_req_mock.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
|
def test_delete_cifs_share_with_ipv6(self):
|
||||||
|
share_server = fakes.SHARE_SERVER_IPV6
|
||||||
|
share = fakes.CIFS_SHARE
|
||||||
|
|
||||||
|
hook = utils.RequestSideEffect()
|
||||||
|
hook.append(self.cifs_share.resp_get_succeed(self.vdm.vdm_id))
|
||||||
|
hook.append(self.vdm.resp_get_succeed(
|
||||||
|
interface1=fakes.FakeData.interface_name3,
|
||||||
|
interface2=fakes.FakeData.interface_name4))
|
||||||
|
hook.append(self.cifs_share.resp_task_succeed())
|
||||||
|
hook.append(self.mount.resp_task_succeed())
|
||||||
|
hook.append(self.fs.resp_get_succeed())
|
||||||
|
hook.append(self.fs.resp_task_succeed())
|
||||||
|
xml_req_mock = utils.EMCMock(side_effect=hook)
|
||||||
|
self.connection.manager.connectors['XML'].request = xml_req_mock
|
||||||
|
|
||||||
|
self.connection.delete_share(None, share, share_server)
|
||||||
|
|
||||||
|
expected_calls = [
|
||||||
|
mock.call(self.cifs_share.req_get()),
|
||||||
|
mock.call(self.vdm.req_get()),
|
||||||
|
mock.call(self.cifs_share.req_delete(self.vdm.vdm_id)),
|
||||||
|
mock.call(self.mount.req_delete(self.vdm.vdm_id)),
|
||||||
|
mock.call(self.fs.req_get()),
|
||||||
|
mock.call(self.fs.req_delete()),
|
||||||
|
]
|
||||||
|
xml_req_mock.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
def test_delete_nfs_share(self):
|
def test_delete_nfs_share(self):
|
||||||
share_server = fakes.SHARE_SERVER
|
share_server = fakes.SHARE_SERVER
|
||||||
share = fakes.NFS_SHARE
|
share = fakes.NFS_SHARE
|
||||||
|
@ -476,6 +698,44 @@ class StorageConnectionTestCase(test.TestCase):
|
||||||
]
|
]
|
||||||
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
|
def test_delete_nfs_share_with_ipv6(self):
|
||||||
|
share_server = fakes.SHARE_SERVER_IPV6
|
||||||
|
share = fakes.NFS_SHARE
|
||||||
|
|
||||||
|
hook = utils.RequestSideEffect()
|
||||||
|
hook.append(self.vdm.resp_get_succeed(
|
||||||
|
interface1=fakes.FakeData.interface_name3,
|
||||||
|
interface2=fakes.FakeData.interface_name4))
|
||||||
|
hook.append(self.mount.resp_task_succeed())
|
||||||
|
hook.append(self.fs.resp_get_succeed())
|
||||||
|
hook.append(self.fs.resp_task_succeed())
|
||||||
|
xml_req_mock = utils.EMCMock(side_effect=hook)
|
||||||
|
self.connection.manager.connectors['XML'].request = xml_req_mock
|
||||||
|
|
||||||
|
ssh_hook = utils.SSHSideEffect()
|
||||||
|
ssh_hook.append(self.nfs_share.output_get_succeed(
|
||||||
|
rw_hosts=self.nfs_share.rw_hosts,
|
||||||
|
ro_hosts=self.nfs_share.ro_hosts))
|
||||||
|
ssh_hook.append(self.nfs_share.output_delete_succeed())
|
||||||
|
ssh_cmd_mock = mock.Mock(side_effect=ssh_hook)
|
||||||
|
self.connection.manager.connectors['SSH'].run_ssh = ssh_cmd_mock
|
||||||
|
|
||||||
|
self.connection.delete_share(None, share, share_server)
|
||||||
|
|
||||||
|
expected_calls = [
|
||||||
|
mock.call(self.vdm.req_get()),
|
||||||
|
mock.call(self.mount.req_delete(self.vdm.vdm_id)),
|
||||||
|
mock.call(self.fs.req_get()),
|
||||||
|
mock.call(self.fs.req_delete()),
|
||||||
|
]
|
||||||
|
xml_req_mock.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
|
ssh_calls = [
|
||||||
|
mock.call(self.nfs_share.cmd_get(), False),
|
||||||
|
mock.call(self.nfs_share.cmd_delete(), True),
|
||||||
|
]
|
||||||
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
def test_delete_share_without_share_server(self):
|
def test_delete_share_without_share_server(self):
|
||||||
share = fakes.CIFS_SHARE
|
share = fakes.CIFS_SHARE
|
||||||
|
|
||||||
|
@ -538,6 +798,27 @@ class StorageConnectionTestCase(test.TestCase):
|
||||||
]
|
]
|
||||||
xml_req_mock.assert_has_calls(expected_calls)
|
xml_req_mock.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
|
def test_extend_share_with_ipv6(self):
|
||||||
|
share_server = fakes.SHARE_SERVER_IPV6
|
||||||
|
share = fakes.CIFS_SHARE
|
||||||
|
new_size = fakes.FakeData.new_size
|
||||||
|
|
||||||
|
hook = utils.RequestSideEffect()
|
||||||
|
hook.append(self.fs.resp_get_succeed())
|
||||||
|
hook.append(self.pool.resp_get_succeed())
|
||||||
|
hook.append(self.fs.resp_task_succeed())
|
||||||
|
xml_req_mock = utils.EMCMock(side_effect=hook)
|
||||||
|
self.connection.manager.connectors['XML'].request = xml_req_mock
|
||||||
|
|
||||||
|
self.connection.extend_share(share, new_size, share_server)
|
||||||
|
|
||||||
|
expected_calls = [
|
||||||
|
mock.call(self.fs.req_get()),
|
||||||
|
mock.call(self.pool.req_get()),
|
||||||
|
mock.call(self.fs.req_extend()),
|
||||||
|
]
|
||||||
|
xml_req_mock.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
def test_extend_share_without_pool_name(self):
|
def test_extend_share_without_pool_name(self):
|
||||||
share_server = fakes.SHARE_SERVER
|
share_server = fakes.SHARE_SERVER
|
||||||
share = fake_share.fake_share(host='HostA@BackendB',
|
share = fake_share.fake_share(host='HostA@BackendB',
|
||||||
|
@ -569,6 +850,27 @@ class StorageConnectionTestCase(test.TestCase):
|
||||||
]
|
]
|
||||||
xml_req_mock.assert_has_calls(expected_calls)
|
xml_req_mock.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
|
def test_create_snapshot_with_ipv6(self):
|
||||||
|
share_server = fakes.SHARE_SERVER_IPV6
|
||||||
|
snapshot = fake_share.fake_snapshot(
|
||||||
|
id=fakes.FakeData.snapshot_name,
|
||||||
|
share_id=fakes.FakeData.filesystem_name,
|
||||||
|
share_name=fakes.FakeData.share_name)
|
||||||
|
|
||||||
|
hook = utils.RequestSideEffect()
|
||||||
|
hook.append(self.fs.resp_get_succeed())
|
||||||
|
hook.append(self.snap.resp_task_succeed())
|
||||||
|
xml_req_mock = utils.EMCMock(side_effect=hook)
|
||||||
|
self.connection.manager.connectors['XML'].request = xml_req_mock
|
||||||
|
|
||||||
|
self.connection.create_snapshot(None, snapshot, share_server)
|
||||||
|
|
||||||
|
expected_calls = [
|
||||||
|
mock.call(self.fs.req_get()),
|
||||||
|
mock.call(self.snap.req_create()),
|
||||||
|
]
|
||||||
|
xml_req_mock.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
def test_create_snapshot_with_incorrect_share_info(self):
|
def test_create_snapshot_with_incorrect_share_info(self):
|
||||||
share_server = fakes.SHARE_SERVER
|
share_server = fakes.SHARE_SERVER
|
||||||
snapshot = fake_share.fake_snapshot(
|
snapshot = fake_share.fake_snapshot(
|
||||||
|
@ -609,6 +911,27 @@ class StorageConnectionTestCase(test.TestCase):
|
||||||
]
|
]
|
||||||
xml_req_mock.assert_has_calls(expected_calls)
|
xml_req_mock.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
|
def test_delete_snapshot_with_ipv6(self):
|
||||||
|
share_server = fakes.SHARE_SERVER_IPV6
|
||||||
|
snapshot = fake_share.fake_snapshot(
|
||||||
|
id=fakes.FakeData.snapshot_name,
|
||||||
|
share_id=fakes.FakeData.filesystem_name,
|
||||||
|
share_name=fakes.FakeData.share_name)
|
||||||
|
|
||||||
|
hook = utils.RequestSideEffect()
|
||||||
|
hook.append(self.snap.resp_get_succeed())
|
||||||
|
hook.append(self.snap.resp_task_succeed())
|
||||||
|
xml_req_mock = utils.EMCMock(side_effect=hook)
|
||||||
|
self.connection.manager.connectors['XML'].request = xml_req_mock
|
||||||
|
|
||||||
|
self.connection.delete_snapshot(None, snapshot, share_server)
|
||||||
|
|
||||||
|
expected_calls = [
|
||||||
|
mock.call(self.snap.req_get()),
|
||||||
|
mock.call(self.snap.req_delete()),
|
||||||
|
]
|
||||||
|
xml_req_mock.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
@utils.patch_get_managed_ports_vnx(return_value=['cge-1-0'])
|
@utils.patch_get_managed_ports_vnx(return_value=['cge-1-0'])
|
||||||
def test_setup_server(self):
|
def test_setup_server(self):
|
||||||
hook = utils.RequestSideEffect()
|
hook = utils.RequestSideEffect()
|
||||||
|
@ -630,8 +953,8 @@ class StorageConnectionTestCase(test.TestCase):
|
||||||
|
|
||||||
self.connection.setup_server(fakes.NETWORK_INFO, None)
|
self.connection.setup_server(fakes.NETWORK_INFO, None)
|
||||||
|
|
||||||
if_name_1 = fakes.FakeData.network_allocations_id1[-12:]
|
if_name_1 = fakes.FakeData.interface_name1
|
||||||
if_name_2 = fakes.FakeData.network_allocations_id2[-12:]
|
if_name_2 = fakes.FakeData.interface_name2
|
||||||
|
|
||||||
expected_calls = [
|
expected_calls = [
|
||||||
mock.call(self.vdm.req_get()),
|
mock.call(self.vdm.req_get()),
|
||||||
|
@ -654,6 +977,59 @@ class StorageConnectionTestCase(test.TestCase):
|
||||||
]
|
]
|
||||||
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
|
@utils.patch_get_managed_ports_vnx(return_value=['cge-1-0'])
|
||||||
|
def test_setup_server_with_ipv6(self):
|
||||||
|
hook = utils.RequestSideEffect()
|
||||||
|
hook.append(self.vdm.resp_get_but_not_found())
|
||||||
|
hook.append(self.mover.resp_get_ref_succeed())
|
||||||
|
hook.append(self.vdm.resp_task_succeed())
|
||||||
|
hook.append(self.mover.resp_task_succeed())
|
||||||
|
hook.append(self.mover.resp_task_succeed())
|
||||||
|
hook.append(self.dns.resp_task_succeed())
|
||||||
|
hook.append(self.vdm.resp_get_succeed())
|
||||||
|
hook.append(self.cifs_server.resp_task_succeed())
|
||||||
|
xml_req_mock = utils.EMCMock(side_effect=hook)
|
||||||
|
self.connection.manager.connectors['XML'].request = xml_req_mock
|
||||||
|
|
||||||
|
ssh_hook = utils.SSHSideEffect()
|
||||||
|
ssh_hook.append()
|
||||||
|
ssh_cmd_mock = mock.Mock(side_effect=ssh_hook)
|
||||||
|
self.connection.manager.connectors['SSH'].run_ssh = ssh_cmd_mock
|
||||||
|
|
||||||
|
self.connection.setup_server(fakes.NETWORK_INFO_IPV6, None)
|
||||||
|
|
||||||
|
if_name_1 = fakes.FakeData.interface_name3
|
||||||
|
if_name_2 = fakes.FakeData.interface_name4
|
||||||
|
|
||||||
|
expect_ip_1 = fakes.FakeData.network_allocations_ip3
|
||||||
|
expect_ip_2 = fakes.FakeData.network_allocations_ip4
|
||||||
|
|
||||||
|
expected_calls = [
|
||||||
|
mock.call(self.vdm.req_get()),
|
||||||
|
mock.call(self.mover.req_get_ref()),
|
||||||
|
mock.call(self.vdm.req_create()),
|
||||||
|
mock.call(self.mover.req_create_interface_with_ipv6(
|
||||||
|
if_name=if_name_1,
|
||||||
|
ip=expect_ip_1)),
|
||||||
|
mock.call(self.mover.req_create_interface_with_ipv6(
|
||||||
|
if_name=if_name_2,
|
||||||
|
ip=expect_ip_2)),
|
||||||
|
mock.call(self.dns.req_create(
|
||||||
|
ip_addr=fakes.FakeData.dns_ipv6_address)),
|
||||||
|
mock.call(self.vdm.req_get()),
|
||||||
|
mock.call(self.cifs_server.req_create(
|
||||||
|
self.vdm.vdm_id,
|
||||||
|
ip_addr=fakes.FakeData.network_allocations_ip3)),
|
||||||
|
]
|
||||||
|
xml_req_mock.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
|
ssh_calls = [
|
||||||
|
mock.call(self.vdm.cmd_attach_nfs_interface(
|
||||||
|
interface=fakes.FakeData.interface_name4), False),
|
||||||
|
]
|
||||||
|
|
||||||
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
@utils.patch_get_managed_ports_vnx(return_value=['cge-1-0'])
|
@utils.patch_get_managed_ports_vnx(return_value=['cge-1-0'])
|
||||||
def test_setup_server_with_existing_vdm(self):
|
def test_setup_server_with_existing_vdm(self):
|
||||||
hook = utils.RequestSideEffect()
|
hook = utils.RequestSideEffect()
|
||||||
|
@ -834,6 +1210,51 @@ class StorageConnectionTestCase(test.TestCase):
|
||||||
]
|
]
|
||||||
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
|
def test_teardown_server_with_ipv6(self):
|
||||||
|
hook = utils.RequestSideEffect()
|
||||||
|
hook.append(self.vdm.resp_get_succeed())
|
||||||
|
hook.append(self.cifs_server.resp_get_succeed(
|
||||||
|
mover_id=self.vdm.vdm_id, is_vdm=True, join_domain=True))
|
||||||
|
hook.append(self.cifs_server.resp_task_succeed())
|
||||||
|
hook.append(self.cifs_server.resp_get_succeed(
|
||||||
|
mover_id=self.vdm.vdm_id, is_vdm=True, join_domain=False))
|
||||||
|
hook.append(self.mover.resp_get_ref_succeed())
|
||||||
|
hook.append(self.mover.resp_task_succeed())
|
||||||
|
hook.append(self.mover.resp_task_succeed())
|
||||||
|
hook.append(self.vdm.resp_task_succeed())
|
||||||
|
xml_req_mock = utils.EMCMock(side_effect=hook)
|
||||||
|
self.connection.manager.connectors['XML'].request = xml_req_mock
|
||||||
|
|
||||||
|
ssh_hook = utils.SSHSideEffect()
|
||||||
|
ssh_hook.append(self.vdm.output_get_interfaces_vdm())
|
||||||
|
ssh_hook.append()
|
||||||
|
ssh_cmd_mock = mock.Mock(side_effect=ssh_hook)
|
||||||
|
self.connection.manager.connectors['SSH'].run_ssh = ssh_cmd_mock
|
||||||
|
|
||||||
|
self.connection.teardown_server(fakes.SERVER_DETAIL_IPV6,
|
||||||
|
fakes.SECURITY_SERVICE_IPV6)
|
||||||
|
|
||||||
|
expected_calls = [
|
||||||
|
mock.call(self.vdm.req_get()),
|
||||||
|
mock.call(self.cifs_server.req_get(self.vdm.vdm_id)),
|
||||||
|
mock.call(self.cifs_server.req_modify(
|
||||||
|
mover_id=self.vdm.vdm_id, is_vdm=True, join_domain=False)),
|
||||||
|
mock.call(self.cifs_server.req_delete(self.vdm.vdm_id)),
|
||||||
|
mock.call(self.mover.req_get_ref()),
|
||||||
|
mock.call(self.mover.req_delete_interface(
|
||||||
|
fakes.FakeData.network_allocations_ip3)),
|
||||||
|
mock.call(self.mover.req_delete_interface(
|
||||||
|
fakes.FakeData.network_allocations_ip4)),
|
||||||
|
mock.call(self.vdm.req_delete()),
|
||||||
|
]
|
||||||
|
xml_req_mock.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
|
ssh_calls = [
|
||||||
|
mock.call(self.vdm.cmd_get_interfaces(), False),
|
||||||
|
mock.call(self.vdm.cmd_detach_nfs_interface(), True),
|
||||||
|
]
|
||||||
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
def test_teardown_server_without_server_detail(self):
|
def test_teardown_server_without_server_detail(self):
|
||||||
self.connection.teardown_server(None, fakes.SECURITY_SERVICE)
|
self.connection.teardown_server(None, fakes.SECURITY_SERVICE)
|
||||||
|
|
||||||
|
@ -1006,6 +1427,40 @@ class StorageConnectionTestCase(test.TestCase):
|
||||||
]
|
]
|
||||||
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
|
def test_update_access_add_cifs_rw_with_ipv6(self):
|
||||||
|
share_server = fakes.SHARE_SERVER_IPV6
|
||||||
|
share = fakes.CIFS_SHARE
|
||||||
|
access = fakes.CIFS_RW_ACCESS
|
||||||
|
|
||||||
|
hook = utils.RequestSideEffect()
|
||||||
|
hook.append(self.vdm.resp_get_succeed(
|
||||||
|
interface1=fakes.FakeData.interface_name3,
|
||||||
|
interface2=fakes.FakeData.interface_name4))
|
||||||
|
hook.append(self.cifs_server.resp_get_succeed(
|
||||||
|
mover_id=self.vdm.vdm_id, is_vdm=True, join_domain=True,
|
||||||
|
ip_addr=fakes.FakeData.network_allocations_ip3))
|
||||||
|
xml_req_mock = utils.EMCMock(side_effect=hook)
|
||||||
|
self.connection.manager.connectors['XML'].request = xml_req_mock
|
||||||
|
|
||||||
|
ssh_hook = utils.SSHSideEffect()
|
||||||
|
ssh_hook.append(self.cifs_share.output_allow_access())
|
||||||
|
ssh_cmd_mock = mock.Mock(side_effect=ssh_hook)
|
||||||
|
self.connection.manager.connectors['SSH'].run_ssh = ssh_cmd_mock
|
||||||
|
|
||||||
|
self.connection.update_access(None, share, [], [access], [],
|
||||||
|
share_server=share_server)
|
||||||
|
|
||||||
|
expected_calls = [
|
||||||
|
mock.call(self.vdm.req_get()),
|
||||||
|
mock.call(self.cifs_server.req_get(self.vdm.vdm_id)),
|
||||||
|
]
|
||||||
|
xml_req_mock.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
|
ssh_calls = [
|
||||||
|
mock.call(self.cifs_share.cmd_change_access(), True),
|
||||||
|
]
|
||||||
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
def test_update_access_deny_nfs(self):
|
def test_update_access_deny_nfs(self):
|
||||||
share_server = fakes.SHARE_SERVER
|
share_server = fakes.SHARE_SERVER
|
||||||
share = fakes.NFS_SHARE
|
share = fakes.NFS_SHARE
|
||||||
|
@ -1037,6 +1492,37 @@ class StorageConnectionTestCase(test.TestCase):
|
||||||
]
|
]
|
||||||
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
|
def test_update_access_deny_nfs_with_ipv6(self):
|
||||||
|
share_server = fakes.SHARE_SERVER_IPV6
|
||||||
|
share = fakes.NFS_SHARE
|
||||||
|
access = fakes.NFS_RW_ACCESS
|
||||||
|
|
||||||
|
rw_hosts = copy.deepcopy(fakes.FakeData.rw_hosts_ipv6)
|
||||||
|
rw_hosts.append(access['access_to'])
|
||||||
|
|
||||||
|
ssh_hook = utils.SSHSideEffect()
|
||||||
|
ssh_hook.append(self.nfs_share.output_get_succeed(
|
||||||
|
rw_hosts=rw_hosts,
|
||||||
|
ro_hosts=fakes.FakeData.ro_hosts_ipv6))
|
||||||
|
ssh_hook.append(self.nfs_share.output_set_access_success())
|
||||||
|
ssh_hook.append(self.nfs_share.output_get_succeed(
|
||||||
|
rw_hosts=fakes.FakeData.rw_hosts_ipv6,
|
||||||
|
ro_hosts=fakes.FakeData.ro_hosts_ipv6))
|
||||||
|
ssh_cmd_mock = utils.EMCNFSShareMock(side_effect=ssh_hook)
|
||||||
|
self.connection.manager.connectors['SSH'].run_ssh = ssh_cmd_mock
|
||||||
|
|
||||||
|
self.connection.update_access(None, share, [], [], [access],
|
||||||
|
share_server=share_server)
|
||||||
|
|
||||||
|
ssh_calls = [
|
||||||
|
mock.call(self.nfs_share.cmd_get(), True),
|
||||||
|
mock.call(self.nfs_share.cmd_set_access(
|
||||||
|
rw_hosts=self.nfs_share.rw_hosts_ipv6,
|
||||||
|
ro_hosts=self.nfs_share.ro_hosts_ipv6), True),
|
||||||
|
mock.call(self.nfs_share.cmd_get(), True),
|
||||||
|
]
|
||||||
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
def test_update_access_recover_nfs_rule(self):
|
def test_update_access_recover_nfs_rule(self):
|
||||||
share_server = fakes.SHARE_SERVER
|
share_server = fakes.SHARE_SERVER
|
||||||
share = fakes.NFS_SHARE
|
share = fakes.NFS_SHARE
|
||||||
|
@ -1069,6 +1555,38 @@ class StorageConnectionTestCase(test.TestCase):
|
||||||
]
|
]
|
||||||
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
|
def test_update_access_recover_nfs_rule_with_ipv6(self):
|
||||||
|
share_server = fakes.SHARE_SERVER_IPV6
|
||||||
|
share = fakes.NFS_SHARE
|
||||||
|
access = fakes.NFS_RW_ACCESS_IPV6
|
||||||
|
hosts = ['fdf8:f53b:82e1::5']
|
||||||
|
|
||||||
|
rw_hosts = copy.deepcopy(fakes.FakeData.rw_hosts_ipv6)
|
||||||
|
rw_hosts.append(access['access_to'])
|
||||||
|
|
||||||
|
ssh_hook = utils.SSHSideEffect()
|
||||||
|
ssh_hook.append(self.nfs_share.output_get_succeed(
|
||||||
|
rw_hosts=rw_hosts,
|
||||||
|
ro_hosts=fakes.FakeData.ro_hosts_ipv6))
|
||||||
|
ssh_hook.append(self.nfs_share.output_set_access_success())
|
||||||
|
ssh_hook.append(self.nfs_share.output_get_succeed(
|
||||||
|
rw_hosts=hosts,
|
||||||
|
ro_hosts=[]))
|
||||||
|
ssh_cmd_mock = utils.EMCNFSShareMock(side_effect=ssh_hook)
|
||||||
|
self.connection.manager.connectors['SSH'].run_ssh = ssh_cmd_mock
|
||||||
|
|
||||||
|
self.connection.update_access(None, share, [access], [], [],
|
||||||
|
share_server=share_server)
|
||||||
|
|
||||||
|
ssh_calls = [
|
||||||
|
mock.call(self.nfs_share.cmd_get(), True),
|
||||||
|
mock.call(self.nfs_share.cmd_set_access(
|
||||||
|
rw_hosts=hosts,
|
||||||
|
ro_hosts=[]), True),
|
||||||
|
mock.call(self.nfs_share.cmd_get(), True),
|
||||||
|
]
|
||||||
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
def test_update_access_recover_cifs_rule(self):
|
def test_update_access_recover_cifs_rule(self):
|
||||||
share_server = fakes.SHARE_SERVER
|
share_server = fakes.SHARE_SERVER
|
||||||
share = fakes.CIFS_SHARE
|
share = fakes.CIFS_SHARE
|
||||||
|
@ -1106,6 +1624,46 @@ class StorageConnectionTestCase(test.TestCase):
|
||||||
]
|
]
|
||||||
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
|
def test_update_access_recover_cifs_rule_with_ipv6(self):
|
||||||
|
share_server = fakes.SHARE_SERVER_IPV6
|
||||||
|
share = fakes.CIFS_SHARE
|
||||||
|
access = fakes.CIFS_RW_ACCESS
|
||||||
|
|
||||||
|
hook = utils.RequestSideEffect()
|
||||||
|
hook.append(self.vdm.resp_get_succeed(
|
||||||
|
interface1=fakes.FakeData.interface_name3,
|
||||||
|
interface2=fakes.FakeData.interface_name4))
|
||||||
|
hook.append(self.cifs_server.resp_get_succeed(
|
||||||
|
mover_id=self.vdm.vdm_id, is_vdm=True, join_domain=True,
|
||||||
|
ip_addr=fakes.FakeData.network_allocations_ip3))
|
||||||
|
xml_req_mock = utils.EMCMock(side_effect=hook)
|
||||||
|
self.connection.manager.connectors['XML'].request = xml_req_mock
|
||||||
|
|
||||||
|
ssh_hook = utils.SSHSideEffect()
|
||||||
|
ssh_hook.append(self.cifs_share.output_allow_access())
|
||||||
|
ssh_hook.append(fakes.FakeData.cifs_access)
|
||||||
|
ssh_hook.append('Command succeeded')
|
||||||
|
|
||||||
|
ssh_cmd_mock = mock.Mock(side_effect=ssh_hook)
|
||||||
|
self.connection.manager.connectors['SSH'].run_ssh = ssh_cmd_mock
|
||||||
|
|
||||||
|
self.connection.update_access(None, share, [access], [], [],
|
||||||
|
share_server=share_server)
|
||||||
|
|
||||||
|
expected_calls = [
|
||||||
|
mock.call(self.vdm.req_get()),
|
||||||
|
mock.call(self.cifs_server.req_get(self.vdm.vdm_id)),
|
||||||
|
]
|
||||||
|
xml_req_mock.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
|
ssh_calls = [
|
||||||
|
mock.call(self.cifs_share.cmd_change_access(), True),
|
||||||
|
mock.call(self.cifs_share.cmd_get_access(), True),
|
||||||
|
mock.call(self.cifs_share.cmd_change_access(
|
||||||
|
action='revoke', user='guest'), True),
|
||||||
|
]
|
||||||
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
def test_cifs_clear_access_server_not_found(self):
|
def test_cifs_clear_access_server_not_found(self):
|
||||||
server = fakes.SHARE_SERVER
|
server = fakes.SHARE_SERVER
|
||||||
|
|
||||||
|
@ -1157,6 +1715,39 @@ class StorageConnectionTestCase(test.TestCase):
|
||||||
]
|
]
|
||||||
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
|
def test_allow_cifs_rw_access_with_ipv6(self):
|
||||||
|
share_server = fakes.SHARE_SERVER_IPV6
|
||||||
|
share = fakes.CIFS_SHARE
|
||||||
|
access = fakes.CIFS_RW_ACCESS
|
||||||
|
|
||||||
|
hook = utils.RequestSideEffect()
|
||||||
|
hook.append(self.vdm.resp_get_succeed(
|
||||||
|
interface1=fakes.FakeData.interface_name3,
|
||||||
|
interface2=fakes.FakeData.interface_name4))
|
||||||
|
hook.append(self.cifs_server.resp_get_succeed(
|
||||||
|
mover_id=self.vdm.vdm_id, is_vdm=True, join_domain=True,
|
||||||
|
ip_addr=fakes.FakeData.network_allocations_ip3))
|
||||||
|
xml_req_mock = utils.EMCMock(side_effect=hook)
|
||||||
|
self.connection.manager.connectors['XML'].request = xml_req_mock
|
||||||
|
|
||||||
|
ssh_hook = utils.SSHSideEffect()
|
||||||
|
ssh_hook.append(self.cifs_share.output_allow_access())
|
||||||
|
ssh_cmd_mock = mock.Mock(side_effect=ssh_hook)
|
||||||
|
self.connection.manager.connectors['SSH'].run_ssh = ssh_cmd_mock
|
||||||
|
|
||||||
|
self.connection.allow_access(None, share, access, share_server)
|
||||||
|
|
||||||
|
expected_calls = [
|
||||||
|
mock.call(self.vdm.req_get()),
|
||||||
|
mock.call(self.cifs_server.req_get(self.vdm.vdm_id)),
|
||||||
|
]
|
||||||
|
xml_req_mock.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
|
ssh_calls = [
|
||||||
|
mock.call(self.cifs_share.cmd_change_access(), True),
|
||||||
|
]
|
||||||
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
def test_allow_cifs_ro_access(self):
|
def test_allow_cifs_ro_access(self):
|
||||||
share_server = fakes.SHARE_SERVER
|
share_server = fakes.SHARE_SERVER
|
||||||
share = fakes.CIFS_SHARE
|
share = fakes.CIFS_SHARE
|
||||||
|
@ -1187,6 +1778,39 @@ class StorageConnectionTestCase(test.TestCase):
|
||||||
]
|
]
|
||||||
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
|
def test_allow_cifs_ro_access_with_ipv6(self):
|
||||||
|
share_server = fakes.SHARE_SERVER_IPV6
|
||||||
|
share = fakes.CIFS_SHARE
|
||||||
|
access = fakes.CIFS_RO_ACCESS
|
||||||
|
|
||||||
|
hook = utils.RequestSideEffect()
|
||||||
|
hook.append(self.vdm.resp_get_succeed(
|
||||||
|
interface1=fakes.FakeData.interface_name3,
|
||||||
|
interface2=fakes.FakeData.interface_name4))
|
||||||
|
hook.append(self.cifs_server.resp_get_succeed(
|
||||||
|
mover_id=self.vdm.vdm_id, is_vdm=True, join_domain=True,
|
||||||
|
ip_addr=fakes.FakeData.network_allocations_ip3))
|
||||||
|
xml_req_mock = utils.EMCMock(side_effect=hook)
|
||||||
|
self.connection.manager.connectors['XML'].request = xml_req_mock
|
||||||
|
|
||||||
|
ssh_hook = utils.SSHSideEffect()
|
||||||
|
ssh_hook.append(self.cifs_share.output_allow_access())
|
||||||
|
ssh_cmd_mock = mock.Mock(side_effect=ssh_hook)
|
||||||
|
self.connection.manager.connectors['SSH'].run_ssh = ssh_cmd_mock
|
||||||
|
|
||||||
|
self.connection.allow_access(None, share, access, share_server)
|
||||||
|
|
||||||
|
expected_calls = [
|
||||||
|
mock.call(self.vdm.req_get()),
|
||||||
|
mock.call(self.cifs_server.req_get(self.vdm.vdm_id)),
|
||||||
|
]
|
||||||
|
xml_req_mock.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
|
ssh_calls = [
|
||||||
|
mock.call(self.cifs_share.cmd_change_access('ro'), True),
|
||||||
|
]
|
||||||
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
def test_allow_ro_access_without_share_server_name(self):
|
def test_allow_ro_access_without_share_server_name(self):
|
||||||
share = fakes.CIFS_SHARE
|
share = fakes.CIFS_SHARE
|
||||||
share_server = copy.deepcopy(fakes.SHARE_SERVER)
|
share_server = copy.deepcopy(fakes.SHARE_SERVER)
|
||||||
|
@ -1277,6 +1901,37 @@ class StorageConnectionTestCase(test.TestCase):
|
||||||
]
|
]
|
||||||
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
|
def test_allow_nfs_access_with_ipv6(self):
|
||||||
|
share_server = fakes.SHARE_SERVER_IPV6
|
||||||
|
share = fakes.NFS_SHARE
|
||||||
|
access = fakes.NFS_RW_ACCESS_IPV6
|
||||||
|
|
||||||
|
rw_hosts = copy.deepcopy(fakes.FakeData.rw_hosts_ipv6)
|
||||||
|
rw_hosts.append(access['access_to'])
|
||||||
|
|
||||||
|
ssh_hook = utils.SSHSideEffect()
|
||||||
|
ssh_hook.append(self.nfs_share.output_get_succeed(
|
||||||
|
rw_hosts=fakes.FakeData.rw_hosts_ipv6,
|
||||||
|
ro_hosts=fakes.FakeData.ro_hosts_ipv6))
|
||||||
|
ssh_hook.append(self.nfs_share.output_set_access_success())
|
||||||
|
ssh_hook.append(self.nfs_share.output_get_succeed(
|
||||||
|
rw_hosts=rw_hosts,
|
||||||
|
ro_hosts=fakes.FakeData.ro_hosts_ipv6))
|
||||||
|
ssh_cmd_mock = utils.EMCNFSShareMock(side_effect=ssh_hook)
|
||||||
|
self.connection.manager.connectors['SSH'].run_ssh = ssh_cmd_mock
|
||||||
|
|
||||||
|
self.connection.allow_access(None, share, access, share_server)
|
||||||
|
|
||||||
|
ssh_calls = [
|
||||||
|
mock.call(self.nfs_share.cmd_get(), True),
|
||||||
|
mock.call(self.nfs_share.cmd_set_access(
|
||||||
|
rw_hosts=rw_hosts,
|
||||||
|
ro_hosts=self.nfs_share.ro_hosts_ipv6),
|
||||||
|
True),
|
||||||
|
mock.call(self.nfs_share.cmd_get(), True),
|
||||||
|
]
|
||||||
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
def test_allow_cifs_access_with_incorrect_access_type(self):
|
def test_allow_cifs_access_with_incorrect_access_type(self):
|
||||||
share_server = fakes.SHARE_SERVER
|
share_server = fakes.SHARE_SERVER
|
||||||
share = fakes.CIFS_SHARE
|
share = fakes.CIFS_SHARE
|
||||||
|
@ -1335,6 +1990,40 @@ class StorageConnectionTestCase(test.TestCase):
|
||||||
]
|
]
|
||||||
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
|
def test_deny_cifs_rw_access_with_ipv6(self):
|
||||||
|
share_server = fakes.SHARE_SERVER_IPV6
|
||||||
|
share = fakes.CIFS_SHARE
|
||||||
|
access = fakes.CIFS_RW_ACCESS
|
||||||
|
|
||||||
|
hook = utils.RequestSideEffect()
|
||||||
|
hook.append(self.vdm.resp_get_succeed(
|
||||||
|
interface1=fakes.FakeData.interface_name3,
|
||||||
|
interface2=fakes.FakeData.interface_name4))
|
||||||
|
hook.append(self.cifs_server.resp_get_succeed(
|
||||||
|
mover_id=self.vdm.vdm_id, is_vdm=True, join_domain=True,
|
||||||
|
ip_addr=fakes.FakeData.network_allocations_ip3))
|
||||||
|
xml_req_mock = utils.EMCMock(side_effect=hook)
|
||||||
|
self.connection.manager.connectors['XML'].request = xml_req_mock
|
||||||
|
|
||||||
|
ssh_hook = utils.SSHSideEffect()
|
||||||
|
ssh_hook.append(self.cifs_share.output_allow_access())
|
||||||
|
ssh_cmd_mock = mock.Mock(side_effect=ssh_hook)
|
||||||
|
self.connection.manager.connectors['SSH'].run_ssh = ssh_cmd_mock
|
||||||
|
|
||||||
|
self.connection.deny_access(None, share, access, share_server)
|
||||||
|
|
||||||
|
expected_calls = [
|
||||||
|
mock.call(self.vdm.req_get()),
|
||||||
|
mock.call(self.cifs_server.req_get(self.vdm.vdm_id)),
|
||||||
|
]
|
||||||
|
xml_req_mock.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
|
ssh_calls = [
|
||||||
|
mock.call(self.cifs_share.cmd_change_access(action='revoke'),
|
||||||
|
True),
|
||||||
|
]
|
||||||
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
def test_deny_cifs_ro_access(self):
|
def test_deny_cifs_ro_access(self):
|
||||||
share_server = fakes.SHARE_SERVER
|
share_server = fakes.SHARE_SERVER
|
||||||
share = fakes.CIFS_SHARE
|
share = fakes.CIFS_SHARE
|
||||||
|
@ -1365,6 +2054,39 @@ class StorageConnectionTestCase(test.TestCase):
|
||||||
]
|
]
|
||||||
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
|
def test_deny_cifs_ro_access_with_ipv6(self):
|
||||||
|
share_server = fakes.SHARE_SERVER_IPV6
|
||||||
|
share = fakes.CIFS_SHARE
|
||||||
|
access = fakes.CIFS_RO_ACCESS
|
||||||
|
|
||||||
|
hook = utils.RequestSideEffect()
|
||||||
|
hook.append(self.vdm.resp_get_succeed(
|
||||||
|
interface1=fakes.FakeData.interface_name3,
|
||||||
|
interface2=fakes.FakeData.interface_name4))
|
||||||
|
hook.append(self.cifs_server.resp_get_succeed(
|
||||||
|
mover_id=self.vdm.vdm_id, is_vdm=True, join_domain=True,
|
||||||
|
ip_addr=fakes.FakeData.network_allocations_ip3))
|
||||||
|
xml_req_mock = utils.EMCMock(side_effect=hook)
|
||||||
|
self.connection.manager.connectors['XML'].request = xml_req_mock
|
||||||
|
|
||||||
|
ssh_hook = utils.SSHSideEffect()
|
||||||
|
ssh_hook.append(self.cifs_share.output_allow_access())
|
||||||
|
ssh_cmd_mock = mock.Mock(side_effect=ssh_hook)
|
||||||
|
self.connection.manager.connectors['SSH'].run_ssh = ssh_cmd_mock
|
||||||
|
|
||||||
|
self.connection.deny_access(None, share, access, share_server)
|
||||||
|
|
||||||
|
expected_calls = [
|
||||||
|
mock.call(self.vdm.req_get()),
|
||||||
|
mock.call(self.cifs_server.req_get(self.vdm.vdm_id)),
|
||||||
|
]
|
||||||
|
xml_req_mock.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
|
ssh_calls = [
|
||||||
|
mock.call(self.cifs_share.cmd_change_access('ro', 'revoke'), True),
|
||||||
|
]
|
||||||
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
def test_deny_cifs_access_with_invliad_share_server_name(self):
|
def test_deny_cifs_access_with_invliad_share_server_name(self):
|
||||||
share_server = fakes.SHARE_SERVER
|
share_server = fakes.SHARE_SERVER
|
||||||
share = fakes.CIFS_SHARE
|
share = fakes.CIFS_SHARE
|
||||||
|
@ -1416,6 +2138,36 @@ class StorageConnectionTestCase(test.TestCase):
|
||||||
]
|
]
|
||||||
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
|
def test_deny_nfs_access_with_ipv6(self):
|
||||||
|
share_server = fakes.SHARE_SERVER_IPV6
|
||||||
|
share = fakes.NFS_SHARE
|
||||||
|
access = fakes.NFS_RW_ACCESS_IPV6
|
||||||
|
|
||||||
|
rw_hosts = copy.deepcopy(fakes.FakeData.rw_hosts_ipv6)
|
||||||
|
rw_hosts.append(access['access_to'])
|
||||||
|
|
||||||
|
ssh_hook = utils.SSHSideEffect()
|
||||||
|
ssh_hook.append(self.nfs_share.output_get_succeed(
|
||||||
|
rw_hosts=rw_hosts,
|
||||||
|
ro_hosts=fakes.FakeData.ro_hosts_ipv6))
|
||||||
|
ssh_hook.append(self.nfs_share.output_set_access_success())
|
||||||
|
ssh_hook.append(self.nfs_share.output_get_succeed(
|
||||||
|
rw_hosts=fakes.FakeData.rw_hosts_ipv6,
|
||||||
|
ro_hosts=fakes.FakeData.ro_hosts_ipv6))
|
||||||
|
ssh_cmd_mock = utils.EMCNFSShareMock(side_effect=ssh_hook)
|
||||||
|
self.connection.manager.connectors['SSH'].run_ssh = ssh_cmd_mock
|
||||||
|
|
||||||
|
self.connection.deny_access(None, share, access, share_server)
|
||||||
|
|
||||||
|
ssh_calls = [
|
||||||
|
mock.call(self.nfs_share.cmd_get(), True),
|
||||||
|
mock.call(self.nfs_share.cmd_set_access(
|
||||||
|
rw_hosts=self.nfs_share.rw_hosts_ipv6,
|
||||||
|
ro_hosts=self.nfs_share.ro_hosts_ipv6), True),
|
||||||
|
mock.call(self.nfs_share.cmd_get(), True),
|
||||||
|
]
|
||||||
|
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||||
|
|
||||||
def test_deny_access_with_incorrect_proto(self):
|
def test_deny_access_with_incorrect_proto(self):
|
||||||
share_server = fakes.SHARE_SERVER
|
share_server = fakes.SHARE_SERVER
|
||||||
share = fake_share.fake_share(share_proto='FAKE_PROTO')
|
share = fake_share.fake_share(share_proto='FAKE_PROTO')
|
||||||
|
|
|
@ -345,54 +345,58 @@ class SSHPoolTestCase(test.TestCase):
|
||||||
paramiko.SSHClient.assert_called_once_with()
|
paramiko.SSHClient.assert_called_once_with()
|
||||||
|
|
||||||
|
|
||||||
|
@ddt.ddt
|
||||||
class CidrToNetmaskTestCase(test.TestCase):
|
class CidrToNetmaskTestCase(test.TestCase):
|
||||||
"""Unit test for cidr to netmask."""
|
"""Unit test for cidr to netmask."""
|
||||||
|
|
||||||
def test_cidr_to_netmask_01(self):
|
@ddt.data(
|
||||||
cidr = '10.0.0.0/0'
|
('10.0.0.0/0', '0.0.0.0'),
|
||||||
expected_netmask = '0.0.0.0'
|
('10.0.0.0/24', '255.255.255.0'),
|
||||||
|
('10.0.0.0/5', '248.0.0.0'),
|
||||||
|
('10.0.0.0/32', '255.255.255.255'),
|
||||||
|
('10.0.0.1', '255.255.255.255'),
|
||||||
|
)
|
||||||
|
@ddt.unpack
|
||||||
|
def test_cidr_to_netmask(self, cidr, expected_netmask):
|
||||||
result = utils.cidr_to_netmask(cidr)
|
result = utils.cidr_to_netmask(cidr)
|
||||||
self.assertEqual(expected_netmask, result)
|
self.assertEqual(expected_netmask, result)
|
||||||
|
|
||||||
def test_cidr_to_netmask_02(self):
|
@ddt.data(
|
||||||
cidr = '10.0.0.0/24'
|
'10.0.0.0/33',
|
||||||
expected_netmask = '255.255.255.0'
|
'',
|
||||||
result = utils.cidr_to_netmask(cidr)
|
'10.0.0.555/33'
|
||||||
self.assertEqual(expected_netmask, result)
|
)
|
||||||
|
def test_cidr_to_netmask_invalid(self, cidr):
|
||||||
def test_cidr_to_netmask_03(self):
|
|
||||||
cidr = '10.0.0.0/5'
|
|
||||||
expected_netmask = '248.0.0.0'
|
|
||||||
result = utils.cidr_to_netmask(cidr)
|
|
||||||
self.assertEqual(expected_netmask, result)
|
|
||||||
|
|
||||||
def test_cidr_to_netmask_04(self):
|
|
||||||
cidr = '10.0.0.0/32'
|
|
||||||
expected_netmask = '255.255.255.255'
|
|
||||||
result = utils.cidr_to_netmask(cidr)
|
|
||||||
self.assertEqual(expected_netmask, result)
|
|
||||||
|
|
||||||
def test_cidr_to_netmask_05(self):
|
|
||||||
cidr = '10.0.0.1'
|
|
||||||
expected_netmask = '255.255.255.255'
|
|
||||||
result = utils.cidr_to_netmask(cidr)
|
|
||||||
self.assertEqual(expected_netmask, result)
|
|
||||||
|
|
||||||
def test_cidr_to_netmask_invalid_01(self):
|
|
||||||
cidr = '10.0.0.0/33'
|
|
||||||
self.assertRaises(exception.InvalidInput, utils.cidr_to_netmask, cidr)
|
self.assertRaises(exception.InvalidInput, utils.cidr_to_netmask, cidr)
|
||||||
|
|
||||||
def test_cidr_to_netmask_invalid_02(self):
|
|
||||||
cidr = ''
|
|
||||||
self.assertRaises(exception.InvalidInput, utils.cidr_to_netmask, cidr)
|
|
||||||
|
|
||||||
def test_cidr_to_netmask_invalid_03(self):
|
@ddt.ddt
|
||||||
cidr = '10.0.0.0/33'
|
class CidrToPrefixLenTestCase(test.TestCase):
|
||||||
self.assertRaises(exception.InvalidInput, utils.cidr_to_netmask, cidr)
|
"""Unit test for cidr to prefix length."""
|
||||||
|
|
||||||
def test_cidr_to_netmask_invalid_04(self):
|
@ddt.data(
|
||||||
cidr = '10.0.0.555/33'
|
('10.0.0.0/0', 0),
|
||||||
self.assertRaises(exception.InvalidInput, utils.cidr_to_netmask, cidr)
|
('10.0.0.0/24', 24),
|
||||||
|
('10.0.0.1', 32),
|
||||||
|
('fdf8:f53b:82e1::1/0', 0),
|
||||||
|
('fdf8:f53b:82e1::1/64', 64),
|
||||||
|
('fdf8:f53b:82e1::1', 128),
|
||||||
|
)
|
||||||
|
@ddt.unpack
|
||||||
|
def test_cidr_to_prefixlen(self, cidr, expected_prefixlen):
|
||||||
|
result = utils.cidr_to_prefixlen(cidr)
|
||||||
|
self.assertEqual(expected_prefixlen, result)
|
||||||
|
|
||||||
|
@ddt.data(
|
||||||
|
'10.0.0.0/33',
|
||||||
|
'',
|
||||||
|
'10.0.0.555/33',
|
||||||
|
'fdf8:f53b:82e1::1/129',
|
||||||
|
'fdf8:f53b:82e1::fffff'
|
||||||
|
)
|
||||||
|
def test_cidr_to_prefixlen_invalid(self, cidr):
|
||||||
|
self.assertRaises(exception.InvalidInput,
|
||||||
|
utils.cidr_to_prefixlen, cidr)
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
@ddt.ddt
|
||||||
|
|
|
@ -376,15 +376,25 @@ def walk_class_hierarchy(clazz, encountered=None):
|
||||||
yield subclass
|
yield subclass
|
||||||
|
|
||||||
|
|
||||||
def cidr_to_netmask(cidr):
|
def cidr_to_network(cidr):
|
||||||
"""Convert cidr to netmask."""
|
"""Convert cidr to network."""
|
||||||
try:
|
try:
|
||||||
network = netaddr.IPNetwork(cidr)
|
network = netaddr.IPNetwork(cidr)
|
||||||
return str(network.netmask)
|
return network
|
||||||
except netaddr.AddrFormatError:
|
except netaddr.AddrFormatError:
|
||||||
raise exception.InvalidInput(_("Invalid cidr supplied %s") % cidr)
|
raise exception.InvalidInput(_("Invalid cidr supplied %s") % cidr)
|
||||||
|
|
||||||
|
|
||||||
|
def cidr_to_netmask(cidr):
|
||||||
|
"""Convert cidr to netmask."""
|
||||||
|
return six.text_type(cidr_to_network(cidr).netmask)
|
||||||
|
|
||||||
|
|
||||||
|
def cidr_to_prefixlen(cidr):
|
||||||
|
"""Convert cidr to prefix length."""
|
||||||
|
return cidr_to_network(cidr).prefixlen
|
||||||
|
|
||||||
|
|
||||||
def is_valid_ip_address(ip_address, ip_version):
|
def is_valid_ip_address(ip_address, ip_version):
|
||||||
ip_version = ([int(ip_version)] if not isinstance(ip_version, list)
|
ip_version = ([int(ip_version)] if not isinstance(ip_version, list)
|
||||||
else ip_version)
|
else ip_version)
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
features:
|
||||||
|
- IPv6 support for Dell EMC VNX Manila driver.
|
Loading…
Reference in New Issue