Ejemplo n.º 1
0
    def create_share_from_snapshot(self,
                                   context,
                                   share,
                                   snapshot,
                                   share_server=None):
        old_gmgr = self._share_manager(snapshot['share_instance'])

        # Snapshot clone feature in GlusterFS server essential to support this
        # API is available in GlusterFS server versions 3.7 and higher. So do
        # a version check.
        vers = self.glusterfs_versions[old_gmgr.host_access]
        minvers = (3, 7)
        if common.numreduct(vers) < minvers:
            minvers_str = '.'.join(six.text_type(c) for c in minvers)
            vers_str = '.'.join(vers)
            msg = (_("GlusterFS version %(version)s on server %(server)s does "
                     "not support creation of shares from snapshot. "
                     "minimum requirement: %(minversion)s") % {
                         'version': vers_str,
                         'server': old_gmgr.host,
                         'minversion': minvers_str
                     })
            LOG.error(msg)
            raise exception.GlusterfsException(msg)

        # Clone the snapshot. The snapshot clone, a new GlusterFS volume
        # would serve as a share.
        backend_snapshot_name = self._find_actual_backend_snapshot_name(
            old_gmgr, snapshot)
        volume = ''.join(['manila-', share['id']])
        args_tuple = (('snapshot', 'activate', backend_snapshot_name, 'force',
                       '--mode=script'), ('snapshot', 'clone', volume,
                                          backend_snapshot_name))
        for args in args_tuple:
            out, err = old_gmgr.gluster_call(
                *args, log=("Creating share from snapshot"))

        # Get a manager for the new volume/share.
        comp_vol = old_gmgr.components.copy()
        comp_vol.update({'volume': volume})
        gmgr = self._glustermanager(comp_vol)
        export = self.driver._setup_via_manager(
            {
                'share': share,
                'manager': gmgr
            }, {
                'share': snapshot['share_instance'],
                'manager': old_gmgr
            })

        argseq = (('set', [USER_CLONED_FROM, snapshot['share_id']]),
                  ('set', [USER_MANILA_SHARE, share['id']]), ('start', []))
        for op, opargs in argseq:
            args = ['volume', op, gmgr.volume] + opargs
            gmgr.gluster_call(*args, log=("Creating share from snapshot"))

        self.gluster_used_vols.add(gmgr.qualified)
        self.private_storage.update(share['id'], {'volume': gmgr.qualified})

        return export
Ejemplo n.º 2
0
    def do_setup(self, context):
        """Setup the GlusterFS volumes."""
        glusterfs_versions, exceptions = {}, {}
        for srvaddr in self.configuration.glusterfs_servers:
            try:
                glusterfs_versions[srvaddr] = self._glustermanager(
                    srvaddr, False).get_gluster_version()
            except exception.GlusterfsException as exc:
                exceptions[srvaddr] = six.text_type(exc)
        if exceptions:
            for srvaddr, excmsg in exceptions.items():
                LOG.error(
                    "'gluster version' failed on server "
                    "%(server)s with: %(message)s", {
                        'server': srvaddr,
                        'message': excmsg
                    })
            raise exception.GlusterfsException(
                _("'gluster version' failed on servers %s") %
                (','.join(exceptions.keys())))
        notsupp_servers = []
        for srvaddr, vers in glusterfs_versions.items():
            if common.numreduct(vers) < self.driver.GLUSTERFS_VERSION_MIN:
                notsupp_servers.append(srvaddr)
        if notsupp_servers:
            gluster_version_min_str = '.'.join(
                six.text_type(c) for c in self.driver.GLUSTERFS_VERSION_MIN)
            for srvaddr in notsupp_servers:
                LOG.error(
                    "GlusterFS version %(version)s on server "
                    "%(server)s is not supported, "
                    "minimum requirement: %(minvers)s", {
                        'server': srvaddr,
                        'version': '.'.join(glusterfs_versions[srvaddr]),
                        'minvers': gluster_version_min_str
                    })
            raise exception.GlusterfsException(
                _("Unsupported GlusterFS version on servers %(servers)s, "
                  "minimum requirement: %(minvers)s") % {
                      'servers': ','.join(notsupp_servers),
                      'minvers': gluster_version_min_str
                  })
        self.glusterfs_versions = glusterfs_versions

        gluster_volumes_initial = set(
            self._fetch_gluster_volumes(filter_used=False))
        if not gluster_volumes_initial:
            # No suitable volumes are found on the Gluster end.
            # Raise exception.
            msg = (_("Gluster backend does not provide any volume "
                     "matching pattern %s") %
                   self.configuration.glusterfs_volume_pattern)
            LOG.error(msg)
            raise exception.GlusterfsException(msg)

        LOG.info("Found %d Gluster volumes allocated for Manila.",
                 len(gluster_volumes_initial))

        self._check_mount_glusterfs()
