def check_for_setup_error(self): """Return an error if the prerequisites are not met.""" if not self.configuration.maprfs_clinode_ip: msg = _( 'MapR cluster has not been specified in the configuration. ' 'Add the ip or list of ip of nodes with mapr-core installed ' 'in the "maprfs_clinode_ip" configuration parameter.') LOG.error(msg) raise exception.MapRFSException(msg=msg) if not self.configuration.maprfs_cldb_ip: LOG.warning('CLDB nodes are not specified!') if not self.configuration.maprfs_zookeeper_ip: LOG.warning('Zookeeper nodes are not specified!') if not self._check_maprfs_state(): msg = _('MapR-FS is not in healthy state.') LOG.error(msg) raise exception.MapRFSException(msg=msg) try: self._maprfs_util.maprfs_ls(os.path.join(self._base_volume_dir, '')) except exception.ProcessExecutionError: msg = _('Invalid "maprfs_base_volume_name". No such directory.') LOG.exception(msg) raise exception.MapRFSException(msg=msg)
def create_share_from_snapshot(self, context, share, snapshot, share_server=None): """Creates a share from snapshot.""" metadata = self.api.get_share_metadata(context, {'id': share['share_id']}) sn_share_tenant = self.api.get_share_metadata(context, { 'id': snapshot['share_instance']['share_id']}).get('_tenantuser') if sn_share_tenant and sn_share_tenant != metadata.get('_tenantuser'): msg = ( _('Cannot create share from snapshot %(snapshot_name)s ' 'with name %(share_name)s. Error: Tenant user should not ' 'differ from tenant of the source snapshot.') % {'snapshot_name': snapshot['name'], 'share_name': share['name']}) LOG.error(msg) raise exception.MapRFSException(msg=msg) share_dir = metadata.get('_path', self._share_dir(share['name'])) snapshot_path = self._get_snapshot_path(snapshot) self._create_share(share, metadata, context) try: if self._maprfs_util.dir_not_empty(snapshot_path): self._maprfs_util.maprfs_cp(snapshot_path + '/*', share_dir) except exception.ProcessExecutionError: msg = ( _('Failed to create share from snapshot %(snapshot_name)s ' 'with name %(share_name)s.') % { 'snapshot_name': snapshot['name'], 'share_name': share['name']}) LOG.exception(msg) raise exception.MapRFSException(msg=msg) return self._get_share_export_locations(share, path=metadata.get('_path'))
def _check_maprfs_state(self): try: return self._maprfs_util.check_state() except exception.ProcessExecutionError: msg = _('Failed to check MapRFS state.') LOG.exception(msg) raise exception.MapRFSException(msg=msg)
def update_access(self, context, share, access_rules, add_rules, delete_rules, share_server=None): """Update access rules for given share.""" for access in access_rules: if access['access_type'].lower() != 'user': msg = _("Only 'user' access type allowed!") LOG.error(msg) raise exception.InvalidShareAccess(reason=msg) volume_name = self._get_volume_name(context, share) try: # 'update_access' is called before share is removed, so this # method shouldn`t raise exception if share does # not exist actually if not self._maprfs_util.volume_exists(volume_name): LOG.warning('Can not get share %s.', share['name']) return # check update if add_rules or delete_rules: self._maprfs_util.remove_volume_ace_rules( volume_name, delete_rules) self._maprfs_util.add_volume_ace_rules(volume_name, add_rules) else: self._maprfs_util.set_volume_ace(volume_name, access_rules) except exception.ProcessExecutionError: msg = (_('Failed to update access for share %(name)s.') % { 'name': share['name'] }) LOG.exception(msg) raise exception.MapRFSException(msg=msg)
def delete_snapshot(self, context, snapshot, share_server=None): """Deletes a snapshot.""" snapshot_name = snapshot['provider_location'] or snapshot['name'] volume_name = self._get_volume_name(context, snapshot['share']) try: self._maprfs_util.delete_snapshot(snapshot_name, volume_name) except exception.ProcessExecutionError: msg = (_('Failed to delete snapshot %(snapshot_name)s.') % {'snapshot_name': snapshot['name']}) LOG.exception(msg) raise exception.MapRFSException(msg=msg)
def _create_share(self, share, metadata, context): """Creates a share.""" if share['share_proto'].lower() != 'maprfs': msg = _('Only MapRFS protocol supported!') LOG.error(msg) raise exception.MapRFSException(msg=msg) options = {k[1:]: v for k, v in metadata.items() if k[0] == '_'} share_dir = options.pop('path', self._share_dir(share['name'])) volume_name = options.pop('name', self._volume_name(share['name'])) try: self._maprfs_util.create_volume(volume_name, share_dir, share['size'], **options) # posix permissions should be 777, ACEs are used as a restriction self._maprfs_util.maprfs_chmod(share_dir, '777') except exception.ProcessExecutionError: self.api.update_share_metadata(context, {'id': share['share_id']}, {'_name': 'error'}) msg = (_('Failed to create volume in MapR-FS for the ' 'share %(share_name)s.') % { 'share_name': share['name'] }) LOG.exception(msg) raise exception.MapRFSException(msg=msg)
def delete_share(self, context, share, share_server=None): """Deletes share storage.""" volume_name = self._get_volume_name(context, share) if volume_name == "error": LOG.info(_LI("Skipping deleting share with name %s, as it does not" " exist on the backend"), share['name']) return try: self._maprfs_util.delete_volume(volume_name) except exception.ProcessExecutionError: msg = (_('Failed to delete share %(share_name)s.') % {'share_name': share['name']}) LOG.exception(msg) raise exception.MapRFSException(msg=msg)
def create_snapshot(self, context, snapshot, share_server=None): """Creates a snapshot.""" volume_name = self._get_volume_name(context, snapshot['share']) snapshot_name = snapshot['name'] try: self._maprfs_util.create_snapshot(snapshot_name, volume_name) return {'provider_location': snapshot_name} except exception.ProcessExecutionError: msg = ( _('Failed to create snapshot %(snapshot_name)s for the share ' '%(share_name)s.') % {'snapshot_name': snapshot_name, 'share_name': snapshot['share_name']}) LOG.exception(msg) raise exception.MapRFSException(msg=msg)
def _set_share_size(self, share, size): volume_name = self._get_volume_name(context.get_admin_context(), share) try: if share['size'] > size: info = self._maprfs_util.get_volume_info(volume_name) used = info['totalused'] if int(used) >= int(size) * units.Ki: raise exception.ShareShrinkingPossibleDataLoss( share_id=share['id']) self._maprfs_util.set_volume_size(volume_name, size) except exception.ProcessExecutionError: msg = (_('Failed to set space quota for the share %(share_name)s.') % {'share_name': share['name']}) LOG.exception(msg) raise exception.MapRFSException(msg=msg)
def manage_existing_snapshot(self, snapshot, driver_options): volume_name = self._get_volume_name(context.get_admin_context(), snapshot['share']) snapshot_path = self._get_snapshot_path(snapshot) try: snapshot_list = self._maprfs_util.get_snapshot_list( volume_name=volume_name) snapshot_name = snapshot['provider_location'] if snapshot_name not in snapshot_list: msg = _("Snapshot %s not found") % snapshot_name LOG.error(msg) raise exception.ManageInvalidShareSnapshot(reason=msg) size = math.ceil( float(self._maprfs_util.maprfs_du(snapshot_path)) / units.Gi) return {'size': size} except exception.ProcessExecutionError: msg = _("Manage existing share snapshot failed.") LOG.exception(msg) raise exception.MapRFSException(msg=msg)
def manage_existing(self, share, driver_options): try: # retrieve share path from export location, maprfs:// prefix and # metadata (-C -Z -N) should be casted away share_path = share['export_location'].split( )[0][len(self._maprfs_base_path):] info = self._maprfs_util.get_volume_info_by_path( share_path, check_if_exists=True) if not info: msg = _("Share %s not found") % share[ 'export_location'] LOG.error(msg) raise exception.ManageInvalidShare(reason=msg) size = math.ceil(float(info['quota']) / units.Ki) used = math.ceil(float(info['totalused']) / units.Ki) volume_name = info['volumename'] should_rename = self.rename_volume rename_option = driver_options.get('rename') if rename_option: should_rename = strutils.bool_from_string(rename_option) if should_rename: self._maprfs_util.rename_volume(volume_name, share['name']) else: self.api.update_share_metadata(context.get_admin_context(), {'id': share['share_id']}, {'_name': volume_name}) location = self._get_share_export_locations(share, path=share_path) if size == 0: size = used msg = _LW( 'Share %s has no size quota. Total used value will be' ' used as share size') LOG.warning(msg, share['name']) return {'size': size, 'export_locations': location} except (ValueError, KeyError, exception.ProcessExecutionError): msg = _('Failed to manage share.') LOG.exception(msg) raise exception.MapRFSException(msg=msg)
def _update_share_stats(self): """Retrieves stats info of share directories group.""" try: total, free = self._maprfs_util.fs_capacity() except exception.ProcessExecutionError: msg = _('Failed to check MapRFS capacity info.') LOG.exception(msg) raise exception.MapRFSException(msg=msg) total_capacity_gb = int(math.ceil(float(total) / units.Gi)) free_capacity_gb = int(math.floor(float(free) / units.Gi)) data = { 'share_backend_name': self.backend_name, 'storage_protocol': 'MAPRFS', 'driver_handles_share_servers': self.driver_handles_share_servers, 'vendor_name': 'MapR Technologies', 'driver_version': '1.0', 'total_capacity_gb': total_capacity_gb, 'free_capacity_gb': free_capacity_gb, 'snapshot_support': True, 'create_share_from_snapshot_support': True, } super(MapRFSNativeShareDriver, self)._update_share_stats(data)