manila/manila/share/drivers/emc/plugins/vnx/connection.py

921 lines
36 KiB
Python

# Copyright 2014 EMC Corporation.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""VNX backend for the EMC Manila driver."""
from oslo_utils import excutils
from oslo_utils import units
import six
from manila import db as manila_db
from manila import exception
from manila.i18n import _
from manila.i18n import _LE
from manila.i18n import _LW
from manila.openstack.common import log
from manila.share.drivers.emc.plugins import base as driver
from manila.share.drivers.emc.plugins.vnx import constants
from manila.share.drivers.emc.plugins.vnx import helper
from manila.share.drivers.emc.plugins.vnx import utils as vnx_utils
from manila import utils
VERSION = "0.1.0"
LOG = log.getLogger(__name__)
@vnx_utils.decorate_all_methods(vnx_utils.log_enter_exit,
debug_only=True)
class VNXStorageConnection(driver.StorageConnection):
"""Implements VNX specific functionality for EMC Manila driver."""
@vnx_utils.log_enter_exit
def __init__(self, *args, **kwargs):
super(VNXStorageConnection, self).__init__(*args, **kwargs)
self._mover_name = None
self._pool_name = None
self._pool = None
self._filesystems = {}
self.driver_handles_share_servers = True
def create_share(self, emc_share_driver, context, share,
share_server=None):
"""Is called to create share."""
share_name = share['name']
size = share['size'] * units.Ki
vdm = self.share_server_validation(share_server)
self.allocate_container(share_name, size, vdm['id'])
if share['share_proto'].startswith('NFS'):
location = self._create_nfs_share(share_name, vdm['name'],
share_server)
elif share['share_proto'].startswith('CIFS'):
location = self._create_cifs_share(share_name, vdm)
else:
raise exception.InvalidShare(
reason=(_('Invalid NAS protocol supplied: %s.')
% share['share_proto']))
return location
def share_server_validation(self, share_server):
"""Is called to validate the share server."""
vdm_name = None
vdm_id = None
if share_server:
backend_detail = share_server.get('backend_details')
if backend_detail:
vdm_name = backend_detail.get('share_server_name')
vdm_id = backend_detail.get('share_server_id')
if vdm_name is None or vdm_id is None:
message = _("No share server found.")
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
return {'id': vdm_id, 'name': vdm_name}
def allocate_container(self, share_name, size, vdm_id):
"""Is called to allocate container for share."""
status, out = self._XMLAPI_helper.create_file_system(
share_name, size, self._pool['id'], vdm_id)
if constants.STATUS_OK != status:
message = _("Could not create file system for %s.") % share_name
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
def allocate_container_from_snapshot(self, share, snapshot, vdm_ref):
"""Is called to create share from snapshot."""
self._replicate_snapshot(share, snapshot, self._mover_name, vdm_ref)
@vnx_utils.log_enter_exit
def _create_cifs_share(self, share_name, vdm):
"""Create cifs share."""
# Get available CIFS Server and interface
cifs_server = self._get_cifs_server_by_mover(vdm['id'])
status, out = self._XMLAPI_helper.create_cifs_share(
share_name, cifs_server['name'], vdm['id'])
if constants.STATUS_OK != status:
message = (_("Could not create CIFS share."
" Reason: %s.") % out)
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
status, out = self._NASCmd_helper.disable_cifs_access(
vdm['name'], share_name)
if constants.STATUS_OK != status:
message = _("Could not disable share access. Reason: %s.") % out
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
if len(cifs_server['interfaces']) == 0:
message = (_("CIFS server %s doesn't have interface, "
"so the share is inaccessible.")
% cifs_server['name'])
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
interface = cifs_server['interfaces'][0]
location = '//%(interface)s/%(name)s' % {'interface': interface,
'name': share_name}
return location
@vnx_utils.log_enter_exit
def _create_nfs_share(self, share_name, vdm_name, share_server):
"""Is called to create nfs share."""
status, out = self._NASCmd_helper.create_nfs_share(
share_name, vdm_name)
if constants.STATUS_OK != status:
message = (_("Could not create NFS export for share %s.")
% share_name)
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
return ('%(nfs_if)s:/%(share_name)s'
% {'nfs_if': share_server['backend_details']['nfs_if'],
'share_name': share_name})
def create_share_from_snapshot(self, emc_share_driver, context,
share, snapshot, share_server=None):
"""Is called to create share from snapshot."""
share_name = share['name']
vdm_ref = self.share_server_validation(share_server)
self.allocate_container_from_snapshot(share, snapshot, vdm_ref)
if share['share_proto'].startswith('NFS'):
self._create_nfs_share(share_name, vdm_ref['name'], share_server)
location = ('%(nfs_if)s:/%(share_name)s'
% {'nfs_if': share_server['backend_details']['nfs_if'],
'share_name': share_name})
elif share['share_proto'].startswith('CIFS'):
location = self._create_cifs_share(share_name, vdm_ref)
else:
raise exception.InvalidShare(
reason=(_('Invalid NAS protocol supplied: %s.')
% share['share_proto']))
return location
def create_snapshot(self, emc_share_driver, context, snapshot,
share_server=None):
"""Create snapshot from share."""
ckpt_name = snapshot['name']
fs_name = snapshot['share_name']
filesystem = self._get_file_system_by_name(fs_name)
status, out = self._XMLAPI_helper.create_check_point(filesystem['id'],
ckpt_name,
self._pool['id'])
if constants.STATUS_ERROR == status:
message = (_("Could not create check point. Reason: %s.")
% out['info'])
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
def delete_share(self, emc_share_driver, context, share,
share_server=None):
"""Is called to remove share."""
if share_server is None:
LOG.warn(_LW("Driver does not support share deletion without "
"share network specified. "
"Return directly because there is nothing to clean"))
return
if share['share_proto'].startswith('NFS'):
self._delete_nfs_share(share, share_server)
elif share['share_proto'].startswith('CIFS'):
self._delete_cifs_share(share, share_server)
else:
raise exception.InvalidShare(
reason='Unsupported share type')
@vnx_utils.log_enter_exit
def _delete_cifs_share(self, share, share_server):
"""Remove cifs share."""
name = share['name']
mover_name = self._get_vdm_name(share_server)
mover_id = self._get_vdm_id(share_server)
status, share_obj = self._XMLAPI_helper.get_cifs_share_by_name(name)
if constants.STATUS_NOT_FOUND == status:
LOG.warn(_LW("CIFS share %s not found. Skip the deletion"), name)
else:
mover_id = share_obj['mover']
# Delete CIFS export
status, out = self._XMLAPI_helper.delete_cifs_share(
name,
mover_id,
share_obj['CifsServers'],
share_obj['moverIdIsVdm'])
if constants.STATUS_OK != status:
error = (_("Deleting CIFS share %(share_name)s on "
"%(mover)s failed."
" Reason: %(err)s")
% {'share_name': name,
'mover': mover_name,
'err': out})
LOG.error(error)
raise exception.EMCVnxXMLAPIError(err=error)
self._deallocate_container(name, mover_name, mover_id)
@vnx_utils.log_enter_exit
def _delete_nfs_share(self, share, share_server):
"""Remove nfs share."""
name = share['name']
path = '/' + name
mover_name = self._get_vdm_name(share_server)
mover_id = self._get_vdm_id(share_server)
status, share_obj = self._NASCmd_helper.get_nfs_share_by_path(
path,
mover_name)
if constants.STATUS_NOT_FOUND == status:
LOG.warn(_LW("NFS share %s not found. Skip the deletion"), name)
else:
# Delete NFS export if it is present
status, out = self._NASCmd_helper.delete_nfs_share(
path, mover_name)
if constants.STATUS_OK != status:
error = (_("Deleting NFS share %(share_name)s on "
"%(mover_name)s failed. Reason: %(err)s")
% {'share_name': name,
'mover_name': mover_name,
'err': out})
LOG.error(error)
raise exception.EMCVnxXMLAPIError(err=error)
self._deallocate_container(name, mover_name, mover_id)
@vnx_utils.log_enter_exit
def _deallocate_container(self, share_name, vdm_name, vdm_id=None):
"""Delete underneath objects of the share."""
# Delete mount point
name = share_name
path = '/' + name
if vdm_id is None:
vdm = self.get_vdm_by_name(vdm_name, allow_absence=True)
vdm_id = vdm['id'] if vdm else None
if vdm_id is not None:
status, out = self._XMLAPI_helper.delete_mount_point(
vdm_id,
path,
'true')
if constants.STATUS_OK != status:
if self._XMLAPI_helper._is_mount_point_unexist_error(out):
LOG.warn(_LW("Mount point %(path)s on %(vdm)s not found."),
{'path': path, 'vdm': vdm_name})
else:
LOG.warn(_LW("Deleting mount point %(path)s on "
"%(mover_name)s failed. Reason: %(err)s"),
{'path': path,
'mover_name': vdm_name,
'err': out})
else:
LOG.warn(_LW("Failed to find the VDM. Try to "
"delete the file system"))
self._delete_filesystem(name)
@vnx_utils.log_enter_exit
def _delete_filesystem(self, name):
filesystem = self._get_file_system_by_name(name,
allow_absence=True)
if not filesystem:
LOG.warn(_LW("File system %s not found. Skip the deletion"), name)
return
# Delete file system
status, out = self._XMLAPI_helper.delete_file_system(filesystem['id'])
if constants.STATUS_OK != status:
message = (_("Failed to delete file system %(fsid)s. "
"Reason: %(err)s.")
% {'fsid': filesystem['id'],
'err': out})
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
def delete_snapshot(self, emc_share_driver, context, snapshot,
share_server=None):
"""Remove share's snapshot."""
ckpt_name = snapshot['name']
status, ckpt = self._XMLAPI_helper.get_check_point_by_name(ckpt_name)
if constants.STATUS_OK != status:
LOG.warn(_LW("Check point not found. Reason: %s."), status)
return
if ckpt['id'] == '':
LOG.warn(_LW("Snapshot: %(name)s not found. "
"Skip the deletion.") % {'name': snapshot['name']})
return
status, out = self._XMLAPI_helper.delete_check_point(ckpt['id'])
if constants.STATUS_OK != status:
message = (_("Could not delete check point. Reason: %s.")
% out['info'])
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
def ensure_share(self, emc_share_driver,
context, share,
share_server=None):
"""Invoked to ensure that share is exported."""
pass
def allow_access(self, emc_share_driver, context, share, access,
share_server=None):
"""Allow access to the share."""
if share['share_proto'].startswith('NFS'):
self._nfs_allow_access(context, share, access, share_server)
elif share['share_proto'].startswith('CIFS'):
self._cifs_allow_access(context, share, access, share_server)
else:
raise exception.InvalidShare(
reason=(_('Invalid NAS protocol supplied: %s.')
% share['share_proto']))
@vnx_utils.log_enter_exit
def _cifs_allow_access(self, context, share, access, share_server):
"""Allow access to cifs share."""
self._ensure_access_type_for_cifs(access)
network_id = share['share_network_id']
share_network = manila_db.share_network_get(context, network_id)
security_services = share_network['security_services']
self._ensure_security_service_for_cifs(security_services)
share_name = share['name']
mover_name = self._get_vdm_name(share_server)
user_name = access['access_to']
status, out = self._NASCmd_helper.allow_cifs_access(
mover_name,
share_name,
user_name,
security_services[0]['domain'])
if constants.STATUS_OK != status:
message = _("Could not allow CIFS access. Reason: %s.") % out
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
@vnx_utils.log_enter_exit
def _nfs_allow_access(self, context, share, access, share_server):
"""Allow access to nfs share."""
share_path = '/' + share['name']
access_type = access['access_type']
if access_type != 'ip':
reason = _('Only ip access type allowed.')
raise exception.InvalidShareAccess(reason)
host_ip = access['access_to']
mover_name = self._get_vdm_name(share_server)
status, reason = self._NASCmd_helper.allow_nfs_share_access(
share_path, host_ip, mover_name)
if constants.STATUS_OK != status:
message = (_("Could not allow access to NFS share. Reason: %s.")
% reason)
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
def deny_access(self, emc_share_driver, context, share, access,
share_server=None):
"""Deny access to the share."""
if share['share_proto'].startswith('NFS'):
self._nfs_deny_access(share, access, share_server)
elif share['share_proto'].startswith('CIFS'):
self._cifs_deny_access(context, share, access, share_server)
else:
raise exception.InvalidShare(
reason=_('Unsupported share type'))
@vnx_utils.log_enter_exit
def _cifs_deny_access(self, context, share, access, share_server):
"""Deny access to cifs share."""
self._ensure_access_type_for_cifs(access)
network_id = share['share_network_id']
share_network = manila_db.share_network_get(context, network_id)
security_services = share_network['security_services']
self._ensure_security_service_for_cifs(security_services)
share_name = share['name']
mover_name = self._get_vdm_name(share_server)
user_name = access['access_to']
status, out = self._NASCmd_helper.deny_cifs_access(
mover_name,
share_name,
user_name,
security_services[0]['domain'])
if constants.STATUS_OK != status:
message = (_("Could not deny access to CIFS share. Reason: %s.")
% out)
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
@vnx_utils.log_enter_exit
def _nfs_deny_access(self, share, access, share_server):
"""Deny access to nfs share."""
share_path = '/' + share['name']
access_type = access['access_type']
if access_type != 'ip':
reason = _('Only ip access type allowed.')
raise exception.InvalidShareAccess(reason)
host_ip = access['access_to']
mover_name = self._get_vdm_name(share_server)
status, reason = self._NASCmd_helper.deny_nfs_share_access(
share_path, host_ip, mover_name)
if constants.STATUS_OK != status:
message = (_("Could not deny access to NFS share. Reason: %s.")
% reason)
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
def check_for_setup_error(self, emc_share_driver):
"""Check for setup error."""
pass
def connect(self, emc_share_driver, context):
"""Try to connect to VNX NAS server."""
self._mover_name = (
emc_share_driver.configuration.emc_nas_server_container)
self._pool_name = emc_share_driver.configuration.emc_nas_pool_name
configuration = emc_share_driver.configuration
self._XMLAPI_helper = helper.XMLAPIHelper(configuration)
self._NASCmd_helper = helper.NASCommandHelper(configuration)
# To verify the input from manila configuration
self.get_mover_ref_by_name(self._mover_name)
self._pool = self._get_available_pool_by_name(self._pool_name)
def update_share_stats(self, stats_dict):
"""Communicate with EMCNASClient to get the stats."""
stats_dict['driver_version'] = VERSION
pool = self._get_available_pool_by_name(self._pool_name)
stats_dict['total_capacity_gb'] = pool['total_size']
stats_dict['free_capacity_gb'] = (
int(pool['total_size']) - int(pool['used_size']))
def get_network_allocations_number(self, emc_share_driver):
"""Returns number of network allocations for creating VIFs."""
return constants.IP_ALLOCATIONS
def setup_server(self, emc_share_driver, network_info, metadata=None):
"""Set up and configures share server with given network parameters."""
# Only support single security service with type 'active_directory'
interface_info = []
vdm_name = 'vdm-' + network_info['server_id']
vlan_id = network_info['segmentation_id']
active_directory = None
sec_services = []
if network_info.get('security_services'):
sec_services = network_info['security_services']
is_valid, data = self._get_valid_security_service(
sec_services)
if is_valid:
active_directory = data
else:
LOG.error(data)
raise exception.EMCVnxXMLAPIError(err=data)
try:
# Refresh DataMover/VDM by the configuration
moverRef = self.get_mover_ref_by_name(self._mover_name)
if not self._vdm_exist(vdm_name):
LOG.debug('Share Server %s not found. Creating', vdm_name)
self._create_vdm(vdm_name, moverRef)
status, vdmRef = self._XMLAPI_helper.get_vdm_by_name(vdm_name)
if constants.STATUS_OK != status:
message = (_('Could not get Share Server by name %(name)s. '
'Reason: %(err)s.')
% {'name': vdm_name,
'err': vdmRef})
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
netmask = utils.cidr_to_netmask(network_info['cidr'])
allocated_interfaces = []
device_port = self._get_device_port(moverRef)
for net_info in network_info['network_allocations']:
ip = net_info['ip_address']
if_name = 'if-' + net_info['id'][-12:]
if_info = {'ip': ip, 'if_name': if_name}
interface_info.append(if_info)
status, interface = self._XMLAPI_helper.create_mover_interface(
if_name,
device_port['name'],
ip,
moverRef['id'],
netmask,
vlan_id)
if constants.STATUS_OK != status:
message = (_('Interface creation failed. Reason: %s.')
% interface)
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
allocated_interfaces.append(interface)
if active_directory:
self._configure_active_directory(
active_directory, vdmRef,
allocated_interfaces[0])
self._enable_nfs_service(vdmRef, allocated_interfaces[1])
return {
'share_server_name': vdm_name,
'share_server_id': vdmRef['id'],
'cifs_if': allocated_interfaces[0]['ip'],
'nfs_if': allocated_interfaces[1]['ip'],
}
except Exception as ex:
with excutils.save_and_reraise_exception():
LOG.error(_LE('Could not setup server. Reason: %s.'), ex)
server_details = self._contruct_backend_details(
vdm_name, vdmRef, interface_info)
self.teardown_server(None, server_details, sec_services)
def _contruct_backend_details(self, vdm_name, vdmRef, interfaces):
vdm_id = vdmRef['id'] if vdmRef else ""
if_number = len(interfaces)
cifs_if = interfaces[0]['ip'] if if_number > 0 else None
nfs_if = interfaces[1]['ip'] if if_number > 1 else None
return {
'share_server_name': vdm_name,
'share_server_id': vdm_id,
'cifs_if': cifs_if,
'nfs_if': nfs_if,
}
@vnx_utils.log_enter_exit
def _vdm_exist(self, name, id=None):
status, vdmRef = self._XMLAPI_helper.get_vdm_by_name(name)
if constants.STATUS_OK != status:
return False
if id and vdmRef['id'] != id:
return False
return True
def _create_vdm(self, vdm_name, moverRef):
"""Create a new VDM as a share sever."""
status, out = self._XMLAPI_helper.create_vdm(vdm_name, moverRef['id'])
if constants.STATUS_OK != status:
message = _('Could not create VDM %s.') % vdm_name
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
def _get_device_port(self, moverRef):
"""Get a proper network device to create interface."""
status, mover = self._XMLAPI_helper.get_mover_by_id(moverRef['id'])
if constants.STATUS_OK != status:
message = (_("Could not get physical device port "
"on mover (id:%s).")
% moverRef['id'])
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
device_ports = mover['devices']
return device_ports[0]
def _configure_active_directory(self, security_service, vdmRef, interface):
moverRef = self.get_mover_ref_by_name(self._mover_name)
self._configure_dns(security_service, moverRef)
data = {
'mover_id': vdmRef['id'],
'compName': vdmRef['name'],
'netbios': vdmRef['name'][-14:],
'domain': security_service['domain'],
'admin_username': security_service['user'],
'admin_password': security_service['password'],
'interface': interface['ip'],
'alias': [vdmRef['name'][-12:]],
}
status, out = self._XMLAPI_helper.create_cifs_server(data)
if constants.STATUS_ERROR == status:
message = (_('Failed to create cifs server %(name)s.'
'Reason: %(err)s.')
% {'name': data['compName'],
'err': out})
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
def _configure_dns(self, security_service, moverRef):
domain = security_service['domain']
server = security_service['dns_ip']
status, out = self._XMLAPI_helper.create_dns_domain(moverRef['id'],
domain,
server)
if constants.STATUS_OK != status:
message = _("Could not create DNS domain. Reason: %s.") % out
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
def _enable_nfs_service(self, vdmRef, interface):
self._NASCmd_helper.enable_nfs_service(vdmRef['name'],
interface['name'])
def teardown_server(self, emc_share_driver, server_details,
security_services=None):
"""Teardown share server."""
if not server_details:
LOG.debug('Server details are empty.')
return
vdm_name = server_details['share_server_name']
vdm_id = server_details['share_server_id']
cifs_if = server_details['cifs_if']
nfs_if = server_details['nfs_if']
status, vdmRef = self._XMLAPI_helper.get_vdm_by_name(vdm_name)
if constants.STATUS_OK != status or vdmRef['id'] != vdm_id:
LOG.debug('Share server %s not found.', vdm_name)
return
self._disable_nfs_service(vdm_name)
if security_services:
# Only support single security service with type 'active_directory'
is_valid, active_directory = self._get_valid_security_service(
security_services)
if is_valid and active_directory:
status, cifs_servers = self._XMLAPI_helper.get_cifs_servers(
vdm_id)
if constants.STATUS_OK != status:
LOG.error(_LE('Could not find CIFS server by name: %s.'),
vdm_name)
for server in cifs_servers:
# Unjoin CIFS Server from domain
data = {
'name': server['name'],
'join_domain': 'false',
'admin_username': active_directory['user'],
'admin_password': active_directory['password'],
'mover_id': vdm_id,
}
self._XMLAPI_helper.modify_cifs_server(data)
# Delete CIFS Server
self._XMLAPI_helper.delete_cifs_server(server['name'],
vdm_id)
# Delete interface from Data Mover
if cifs_if:
self._XMLAPI_helper.delete_mover_interface(
cifs_if,
vdmRef['host_mover_id'])
if nfs_if:
self._XMLAPI_helper.delete_mover_interface(
nfs_if,
vdmRef['host_mover_id'])
# Delete Virtual Data Mover
self._XMLAPI_helper.delete_vdm(vdmRef['id'])
@vnx_utils.log_enter_exit
def _disable_nfs_service(self, vdm_name):
interfaces = self._NASCmd_helper.get_interfaces_by_vdm(vdm_name)
for if_name in interfaces['vdm']:
self._NASCmd_helper.disable_nfs_service(vdm_name, if_name)
@vnx_utils.log_enter_exit
def _get_available_pool_by_name(self, name):
status, out = self._XMLAPI_helper.list_storage_pool()
if constants.STATUS_OK != status:
LOG.error(_LE("Could not get storage pool list."))
for pool in out:
if name == pool['name']:
self._pool = pool
break
if self._pool is None:
message = (_("Could not find the storage pool by name: %s.")
% name)
LOG.error(message)
raise exception.InvalidParameterValue(err=message)
return self._pool
def get_mover_ref_by_name(self, name):
status, mover = self._XMLAPI_helper.get_mover_ref_by_name(name)
if constants.STATUS_ERROR == status:
message = _("Could not find Data Mover by name: %s.") % name
LOG.error(message)
raise exception.InvalidParameterValue(err=message)
return mover
def get_vdm_by_name(self, name, allow_absence=False):
status, vdm = self._XMLAPI_helper.get_vdm_by_name(name)
if constants.STATUS_OK != status:
if allow_absence and constants.STATUS_NOT_FOUND == status:
return None
else:
message = (_("Could not find Virtual Data Mover by name: %s.")
% name)
LOG.error(message)
raise exception.InvalidParameterValue(err=message)
return vdm
def _get_mover_by_id(self, mover_id):
status, mover = self._XMLAPI_helper.get_mover_by_id(mover_id)
if constants.STATUS_OK != status:
message = _("Could not find Data Mover by id: %s.") % mover_id
LOG.error(message)
raise exception.InvalidParameterValue(err=message)
return mover
def _get_cifs_server_by_mover(self, mover_id):
status, servers = self._XMLAPI_helper.get_cifs_servers(mover_id)
if constants.STATUS_OK != status:
message = _("Could not get CIFS server list for %s.") % mover_id
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
if len(servers) == 0:
message = (_("Could not find the CIFS servers on VDM: %s.")
% mover_id)
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
return servers[0]
def _get_file_system_by_name(self, name, allow_absence=False):
status, filesystem = self._XMLAPI_helper.get_file_system_by_name(name)
if constants.STATUS_OK != status:
if allow_absence and constants.STATUS_NOT_FOUND == status:
return None
else:
message = _("Could not get file system by name: %s.") % name
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
return filesystem
def _replicate_snapshot(self, share, snapshot, mover_name, vdm_ref):
# Source snapshot name
ckpt_name = snapshot['name']
# Source file system name
source_share = snapshot['share_name']
# Target file system name
fs_name = share['name']
fs_size = share['size'] * units.Ki
interconn_id = self._NASCmd_helper.get_interconnect_id(
mover_name, mover_name)
# Run NAS command to copy ckpt to a fs
status, msg = self._NASCmd_helper.create_fs_from_ckpt(
fs_name,
vdm_ref['name'],
ckpt_name,
source_share,
self._pool['name'],
interconn_id
)
if constants.STATUS_OK != status:
message = _("Copy content from checkpoint to"
" file system failed. Reason: %s.") % msg
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
# Query the new created file system
filesystem = self._get_file_system_by_name(fs_name)
# Keep the compatibility for both Python2.x and Python 3.x
if six.PY2:
source_fs_size = long(filesystem['size'])
else:
source_fs_size = int(filesystem['size'])
if source_fs_size < fs_size:
status, out = self._XMLAPI_helper.extend_file_system(
filesystem['id'],
self._pool['id'],
fs_size - source_fs_size
)
if constants.STATUS_OK != status:
message = (_("Extend the file system failed. Reason: %s.")
% out)
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
def _get_mount_point_by_filesystem(self, filesystem, mover):
status, out = self._XMLAPI_helper.get_mount_point(mover['id'])
if constants.STATUS_OK != status:
LOG.error(_LE("Could not get mount point. Reason: %s."), out)
for mount in out:
if mount['fs_id'] == filesystem['id']:
return mount
def _get_vdm_name(self, share_server):
try:
return share_server['backend_details']['share_server_name']
except Exception:
LOG.debug("Didn't get share server name from share_server %s",
share_server)
return 'vdm-' + share_server['id']
def _get_vdm_id(self, share_server):
try:
return share_server['backend_details']['share_server_id']
except Exception:
LOG.debug("Didn't get share server id from share_server %s",
share_server)
return None
def _get_valid_security_service(self, security_services):
"""Validate security services and return a supported security service.
:param security_services:
:return: (<is_valid>, <data>)
<is_valid> is true to indicate security_services includes zero or
single security service for active directory. Otherwise, it
would return false.
<data> return error message when <is_valid> is false. Otherwise,
it will return zero or single security service for active
directory.
"""
# Only support single security service with type 'active_directory'
service_number = len(security_services)
if service_number == 0:
return True, None
if (service_number > 1 or
security_services[0]['type'] != 'active_directory'):
return False, _("Unsupported Security Services. "
"Only support single security service and "
"only support type 'active_directory'")
return True, security_services[0]
def _ensure_access_type_for_cifs(self, access):
if access['access_type'] != 'user':
msg = _('Only user access type allowed for cifs share')
raise exception.EMCVnxXMLAPIError(err=msg)
def _ensure_security_service_for_cifs(self, security_services):
if (len(security_services) != 1 or
security_services[0]['type'] != 'active_directory'):
msg = _("Only single security service with "
"type 'active_directory' supported")
raise exception.EMCVnxXMLAPIError(err=msg)