Ejemplo n.º 3
0
    def create_share_from_snapshot(self, context, share, snapshot,
                                   share_server=None):
        old_gmgr = self._share_manager(snapshot['share_instance'])

        # Snapshot clone feature in GlusterFS server essential to support this
        # API is available in GlusterFS server versions 3.7 and higher. So do
        # a version check.
        vers = self.glusterfs_versions[old_gmgr.host_access]
        minvers = (3, 7)
        if common.numreduct(vers) < minvers:
            minvers_str = '.'.join(six.text_type(c) for c in minvers)
            vers_str = '.'.join(vers)
            msg = (_("GlusterFS version %(version)s on server %(server)s does "
                     "not support creation of shares from snapshot. "
                     "minimum requirement: %(minversion)s") %
                   {'version': vers_str, 'server': old_gmgr.host,
                    'minversion': minvers_str})
            LOG.error(msg)
            raise exception.GlusterfsException(msg)

        # Clone the snapshot. The snapshot clone, a new GlusterFS volume
        # would serve as a share.
        backend_snapshot_name = self._find_actual_backend_snapshot_name(
            old_gmgr, snapshot)
        volume = ''.join(['manila-', share['id']])
        args_tuple = (('snapshot', 'activate', backend_snapshot_name,
                      'force', '--mode=script'),
                      ('snapshot', 'clone', volume, backend_snapshot_name))
        for args in args_tuple:
            out, err = old_gmgr.gluster_call(
                *args,
                log=("Creating share from snapshot"))

        # Get a manager for the new volume/share.
        comp_vol = old_gmgr.components.copy()
        comp_vol.update({'volume': volume})
        gmgr = self._glustermanager(comp_vol)
        export = self.driver._setup_via_manager(
            {'share': share, 'manager': gmgr},
            {'share': snapshot['share_instance'], 'manager': old_gmgr})

        argseq = (('set',
                   [USER_CLONED_FROM, snapshot['share_id']]),
                  ('set', [USER_MANILA_SHARE, share['id']]),
                  ('start', []))
        for op, opargs in argseq:
            args = ['volume', op, gmgr.volume] + opargs
            gmgr.gluster_call(*args, log=("Creating share from snapshot"))

        self.gluster_used_vols.add(gmgr.qualified)
        self.private_storage.update(share['id'], {'volume': gmgr.qualified})

        return export
Ejemplo n.º 4
0
    def do_setup(self, context):
        """Setup the GlusterFS volumes."""
        glusterfs_versions, exceptions = {}, {}
        for srvaddr in self.configuration.glusterfs_servers:
            try:
                glusterfs_versions[srvaddr] = self._glustermanager(
                    srvaddr, False).get_gluster_version()
            except exception.GlusterfsException as exc:
                exceptions[srvaddr] = six.text_type(exc)
        if exceptions:
            for srvaddr, excmsg in exceptions.items():
                LOG.error("'gluster version' failed on server "
                          "%(server)s with: %(message)s",
                          {'server': srvaddr, 'message': excmsg})
            raise exception.GlusterfsException(_(
                "'gluster version' failed on servers %s") % (
                ','.join(exceptions.keys())))
        notsupp_servers = []
        for srvaddr, vers in glusterfs_versions.items():
            if common.numreduct(vers) < self.driver.GLUSTERFS_VERSION_MIN:
                notsupp_servers.append(srvaddr)
        if notsupp_servers:
            gluster_version_min_str = '.'.join(
                six.text_type(c) for c in self.driver.GLUSTERFS_VERSION_MIN)
            for srvaddr in notsupp_servers:
                LOG.error("GlusterFS version %(version)s on server "
                          "%(server)s is not supported, "
                          "minimum requirement: %(minvers)s",
                          {'server': srvaddr,
                           'version': '.'.join(glusterfs_versions[srvaddr]),
                           'minvers': gluster_version_min_str})
            raise exception.GlusterfsException(_(
                "Unsupported GlusterFS version on servers %(servers)s, "
                "minimum requirement: %(minvers)s") % {
                'servers': ','.join(notsupp_servers),
                'minvers': gluster_version_min_str})
        self.glusterfs_versions = glusterfs_versions

        gluster_volumes_initial = set(
            self._fetch_gluster_volumes(filter_used=False))
        if not gluster_volumes_initial:
            # No suitable volumes are found on the Gluster end.
            # Raise exception.
            msg = (_("Gluster backend does not provide any volume "
                     "matching pattern %s"
                     ) % self.configuration.glusterfs_volume_pattern)
            LOG.error(msg)
            raise exception.GlusterfsException(msg)

        LOG.info("Found %d Gluster volumes allocated for Manila.",
                 len(gluster_volumes_initial))

        self._check_mount_glusterfs()
