"Fossies" - the Fresh Open Source Software Archive

Member "manila-8.1.3/manila/share/drivers/dell_emc/plugins/unity/client.py" (20 Jul 2020, 14023 Bytes) of package /linux/misc/openstack/manila-8.1.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "client.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 8.1.2_vs_8.1.3.

    1 # Copyright (c) 2016 EMC Corporation.
    2 # All Rights Reserved.
    3 #
    4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    5 #    not use this file except in compliance with the License. You may obtain
    6 #    a copy of the License at
    7 #
    8 #         http://www.apache.org/licenses/LICENSE-2.0
    9 #
   10 #    Unless required by applicable law or agreed to in writing, software
   11 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   13 #    License for the specific language governing permissions and limitations
   14 #    under the License.
   15 import six
   16 
   17 from oslo_log import log
   18 from oslo_utils import excutils
   19 from oslo_utils import importutils
   20 
   21 storops = importutils.try_import('storops')
   22 if storops:
   23     # pylint: disable=import-error
   24     from storops import exception as storops_ex
   25     from storops.unity import enums
   26 
   27 from manila.common import constants as const
   28 from manila import exception
   29 from manila.i18n import _
   30 from manila.share.drivers.dell_emc.common.enas import utils as enas_utils
   31 from manila.share.drivers.dell_emc.plugins.unity import utils
   32 
   33 LOG = log.getLogger(__name__)
   34 
   35 
   36 class UnityClient(object):
   37     def __init__(self, host, username, password):
   38         if storops is None:
   39             LOG.error('StorOps is required to run EMC Unity driver.')
   40         self.system = storops.UnitySystem(host, username, password)
   41 
   42     def create_cifs_share(self, resource, share_name):
   43         """Create CIFS share from the resource.
   44 
   45         :param resource: either UnityFilesystem or UnitySnap object
   46         :param share_name: CIFS share name
   47         :return: UnityCifsShare object
   48         """
   49         try:
   50             share = resource.create_cifs_share(share_name)
   51             try:
   52                 # bug on unity: the enable ace API has bug for snap
   53                 # based share.  Log the internal error if it happens.
   54                 share.enable_ace()
   55             except storops_ex.UnityException:
   56                 msg = ('Failed to enabled ACE for share: {}.')
   57                 LOG.exception(msg.format(share_name))
   58             return share
   59         except storops_ex.UnitySmbShareNameExistedError:
   60             return self.get_share(share_name, 'CIFS')
   61 
   62     def create_nfs_share(self, resource, share_name):
   63         """Create NFS share from the resource.
   64 
   65         :param resource: either UnityFilesystem or UnitySnap object
   66         :param share_name: NFS share name
   67         :return: UnityNfsShare object
   68         """
   69         try:
   70             return resource.create_nfs_share(share_name)
   71         except storops_ex.UnityNfsShareNameExistedError:
   72             return self.get_share(share_name, 'NFS')
   73 
   74     def create_nfs_filesystem_and_share(self, pool, nas_server,
   75                                         share_name, size_gb):
   76         """Create filesystem and share from pool/NAS server.
   77 
   78         :param pool: pool for file system creation
   79         :param nas_server: nas server for file system creation
   80         :param share_name: file system and share name
   81         :param size_gb: file system size
   82         """
   83         size = utils.gib_to_byte(size_gb)
   84         pool.create_nfs_share(
   85             nas_server, share_name, size, user_cap=True)
   86 
   87     def get_share(self, name, share_proto):
   88         # Validate the share protocol
   89         proto = share_proto.upper()
   90 
   91         if proto == 'CIFS':
   92             return self.system.get_cifs_share(name=name)
   93         elif proto == 'NFS':
   94             return self.system.get_nfs_share(name=name)
   95         else:
   96             raise exception.BadConfigurationException(
   97                 reason=_('Invalid NAS protocol supplied: %s.') % share_proto)
   98 
   99     @staticmethod
  100     def delete_share(share):
  101         share.delete()
  102 
  103     def create_filesystem(self, pool, nas_server, share_name, size_gb, proto):
  104         try:
  105             size = utils.gib_to_byte(size_gb)
  106             return pool.create_filesystem(nas_server,
  107                                           share_name,
  108                                           size,
  109                                           proto=proto,
  110                                           user_cap=True)
  111         except storops_ex.UnityFileSystemNameAlreadyExisted:
  112             LOG.debug('Filesystem %s already exists, '
  113                       'ignoring filesystem creation.', share_name)
  114             return self.system.get_filesystem(name=share_name)
  115 
  116     @staticmethod
  117     def delete_filesystem(filesystem):
  118         try:
  119             filesystem.delete()
  120         except storops_ex.UnityResourceNotFoundError:
  121             LOG.info('Filesystem %s is already removed.', filesystem.name)
  122 
  123     def create_nas_server(self, name, sp, pool, tenant=None):
  124         try:
  125             return self.system.create_nas_server(name, sp, pool,
  126                                                  tenant=tenant)
  127         except storops_ex.UnityNasServerNameUsedError:
  128             LOG.info('Share server %s already exists, ignoring share '
  129                      'server creation.', name)
  130             return self.get_nas_server(name)
  131 
  132     def get_nas_server(self, name):
  133         try:
  134             return self.system.get_nas_server(name=name)
  135         except storops_ex.UnityResourceNotFoundError:
  136             LOG.info('NAS server %s not found.', name)
  137             raise
  138 
  139     def delete_nas_server(self, name, username=None, password=None):
  140         tenant = None
  141         try:
  142             nas_server = self.get_nas_server(name=name)
  143             tenant = nas_server.tenant
  144             nas_server.delete(username=username, password=password)
  145         except storops_ex.UnityResourceNotFoundError:
  146             LOG.info('NAS server %s not found.', name)
  147 
  148         if tenant is not None:
  149             self._delete_tenant(tenant)
  150 
  151     @staticmethod
  152     def _delete_tenant(tenant):
  153         if tenant.nas_servers:
  154             LOG.debug('There are NAS servers belonging to the tenant %s. ',
  155                       'Do not delete it.',
  156                       tenant.get_id())
  157             return
  158         try:
  159             tenant.delete(delete_hosts=True)
  160         except storops_ex.UnityException as ex:
  161             LOG.warning('Delete tenant %(tenant)s failed with error: '
  162                         '%(ex)s. Leave the tenant on the system.',
  163                         {'tenant': tenant.get_id(),
  164                          'ex': ex})
  165 
  166     @staticmethod
  167     def create_dns_server(nas_server, domain, dns_ip):
  168         try:
  169             nas_server.create_dns_server(domain, dns_ip)
  170         except storops_ex.UnityOneDnsPerNasServerError:
  171             LOG.info('DNS server %s already exists, '
  172                      'ignoring DNS server creation.', domain)
  173 
  174     @staticmethod
  175     def create_interface(nas_server, ip_addr, netmask, gateway, port_id,
  176                          vlan_id=None, prefix_length=None):
  177         try:
  178             nas_server.create_file_interface(port_id,
  179                                              ip_addr,
  180                                              netmask=netmask,
  181                                              v6_prefix_length=prefix_length,
  182                                              gateway=gateway,
  183                                              vlan_id=vlan_id)
  184         except storops_ex.UnityIpAddressUsedError:
  185             raise exception.IPAddressInUse(ip=ip_addr)
  186 
  187     @staticmethod
  188     def enable_cifs_service(nas_server, domain, username, password):
  189         try:
  190             nas_server.enable_cifs_service(
  191                 nas_server.file_interface,
  192                 domain=domain,
  193                 domain_username=username,
  194                 domain_password=password)
  195         except storops_ex.UnitySmbNameInUseError:
  196             LOG.info('CIFS service on NAS server %s is '
  197                      'already enabled.', nas_server.name)
  198 
  199     @staticmethod
  200     def enable_nfs_service(nas_server):
  201         try:
  202             nas_server.enable_nfs_service()
  203         except storops_ex.UnityNfsAlreadyEnabledError:
  204             LOG.info('NFS service on NAS server %s is '
  205                      'already enabled.', nas_server.name)
  206 
  207     @staticmethod
  208     def create_snapshot(filesystem, name):
  209         access_type = enums.FilesystemSnapAccessTypeEnum.CHECKPOINT
  210         try:
  211             return filesystem.create_snap(name, fs_access_type=access_type)
  212         except storops_ex.UnitySnapNameInUseError:
  213             LOG.info('Snapshot %(snap)s on Filesystem %(fs)s already '
  214                      'exists.', {'snap': name, 'fs': filesystem.name})
  215 
  216     def create_snap_of_snap(self, src_snap, dst_snap_name):
  217         if isinstance(src_snap, six.string_types):
  218             snap = self.get_snapshot(name=src_snap)
  219         else:
  220             snap = src_snap
  221 
  222         try:
  223             return snap.create_snap(dst_snap_name)
  224         except storops_ex.UnitySnapNameInUseError:
  225             return self.get_snapshot(dst_snap_name)
  226 
  227     def get_snapshot(self, name):
  228         return self.system.get_snap(name=name)
  229 
  230     @staticmethod
  231     def delete_snapshot(snap):
  232         try:
  233             snap.delete()
  234         except storops_ex.UnityResourceNotFoundError:
  235             LOG.info('Snapshot %s is already removed.', snap.name)
  236 
  237     def get_pool(self, name=None):
  238         return self.system.get_pool(name=name)
  239 
  240     def get_storage_processor(self, sp_id=None):
  241         sp = self.system.get_sp(sp_id)
  242         if sp_id is None:
  243             # `sp` is a list of SPA and SPB.
  244             return [s for s in sp if s is not None and s.existed]
  245         else:
  246             return sp if sp.existed else None
  247 
  248     def cifs_clear_access(self, share_name, white_list=None):
  249         share = self.system.get_cifs_share(name=share_name)
  250         share.clear_access(white_list)
  251 
  252     def nfs_clear_access(self, share_name, white_list=None):
  253         share = self.system.get_nfs_share(name=share_name)
  254         share.clear_access(white_list, force_create_host=True)
  255 
  256     def cifs_allow_access(self, share_name, user_name, access_level):
  257         share = self.system.get_cifs_share(name=share_name)
  258 
  259         if access_level == const.ACCESS_LEVEL_RW:
  260             cifs_access = enums.ACEAccessLevelEnum.WRITE
  261         else:
  262             cifs_access = enums.ACEAccessLevelEnum.READ
  263 
  264         share.add_ace(user=user_name, access_level=cifs_access)
  265 
  266     def nfs_allow_access(self, share_name, host_ip, access_level):
  267         share = self.system.get_nfs_share(name=share_name)
  268         host_ip = enas_utils.convert_ipv6_format_if_needed(host_ip)
  269         if access_level == const.ACCESS_LEVEL_RW:
  270             share.allow_read_write_access(host_ip, force_create_host=True)
  271             share.allow_root_access(host_ip, force_create_host=True)
  272         else:
  273             share.allow_read_only_access(host_ip, force_create_host=True)
  274 
  275     def cifs_deny_access(self, share_name, user_name):
  276         share = self.system.get_cifs_share(name=share_name)
  277 
  278         try:
  279             share.delete_ace(user=user_name)
  280         except storops_ex.UnityAclUserNotFoundError:
  281             LOG.debug('ACL User "%(user)s" does not exist.',
  282                       {'user': user_name})
  283 
  284     def nfs_deny_access(self, share_name, host_ip):
  285         share = self.system.get_nfs_share(name=share_name)
  286 
  287         try:
  288             share.delete_access(host_ip)
  289         except storops_ex.UnityHostNotFoundException:
  290             LOG.info('%(host)s access to %(share)s is already removed.',
  291                      {'host': host_ip, 'share': share_name})
  292 
  293     def get_file_ports(self):
  294         ports = self.system.get_file_port()
  295         link_up_ports = []
  296         for port in ports:
  297             if port.is_link_up and self._is_external_port(port.id):
  298                 link_up_ports.append(port)
  299 
  300         return link_up_ports
  301 
  302     def extend_filesystem(self, fs, new_size_gb):
  303         size = utils.gib_to_byte(new_size_gb)
  304         try:
  305             fs.extend(size, user_cap=True)
  306         except storops_ex.UnityNothingToModifyError:
  307             LOG.debug('The size of the file system %(id)s is %(size)s '
  308                       'bytes.', {'id': fs.get_id(), 'size': size})
  309         return size
  310 
  311     def shrink_filesystem(self, share_id, fs, new_size_gb):
  312         size = utils.gib_to_byte(new_size_gb)
  313         try:
  314             fs.shrink(size, user_cap=True)
  315         except storops_ex.UnityNothingToModifyError:
  316             LOG.debug('The size of the file system %(id)s is %(size)s '
  317                       'bytes.', {'id': fs.get_id(), 'size': size})
  318         except storops_ex.UnityShareShrinkSizeTooSmallError:
  319             LOG.error('The used size of the file system %(id)s is '
  320                       'bigger than input shrink size,'
  321                       'it may cause date loss.', {'id': fs.get_id()})
  322             raise exception.ShareShrinkingPossibleDataLoss(share_id=share_id)
  323         return size
  324 
  325     @staticmethod
  326     def _is_external_port(port_id):
  327         return 'eth' in port_id or '_la' in port_id
  328 
  329     def get_tenant(self, name, vlan_id):
  330         if not vlan_id:
  331             # Do not create vlan for flat network
  332             return None
  333 
  334         tenant = None
  335         try:
  336             tenant_name = "vlan_%(vlan_id)s_%(name)s" % {'vlan_id': vlan_id,
  337                                                          'name': name}
  338             tenant = self.system.create_tenant(tenant_name, vlans=[vlan_id])
  339         except (storops_ex.UnityVLANUsedByOtherTenantError,
  340                 storops_ex.UnityTenantNameInUseError,
  341                 storops_ex.UnityVLANAlreadyHasInterfaceError):
  342             with excutils.save_and_reraise_exception() as exc:
  343                 tenant = self.system.get_tenant_use_vlan(vlan_id)
  344                 if tenant is not None:
  345                     LOG.debug("The VLAN %s is already added into a tenant. "
  346                               "Use the existing VLAN tenant.", vlan_id)
  347                     exc.reraise = False
  348         except storops_ex.SystemAPINotSupported:
  349             LOG.info("This system doesn't support tenant.")
  350 
  351         return tenant
  352 
  353     def restore_snapshot(self, snap_name):
  354         snap = self.get_snapshot(snap_name)
  355         return snap.restore(delete_backup=True)