Ejemplo n.º 5
0
    def _wipe_gluster_vol(self, gluster_mgr):

        # Create a temporary mount.
        gluster_export = gluster_mgr.export
        tmpdir = tempfile.mkdtemp()
        try:
            common._mount_gluster_vol(self.driver._execute, gluster_export,
                                      tmpdir)
        except exception.GlusterfsException:
            shutil.rmtree(tmpdir, ignore_errors=True)
            raise

        # Delete the contents of a GlusterFS volume that is temporarily
        # mounted.
        # From GlusterFS version 3.7, two directories, '.trashcan' at the root
        # of the GlusterFS volume and 'internal_op' within the '.trashcan'
        # directory, are internally created when a GlusterFS volume is started.
        # GlusterFS does not allow unlink(2) of the two directories. So do not
        # delete the paths of the two directories, but delete their contents
        # along with the rest of the contents of the volume.
        srvaddr = gluster_mgr.host_access
        if common.numreduct(self.glusterfs_versions[srvaddr]) < (3, 7):
            cmd = ['find', tmpdir, '-mindepth', '1', '-delete']
        else:
            ignored_dirs = map(lambda x: os.path.join(tmpdir, *x),
                               [('.trashcan', ), ('.trashcan', 'internal_op')])
            ignored_dirs = list(ignored_dirs)
            cmd = [
                'find', tmpdir, '-mindepth', '1', '!', '-path',
                ignored_dirs[0], '!', '-path', ignored_dirs[1], '-delete'
            ]

        try:
            self.driver._execute(*cmd, run_as_root=True)
        except exception.ProcessExecutionError as exc:
            msg = (_("Error trying to wipe gluster volume. "
                     "gluster_export: %(export)s, Error: %(error)s") % {
                         'export': gluster_export,
                         'error': exc.stderr
                     })
            LOG.error(msg)
            raise exception.GlusterfsException(msg)
        finally:
            # Unmount.
            common._umount_gluster_vol(self.driver._execute, tmpdir)
            shutil.rmtree(tmpdir, ignore_errors=True)
Ejemplo n.º 6
0
    def create_snapshot(self, context, snapshot, share_server=None):
        """Creates a snapshot."""

        gluster_mgr = self._share_manager(snapshot['share'])
        if gluster_mgr.qualified in self.gluster_nosnap_vols_dict:
            opret, operrno = -1, 0
            operrstr = self.gluster_nosnap_vols_dict[gluster_mgr.qualified]
        else:
            args = ('--xml', 'snapshot', 'create', 'manila-' + snapshot['id'],
                    gluster_mgr.volume)
            out, err = gluster_mgr.gluster_call(*args,
                                                log=("Retrieving volume info"))

            if not out:
                raise exception.GlusterfsException(
                    'gluster volume info %s: no data received' %
                    gluster_mgr.volume)

            outxml = etree.fromstring(out)
            opret = int(common.volxml_get(outxml, 'opRet'))
            operrno = int(common.volxml_get(outxml, 'opErrno'))
            operrstr = common.volxml_get(outxml, 'opErrstr', default=None)

        if opret == -1:
            vers = self.glusterfs_versions[gluster_mgr.host_access]
            if common.numreduct(vers) > (3, 6):
                # This logic has not yet been implemented in GlusterFS 3.6
                if operrno == 0:
                    self.gluster_nosnap_vols_dict[
                        gluster_mgr.qualified] = operrstr
                    msg = _("Share %(share_id)s does not support snapshots: "
                            "%(errstr)s.") % {
                                'share_id': snapshot['share_id'],
                                'errstr': operrstr
                            }
                    LOG.error(msg)
                    raise exception.ShareSnapshotNotSupported(msg)
            raise exception.GlusterfsException(
                _("Creating snapshot for share %(share_id)s failed "
                  "with %(errno)d: %(errstr)s") % {
                      'share_id': snapshot['share_id'],
                      'errno': operrno,
                      'errstr': operrstr
                  })
Ejemplo n.º 7
0
    def create_snapshot(self, context, snapshot, share_server=None):
        """Creates a snapshot."""

        gluster_mgr = self._share_manager(snapshot['share'])
        if gluster_mgr.qualified in self.gluster_nosnap_vols_dict:
            opret, operrno = -1, 0
            operrstr = self.gluster_nosnap_vols_dict[gluster_mgr.qualified]
        else:
            args = ('--xml', 'snapshot', 'create', 'manila-' + snapshot['id'],
                    gluster_mgr.volume)
            out, err = gluster_mgr.gluster_call(
                *args,
                log=("Retrieving volume info"))

            if not out:
                raise exception.GlusterfsException(
                    'gluster volume info %s: no data received' %
                    gluster_mgr.volume
                )

            outxml = etree.fromstring(out)
            opret = int(common.volxml_get(outxml, 'opRet'))
            operrno = int(common.volxml_get(outxml, 'opErrno'))
            operrstr = common.volxml_get(outxml, 'opErrstr', default=None)

        if opret == -1:
            vers = self.glusterfs_versions[gluster_mgr.host_access]
            if common.numreduct(vers) > (3, 6):
                # This logic has not yet been implemented in GlusterFS 3.6
                if operrno == 0:
                    self.gluster_nosnap_vols_dict[
                        gluster_mgr.qualified] = operrstr
                    msg = _("Share %(share_id)s does not support snapshots: "
                            "%(errstr)s.") % {'share_id': snapshot['share_id'],
                                              'errstr': operrstr}
                    LOG.error(msg)
                    raise exception.ShareSnapshotNotSupported(msg)
            raise exception.GlusterfsException(
                _("Creating snapshot for share %(share_id)s failed "
                  "with %(errno)d: %(errstr)s") % {
                      'share_id': snapshot['share_id'],
                      'errno': operrno,
                      'errstr': operrstr})
Ejemplo n.º 8
0
    def _wipe_gluster_vol(self, gluster_mgr):

        # Create a temporary mount.
        gluster_export = gluster_mgr.export
        tmpdir = tempfile.mkdtemp()
        try:
            common._mount_gluster_vol(self.driver._execute, gluster_export,
                                      tmpdir)
        except exception.GlusterfsException:
            shutil.rmtree(tmpdir, ignore_errors=True)
            raise

        # Delete the contents of a GlusterFS volume that is temporarily
        # mounted.
        # From GlusterFS version 3.7, two directories, '.trashcan' at the root
        # of the GlusterFS volume and 'internal_op' within the '.trashcan'
        # directory, are internally created when a GlusterFS volume is started.
        # GlusterFS does not allow unlink(2) of the two directories. So do not
        # delete the paths of the two directories, but delete their contents
        # along with the rest of the contents of the volume.
        srvaddr = gluster_mgr.host_access
        if common.numreduct(self.glusterfs_versions[srvaddr]) < (3, 7):
            cmd = ['find', tmpdir, '-mindepth', '1', '-delete']
        else:
            ignored_dirs = map(lambda x: os.path.join(tmpdir, *x),
                               [('.trashcan', ), ('.trashcan', 'internal_op')])
            ignored_dirs = list(ignored_dirs)
            cmd = ['find', tmpdir, '-mindepth', '1', '!', '-path',
                   ignored_dirs[0], '!', '-path', ignored_dirs[1], '-delete']

        try:
            self.driver._execute(*cmd, run_as_root=True)
        except exception.ProcessExecutionError as exc:
            msg = (_("Error trying to wipe gluster volume. "
                     "gluster_export: %(export)s, Error: %(error)s") %
                   {'export': gluster_export, 'error': exc.stderr})
            LOG.error(msg)
            raise exception.GlusterfsException(msg)
        finally:
            # Unmount.
            common._umount_gluster_vol(self.driver._execute, tmpdir)
            shutil.rmtree(tmpdir, ignore_errors=True)
Ejemplo n.º 9
0
 def test_numreduct(self, vers):
     ret = common.numreduct(vers)
     self.assertEqual((3, 6), ret)
Ejemplo n.º 10
0
 def test_numreduct(self, vers):
     ret = common.numreduct(vers)
     self.assertEqual((3, 6), ret)