Пример #1
0
def create_clone(share, new_name, request, logger):
    if (Share.objects.filter(name=new_name).exists()):
        e_msg = ('Share with name: %s already exists.' % new_name)
        handle_exception(Exception(e_msg), request)
    pool_device = Disk.objects.filter(pool=share.pool)[0].name
    snap_name = ('%s-clone-%s-snapshot' % (share.name, new_name))
    if (Snapshot.objects.filter(share=share, name=snap_name).exists()):
        e_msg = ('Snapshot with name: %s already exists for the '
                 'share: %s' % (snap_name, share.name))
        handle_exception(Exception(e_msg), request)

    try:
        add_snap(share.pool.name,
                 pool_device,
                 share.subvol_name,
                 snap_name,
                 share_prepend=False)
        snap_id = share_id(share.pool.name, pool_device, snap_name)
        qgroup_id = ('0/%s' % snap_id)
        update_quota(share.pool.name, pool_device, qgroup_id,
                     share.size * 1024)
        new_share = Share(pool=share.pool,
                          qgroup=qgroup_id,
                          name=new_name,
                          size=share.size,
                          subvol_name=snap_name)
        new_share.save()
        return Response(ShareSerializer(new_share).data)
    except Exception, e:
        e_msg = ('Failed to create clone due to a system error.')
        logger.error(e_msg)
        logger.exception(e)
        handle_exception(Exception(e_msg), request)
Пример #2
0
    def setUpClass(cls):
        super(NFSExportTests, cls).setUpClass()

        # post mocks
        cls.patch_mount_share = patch('storageadmin.views.nfs_exports.'
                                      'mount_share')
        cls.mock_mount_share = cls.patch_mount_share.start()
        cls.mock_mount_share.return_value = ['out'], ['err'], 0

        cls.patch_refresh_nfs_exports = patch('storageadmin.views.nfs_exports.'
                                              'refresh_nfs_exports')
        cls.mock_refresh_nfs_exports = cls.patch_refresh_nfs_exports.start()
        cls.mock_refresh_nfs_exports.return_value = ['out'], ['err'], 0

        # potential mocks for NFSExportGroup
        # validate_nfs_host_str
        # validate_nfs_modify_str
        # validate_nfs_sync_choice

        # all values as per fixture
        cls.temp_pool = Pool(id=11, name='rock-pool', size=5242880)
        cls.temp_share_nfs = Share(id=21, name='share-nfs', pool=cls.temp_pool)
        # the following is not picking up from db !!
        # cls.temp_nfsexportgroup = NFSExportGroup.objects.get(id=1)
        cls.temp_nfsexportgroup = NFSExportGroup(id=1)
        cls.temp_nfsexport = NFSExport(export_group=cls.temp_nfsexportgroup,
                                       share=cls.temp_share_nfs,
                                       mount='/export/share-nfs', id=1)

        cls.temp_share2 = Share(id=22, name='share2', pool=cls.temp_pool)
Пример #3
0
    def setUpClass(cls):
        super(SambaTests, cls).setUpClass()

        # post mocks
        cls.patch_mount_share = patch("storageadmin.views.samba.mount_share")
        cls.mock_mount_share = cls.patch_mount_share.start()

        # mock Share model's mount_status utility
        # True = Share is mounted, False = Share unmounted
        cls.patch_mount_status = patch("system.osi.mount_status")
        cls.mock_mount_status = cls.patch_mount_status.start()
        cls.mock_mount_status.return_value = True

        cls.patch_status = patch("storageadmin.views.samba.status")
        cls.mock_status = cls.patch_status.start()
        cls.mock_status.return_value = "out", "err", 0

        cls.patch_restart_samba = patch("storageadmin.views.samba.restart_samba")
        cls.mock_status = cls.patch_restart_samba.start()

        cls.patch_refresh_smb_config = patch(
            "storageadmin.views.samba.refresh_smb_config"
        )
        cls.mock_refresh_smb_config = cls.patch_refresh_smb_config.start()
        cls.mock_refresh_smb_config.return_value = "smbconfig"

        # all values as per fixture
        cls.temp_pool = Pool(id=11, name="rock-pool", size=5242880)
        cls.temp_share_smb = Share(id=23, name="share-smb", pool=cls.temp_pool)
        cls.temp_sambashare = SambaShare(id=1, share=cls.temp_share_smb)
        # cls.temp_smb_custom_config = \
        #     SambaCustomConfig(id=1, smb_share=cls.temp_sambashare)

        cls.temp_share2 = Share(id=24, name="share2", pool=cls.temp_pool)
Пример #4
0
    def post(self, request):
        try:
            sname = request.DATA['sname']
            if (Share.objects.filter(name=sname).exists()):
                e_msg = ('Share with name: %s already exists.' % sname)
                handle_exception(Exception(e_msg), request)

            pool_name = request.DATA['pool']
            size = int(request.DATA['size']) #in KB
            self._validate_share_size(request, size)
            pool = None
            try:
                pool = Pool.objects.get(name=pool_name)
            except:
                e_msg = ('Pool with name: %s does not exist.' % pool_name)
                handle_exception(Exception(e_msg), request)

            disk = None
            try:
                disk = Disk.objects.filter(pool=pool)[0]
            except:
                e_msg = ('Pool with name: %s does not have any disks in it.' %
                         pool_name)
                handle_exception(Exception(e_msg), request)

            add_share(pool_name, disk.name, sname)
            qgroup_id = self._update_quota(pool_name, disk.name, sname, size)
            s = Share(pool=pool, qgroup=qgroup_id, name=sname, size=size,
                      subvol_name=sname)
            s.save()
            return Response(ShareSerializer(s).data)
        except RockStorAPIException:
            raise
        except Exception, e:
            handle_exception(e, request)
Пример #5
0
def create_clone(share, new_name, request, logger):
    if (Share.objects.filter(name=new_name).exists()):
        e_msg = ('Share with name: %s already exists.' % new_name)
        handle_exception(Exception(e_msg), request)
    pool_device = Disk.objects.filter(pool=share.pool)[0].name
    snap_name = ('%s-clone-%s-snapshot' % (share.name, new_name))
    if (Snapshot.objects.filter(share=share, name=snap_name).exists()):
        e_msg = ('Snapshot with name: %s already exists for the '
                 'share: %s' % (snap_name, share.name))
        handle_exception(Exception(e_msg), request)

    try:
        add_snap(share.pool.name, pool_device, share.subvol_name,
                 snap_name, share_prepend=False)
        snap_id = share_id(share.pool.name, pool_device, snap_name)
        qgroup_id = ('0/%s' % snap_id)
        update_quota(share.pool.name, pool_device, qgroup_id,
                     share.size * 1024)
        new_share = Share(pool=share.pool, qgroup=qgroup_id, name=new_name,
                          size=share.size, subvol_name=snap_name)
        new_share.save()
        return Response(ShareSerializer(new_share).data)
    except Exception, e:
        e_msg = ('Failed to create clone due to a system error.')
        logger.error(e_msg)
        logger.exception(e)
        handle_exception(Exception(e_msg), request)
Пример #6
0
def create_clone(share, new_name, request, logger, snapshot=None):
    # if snapshot is None, create clone of the share.
    # If it's not, then clone it.
    if (re.match(settings.SHARE_REGEX + '$', new_name) is None):
        e_msg = ('Clone name is invalid. It must start with a letter and can'
                 ' contain letters, digits, _, . and - characters')
        handle_exception(Exception(e_msg), request)
    if (Share.objects.filter(name=new_name).exists()):
        e_msg = ('Another Share with name: %s already exists.' % new_name)
        handle_exception(Exception(e_msg), request)
    if (Snapshot.objects.filter(share=share, name=new_name).exists()):
        e_msg = ('Snapshot with name: %s already exists for the '
                 'share: %s. Choose a different name' %
                 (new_name, share.name))
        handle_exception(Exception(e_msg), request)

    try:
        share_name = share.subvol_name
        snap = None
        if (snapshot is not None):
            snap = snapshot.real_name
        add_clone(share.pool, share_name, new_name, snapshot=snap)
        snap_id = share_id(share.pool, new_name)
        qgroup_id = ('0/%s' % snap_id)
        update_quota(share.pool, qgroup_id, share.size * 1024)
        new_share = Share(pool=share.pool, qgroup=qgroup_id, name=new_name,
                          size=share.size, subvol_name=new_name)
        new_share.save()
        return Response(ShareSerializer(new_share).data)
    except Exception as e:
        handle_exception(e, request)
Пример #7
0
    def setUpClass(cls):
        super(SFTPTests, cls).setUpClass()

        # post mocks

        cls.patch_is_share_mounted = patch('storageadmin.views.sftp.'
                                           'is_share_mounted')
        cls.mock_is_share_mounted = cls.patch_is_share_mounted.start()
        cls.mock_is_share_mounted.return_value = True

        cls.patch_helper_mount_share = patch('storageadmin.views.sftp.'
                                             'helper_mount_share')
        cls.mock_helper_mount_share = cls.patch_helper_mount_share.start()
        cls.mock_helper_mount_share.return_value = True

        cls.patch_sftp_mount = patch('storageadmin.views.sftp.sftp_mount')
        cls.mock_sftp_mount = cls.patch_sftp_mount.start()
        cls.mock_sftp_mount.return_value = True

        # all values as per fixture
        cls.temp_pool = Pool(id=10, name='rock-pool', size=5242880)
        # the following line fails with: "Share matching query does not exist."
        # cls.temp_share_sftp = Share.objects.get(pk=18)
        cls.temp_share_sftp = Share(id=18, name='share-sftp',
                                    pool=cls.temp_pool, owner='admin',
                                    group='admin')
        cls.temp_share_root_owned = Share(id=19, name='share-root-owned',
                                          pool=cls.temp_pool)
        cls.temp_share_user_owned = Share(id=20, name='share-user-owned',
                                          pool=cls.temp_pool, owner='admin',
                                          group='admin')

        cls.temp_sftp = SFTP(id=1, share=cls.temp_share_sftp)
Пример #8
0
def create_clone(share, new_name, request, logger, snapshot=None):
    # if snapshot is None, create clone of the share.
    # If it's not, then clone it.
    if (re.match(settings.SHARE_REGEX + '$', new_name) is None):
        e_msg = ('Clone name is invalid. It must start with a letter and can'
                 ' contain letters, digits, _, . and - characters')
        handle_exception(Exception(e_msg), request)
    if (Share.objects.filter(name=new_name).exists()):
        e_msg = ('Another Share with name: %s already exists.' % new_name)
        handle_exception(Exception(e_msg), request)
    if (Snapshot.objects.filter(share=share, name=new_name).exists()):
        e_msg = ('Snapshot with name: %s already exists for the '
                 'share: %s. Choose a different name' %
                 (new_name, share.name))
        handle_exception(Exception(e_msg), request)

    try:
        share_name = share.subvol_name
        snap = None
        if (snapshot is not None):
            snap = snapshot.real_name
        add_clone(share.pool, share_name, new_name, snapshot=snap)
        snap_id = share_id(share.pool, new_name)
        qgroup_id = ('0/%s' % snap_id)
        update_quota(share.pool, qgroup_id, share.size * 1024)
        new_share = Share(pool=share.pool, qgroup=qgroup_id, name=new_name,
                          size=share.size, subvol_name=new_name)
        new_share.save()
        return Response(ShareSerializer(new_share).data)
    except Exception, e:
        handle_exception(e, request)
Пример #9
0
def import_shares(pool, request):
    disk = Disk.objects.filter(pool=pool)[0].name
    shares = [s.name for s in Share.objects.filter(pool=pool)]
    shares_d = shares_info('%s%s' % (settings.MNT_PT, pool.name))
    for s in shares:
        if (s not in shares_d):
            Share.objects.get(pool=pool, name=s).delete()
    for s in shares_d:
        if (s in shares):
            share = Share.objects.get(name=s)
            share.qgroup = shares_d[s]
            rusage, eusage = share_usage(pool, share.qgroup)
            ts = datetime.utcnow().replace(tzinfo=utc)
            if (rusage != share.rusage or eusage != share.eusage):
                share.rusage = rusage
                share.eusage = eusage
                su = ShareUsage(name=s, r_usage=rusage, e_usage=eusage,
                                ts=ts)
                su.save()
            else:
                try:
                    su = ShareUsage.objects.filter(name=s).latest('id')
                    su.ts = ts
                    su.count += 1
                except ShareUsage.DoesNotExist:
                    su = ShareUsage(name=s, r_usage=rusage,
                                    e_usage=eusage, ts=ts)
                finally:
                    su.save()
            share.save()
            continue
        try:
            cshare = Share.objects.get(name=s)
            cshares_d = shares_info('%s%s' % (settings.MNT_PT,
                                              cshare.pool.name))
            if (s in cshares_d):
                e_msg = ('Another pool(%s) has a Share with this same '
                         'name(%s) as this pool(%s). This configuration is not supported.'
                         ' You can delete one of them manually with this command: '
                         'btrfs subvol delete %s[pool name]/%s' %
                         (cshare.pool.name, s, pool.name, settings.MNT_PT, s))
                handle_exception(Exception(e_msg), request)
            else:
                cshare.pool = pool
                cshare.qgroup = shares_d[s]
                cshare.size = pool.size
                cshare.subvol_name = s
                cshare.rusage, cshare.eusage = share_usage(pool, cshare.qgroup)
                cshare.save()
        except Share.DoesNotExist:
            pqid = qgroup_create(pool)
            update_quota(pool, pqid, pool.size * 1024)
            nso = Share(pool=pool, qgroup=shares_d[s], pqgroup=pqid, name=s,
                        size=pool.size, subvol_name=s)
            nso.save()
        mount_share(nso, '%s%s' % (settings.MNT_PT, s))
Пример #10
0
def import_shares(pool, request):
    disk = Disk.objects.filter(pool=pool)[0].name
    shares = [s.name for s in Share.objects.filter(pool=pool)]
    shares_d = shares_info(pool)
    for s in shares:
        if (s not in shares_d):
            Share.objects.get(pool=pool, name=s).delete()
    for s in shares_d:
        if (s in shares):
            share = Share.objects.get(name=s)
            share.qgroup = shares_d[s]
            rusage, eusage = share_usage(pool, share.qgroup)
            ts = datetime.utcnow().replace(tzinfo=utc)
            if (rusage != share.rusage or eusage != share.eusage):
                share.rusage = rusage
                share.eusage = eusage
                su = ShareUsage(name=s, r_usage=rusage, e_usage=eusage,
                                ts=ts)
                su.save()
            else:
                try:
                    su = ShareUsage.objects.filter(name=s).latest('id')
                    su.ts = ts
                    su.count += 1
                except ShareUsage.DoesNotExist:
                    su = ShareUsage(name=s, r_usage=rusage,
                                    e_usage=eusage, ts=ts)
                finally:
                    su.save()
            share.save()
            continue
        try:
            cshare = Share.objects.get(name=s)
            cshares_d = shares_info('%s%s' % (settings.MNT_PT,
                                              cshare.pool.name))
            if (s in cshares_d):
                e_msg = ('Another pool(%s) has a Share with this same '
                         'name(%s) as this pool(%s). This configuration is not supported.'
                         ' You can delete one of them manually with this command: '
                         'btrfs subvol delete %s[pool name]/%s' %
                         (cshare.pool.name, s, pool.name, settings.MNT_PT, s))
                handle_exception(Exception(e_msg), request)
            else:
                cshare.pool = pool
                cshare.qgroup = shares_d[s]
                cshare.size = pool.size
                cshare.subvol_name = s
                cshare.rusage, cshare.eusage = share_usage(pool, cshare.qgroup)
                cshare.save()
        except Share.DoesNotExist:
            pqid = qgroup_create(pool)
            update_quota(pool, pqid, pool.size * 1024)
            nso = Share(pool=pool, qgroup=shares_d[s], pqgroup=pqid, name=s,
                        size=pool.size, subvol_name=s)
            nso.save()
        mount_share(nso, '%s%s' % (settings.MNT_PT, s))
Пример #11
0
    def post(self, request):
        with self._handle_exception(request):
            pool_name = request.data.get('pool', None)
            try:
                pool = Pool.objects.get(name=pool_name)
            except:
                e_msg = ('Pool(%s) does not exist.' % pool_name)
                handle_exception(Exception(e_msg), request)
            compression = self._validate_compression(request)
            size = self._validate_share_size(request, pool)
            sname = request.data.get('sname', None)
            if ((sname is None
                 or re.match('%s$' % settings.SHARE_REGEX, sname) is None)):
                e_msg = ('Share name must start with a alphanumeric(a-z0-9) '
                         'character and can be followed by any of the '
                         'following characters: letter(a-z), digits(0-9), '
                         'hyphen(-), underscore(_) or a period(.).')
                handle_exception(Exception(e_msg), request)

            if (Share.objects.filter(name=sname).exists()):
                e_msg = ('Share(%s) already exists. Choose a different name' %
                         sname)
                handle_exception(Exception(e_msg), request)

            if (Pool.objects.filter(name=sname).exists()):
                e_msg = (
                    'A Pool with this name(%s) exists. Share and Pool names '
                    'must be distinct. Choose a different name' % sname)
                handle_exception(Exception(e_msg), request)
            disk = Disk.objects.filter(pool=pool)[0]
            replica = False
            if ('replica' in request.data):
                replica = request.data['replica']
                if (type(replica) != bool):
                    e_msg = ('replica must be a boolean, not %s' %
                             type(replica))
                    handle_exception(Exception(e_msg), request)
            add_share(pool, disk.name, sname)
            qid = qgroup_id(pool, disk.name, sname)
            update_quota(pool, disk.name, qid, size * 1024)
            s = Share(pool=pool,
                      qgroup=qid,
                      name=sname,
                      size=size,
                      subvol_name=sname,
                      replica=replica,
                      compression_algo=compression)
            s.save()
            mnt_pt = '%s%s' % (settings.MNT_PT, sname)
            if (not is_share_mounted(sname)):
                disk = Disk.objects.filter(pool=pool)[0].name
                mount_share(s, disk, mnt_pt)
            if (compression != 'no'):
                set_property(mnt_pt, 'compression', compression)
            return Response(ShareSerializer(s).data)
Пример #12
0
    def post(self, request):
        with self._handle_exception(request):
            pool_name = request.DATA.get('pool', None)
            try:
                pool = Pool.objects.get(name=pool_name)
            except:
                e_msg = ('Pool(%s) does not exist.' % pool_name)
                handle_exception(Exception(e_msg), request)
            compression = self._validate_compression(request)
            size = self._validate_share_size(request, pool)
            sname = request.DATA.get('sname', None)
            if ((sname is None or
                 re.match('%s$' % settings.SHARE_REGEX, sname) is None)):
                e_msg = ('Share name must start with a letter(a-z) and can '
                         'be followed by any of the following characters: '
                         'letter(a-z), digits(0-9), hyphen(-), underscore'
                         '(_) or a period(.).')
                handle_exception(Exception(e_msg), request)

            if (Share.objects.filter(name=sname).exists()):
                e_msg = ('Share(%s) already exists.' % sname)
                handle_exception(Exception(e_msg), request)

            try:
                disk = Disk.objects.filter(pool=pool)[0]
            except:
                e_msg = ('Pool(%s) does not have any disks in it.' %
                         pool_name)
                handle_exception(Exception(e_msg), request)

            replica = False
            if ('replica' in request.DATA):
                replica = request.DATA['replica']
                if (type(replica) != bool):
                    e_msg = ('replica must be a boolean, not %s' %
                             type(replica))
                    handle_exception(Exception(e_msg), request)
            add_share(pool, disk.name, sname)
            qgroup_id = self._update_quota(pool, disk.name, sname, size)
            s = Share(pool=pool, qgroup=qgroup_id, name=sname, size=size,
                      subvol_name=sname, replica=replica,
                      compression_algo=compression)
            s.save()
            mnt_pt = '%s%s' % (settings.MNT_PT, sname)
            if (not is_share_mounted(sname)):
                disk = Disk.objects.filter(pool=pool)[0].name
                mount_share(s, disk, mnt_pt)
            if (compression != 'no'):
                set_property(mnt_pt, 'compression', compression)
            return Response(ShareSerializer(s).data)
Пример #13
0
    def post(self, request):
        try:
            sname = request.DATA['sname']
            if (re.match('%s$' % settings.SHARE_REGEX, sname) is None):
                e_msg = ('Share name must start with a letter(a-z) and can'
                         ' be followed by any of the following characters: '
                         'letter(a-z), digits(0-9), hyphen(-), underscore'
                         '(_) or a period(.).')
                handle_exception(Exception(e_msg), request)

            if (Share.objects.filter(name=sname).exists()):
                e_msg = ('Share with name: %s already exists.' % sname)
                handle_exception(Exception(e_msg), request)

            pool_name = request.DATA['pool']
            size = int(request.DATA['size']) #in KB
            self._validate_share_size(request, size)
            pool = None
            try:
                pool = Pool.objects.get(name=pool_name)
            except:
                e_msg = ('Pool with name: %s does not exist.' % pool_name)
                handle_exception(Exception(e_msg), request)

            disk = None
            try:
                disk = Disk.objects.filter(pool=pool)[0]
            except:
                e_msg = ('Pool with name: %s does not have any disks in it.' %
                         pool_name)
                handle_exception(Exception(e_msg), request)

            replica = False
            if ('replica' in request.DATA):
                replica = request.DATA['replica']
                if (type(replica) != bool):
                    e_msg = ('replica must be a boolean, not %s' %
                             type(replica))
                    handle_exception(Exception(e_msg), request)

            add_share(pool_name, disk.name, sname)
            qgroup_id = self._update_quota(pool_name, disk.name, sname, size)
            s = Share(pool=pool, qgroup=qgroup_id, name=sname, size=size,
                      subvol_name=sname, replica=replica)
            s.save()
            return Response(ShareSerializer(s).data)
        except RockStorAPIException:
            raise
        except Exception, e:
            handle_exception(e, request)
Пример #14
0
    def post(self, request):
        with self._handle_exception(request):
            pool_name = request.data.get('pool', None)
            try:
                pool = Pool.objects.get(name=pool_name)
            except:
                e_msg = ('Pool(%s) does not exist.' % pool_name)
                handle_exception(Exception(e_msg), request)
            compression = self._validate_compression(request)
            size = self._validate_share_size(request, pool)
            sname = request.data.get('sname', None)
            if ((sname is None or
                 re.match('%s$' % settings.SHARE_REGEX, sname) is None)):
                e_msg = ('Share name must start with a alphanumeric(a-z0-9) '
                         'character and can be followed by any of the '
                         'following characters: letter(a-z), digits(0-9), '
                         'hyphen(-), underscore(_) or a period(.).')
                handle_exception(Exception(e_msg), request)

            if (Share.objects.filter(name=sname).exists()):
                e_msg = ('Share(%s) already exists. Choose a different name' % sname)
                handle_exception(Exception(e_msg), request)

            if (Pool.objects.filter(name=sname).exists()):
                e_msg = ('A Pool with this name(%s) exists. Share and Pool names '
                         'must be distinct. Choose a different name' % sname)
                handle_exception(Exception(e_msg), request)
            disk = Disk.objects.filter(pool=pool)[0]
            replica = False
            if ('replica' in request.data):
                replica = request.data['replica']
                if (type(replica) != bool):
                    e_msg = ('replica must be a boolean, not %s' %
                             type(replica))
                    handle_exception(Exception(e_msg), request)
            add_share(pool, disk.name, sname)
            qid = qgroup_id(pool, disk.name, sname)
            update_quota(pool, disk.name, qid, size * 1024)
            s = Share(pool=pool, qgroup=qgroup_id, name=sname, size=size,
                      subvol_name=sname, replica=replica,
                      compression_algo=compression)
            s.save()
            mnt_pt = '%s%s' % (settings.MNT_PT, sname)
            if (not is_share_mounted(sname)):
                disk = Disk.objects.filter(pool=pool)[0].name
                mount_share(s, disk, mnt_pt)
            if (compression != 'no'):
                set_property(mnt_pt, 'compression', compression)
            return Response(ShareSerializer(s).data)
Пример #15
0
def create_clone(share, new_name, request, logger, snapshot=None):
    # if snapshot is None, create clone of the share.
    # If it's not, then clone it.
    if re.match(settings.SHARE_REGEX + "$", new_name) is None:
        e_msg = ("Clone name is invalid. It must start with a letter and can "
                 "contain letters, digits, _, . and - characters.")
        handle_exception(Exception(e_msg), request)
    if Share.objects.filter(name=new_name).exists():
        e_msg = "Another share with name ({}) already exists.".format(new_name)
        handle_exception(Exception(e_msg), request)
    if Snapshot.objects.filter(share=share, name=new_name).exists():
        e_msg = ("Snapshot with name ({}) already exists for the "
                 "share ({}). Choose a different name.").format(
                     new_name, share.name)
        handle_exception(Exception(e_msg), request)

    try:
        share_name = share.subvol_name
        snap = None
        if snapshot is not None:
            snap = snapshot.real_name
        add_clone(share.pool, share_name, new_name, snapshot=snap)
        snap_id = share_id(share.pool, new_name)
        qgroup_id = "0/{}".format(snap_id)
        pqid = qgroup_create(share.pool)
        new_share = Share(
            pool=share.pool,
            qgroup=qgroup_id,
            pqgroup=pqid,
            name=new_name,
            size=share.size,
            subvol_name=new_name,
        )
        new_share.save()
        if pqid != PQGROUP_DEFAULT:
            update_quota(new_share.pool, pqid, new_share.size * 1024)
            share_pqgroup_assign(pqid, new_share)
        # Mount our new clone share.
        # We independently mount all shares, data pool or system pool, in /mnt2/name
        mnt_pt = "{}{}".format(settings.MNT_PT, new_name)
        mount_share(new_share, mnt_pt)
        return Response(ShareSerializer(new_share).data)
    except Exception as e:
        handle_exception(e, request)
Пример #16
0
    def post(self, request):
        try:
            sname = request.DATA['sname']
            if (Share.objects.filter(name=sname).exists()):
                e_msg = ('Share with name: %s already exists.' % sname)
                handle_exception(Exception(e_msg), request)

            pool_name = request.DATA['pool']
            size = int(request.DATA['size'])  #in KB
            self._validate_share_size(request, size)
            pool = None
            try:
                pool = Pool.objects.get(name=pool_name)
            except:
                e_msg = ('Pool with name: %s does not exist.' % pool_name)
                handle_exception(Exception(e_msg), request)

            disk = None
            try:
                disk = Disk.objects.filter(pool=pool)[0]
            except:
                e_msg = ('Pool with name: %s does not have any disks in it.' %
                         pool_name)
                handle_exception(Exception(e_msg), request)

            add_share(pool_name, disk.name, sname)
            qgroup_id = self._update_quota(pool_name, disk.name, sname, size)
            s = Share(pool=pool,
                      qgroup=qgroup_id,
                      name=sname,
                      size=size,
                      subvol_name=sname)
            s.save()
            return Response(ShareSerializer(s).data)
        except RockStorAPIException:
            raise
        except Exception, e:
            handle_exception(e, request)
Пример #17
0
    def test_delete_requests(self, mock_pool, mock_share, mock_snapshot):
        """
        1. Delete snapshot that does not exist
        2. Delete snapshot with no name specified
        """

        temp_pool = Pool(id=1, name='rockstor_rockstor', size=88025459)
        mock_pool.objects.get.return_value = temp_pool

        temp_share = Share(id=3, name='share1', pool=temp_pool, size=8025459)
        mock_share.objects.get.return_value = temp_share

        mock_snapshot.objects.get.side_effect = Snapshot.DoesNotExist

        # # Delete snapshot that does not exists
        snap_name = 'snap3'
        share_name = 'share1'
        share_id = 3  # from fix5.json
        response = self.client.delete('{}/{}/snapshots/{}'.format(
            self.BASE_URL, share_id, snap_name))
        self.assertEqual(response.status_code,
                         status.HTTP_500_INTERNAL_SERVER_ERROR,
                         msg=response.data)
        e_msg = 'Snapshot name (snap3) does not exist.'
        self.assertEqual(response.data[0], e_msg)

        temp_share2 = Share(id=4, name='share2', pool=temp_pool, size=8025459)
        mock_share.objects.get.return_value = temp_share2

        # Delete without snapshot name
        share_name = 'share1'
        share_id = 3  # from fix5.json
        response = self.client.delete('{}/{}/snapshots'.format(
            self.BASE_URL, share_id))
        self.assertEqual(response.status_code,
                         status.HTTP_200_OK,
                         msg=response.data)
Пример #18
0
def create_clone(share, new_name, request, logger, snapshot=None):
    # if snapshot is None, create clone of the share.
    # If it's not, then clone it.
    if (re.match(settings.SHARE_REGEX + '$', new_name) is None):
        e_msg = ('Clone name is invalid. It must start with a letter and can '
                 'contain letters, digits, _, . and - characters.')
        handle_exception(Exception(e_msg), request)
    if (Share.objects.filter(name=new_name).exists()):
        e_msg = 'Another share with name ({}) already exists.'.format(new_name)
        handle_exception(Exception(e_msg), request)
    if (Snapshot.objects.filter(share=share, name=new_name).exists()):
        e_msg = ('Snapshot with name ({}) already exists for the '
                 'share ({}). Choose a different name.').format(new_name,
                                                                share.name)
        handle_exception(Exception(e_msg), request)

    try:
        share_name = share.subvol_name
        snap = None
        if (snapshot is not None):
            snap = snapshot.real_name
        add_clone(share.pool, share_name, new_name, snapshot=snap)
        snap_id = share_id(share.pool, new_name)
        qgroup_id = ('0/%s' % snap_id)
        pqid = qgroup_create(share.pool)
        new_share = Share(pool=share.pool, qgroup=qgroup_id, pqgroup=pqid,
                          name=new_name, size=share.size, subvol_name=new_name)
        new_share.save()
        if pqid is not PQGROUP_DEFAULT:
            update_quota(new_share.pool, pqid, new_share.size * 1024)
            share_pqgroup_assign(pqid, new_share)
        # Mount our new clone share.
        mnt_pt = '{}{}'.format(settings.MNT_PT, new_name)
        mount_share(new_share, mnt_pt)
        return Response(ShareSerializer(new_share).data)
    except Exception as e:
        handle_exception(e, request)
Пример #19
0
 def post(self, request):
     try:
         pool_name = request.DATA['pool']
         share_name = request.DATA['name']
         size = int(request.DATA['size'])
         pool = None
         for p in Pool.objects.all():
             if (p.name == pool_name):
                 pool = p
                 break
         disk = Disk.objects.filter(pool=p)[0]
         add_share(pool_name, disk.name, share_name)
         sid = share_id(pool_name, disk.name, share_name)
         qgroup_id = '0/' + sid
         update_quota(pool_name, disk.name, qgroup_id, str(size))
         cur_usage = int(share_usage(pool_name, disk.name, qgroup_id))
         qgroup = Qgroup(uuid=qgroup_id)
         qgroup.save()
         s = Share(pool=pool, qgroup=qgroup, name=share_name, size=size,
                 free=(size - cur_usage))
         s.save()
         return Response(ShareSerializer(s).data)
     except Exception, e:
         handle_exception(e, request)
Пример #20
0
    def setUpClass(cls):
        super(AFPTests, cls).setUpClass()

        # post mocks
        cls.patch_mount_share = patch(
            'storageadmin.views.netatalk.mount_share')
        cls.mock_mount_share = cls.patch_mount_share.start()

        cls.patch_refresh_afp_config = patch(
            'storageadmin.views.netatalk.refresh_afp_config')
        cls.mock_refresh_afp_config = cls.patch_refresh_afp_config.start()

        cls.patch_systemctl = patch('storageadmin.views.netatalk.systemctl')
        cls.mock_systemctl = cls.patch_systemctl.start()

        # all values as per fixture
        cls.temp_pool = Pool(id=9, name='rock-pool', size=5242880)
        cls.temp_share = Share(id=14, name='share1', pool=cls.temp_pool)
        cls.temp_afpshare = NetatalkShare(id=1, share=cls.temp_share)
Пример #21
0
    def test_clone_command(self, mock_pool, mock_share, mock_snapshot):

        temp_pool = Pool(id=1, name='rockstor_rockstor', size=88025459)
        mock_pool.objects.get.return_value = temp_pool

        temp_share = Share(id=4, name='share2', pool=temp_pool, size=8025459)
        mock_share.objects.get.return_value = temp_share
        mock_snapshot.objects.get.side_effect = Snapshot.DoesNotExist

        data = {'name': 'clonesnap2'}
        snap_name = 'clonesnap2'
        share = 'share2'
        share_id = 4  # from fix5.json
        response = self.client.post('{}/{}/snapshots/{}'.format(
            self.BASE_URL, share_id, snap_name),
                                    data=data,
                                    sname=share,
                                    snap_name=snap_name,
                                    command='clone')
        self.assertEqual(response.status_code,
                         status.HTTP_200_OK,
                         msg=response.data)
Пример #22
0
    def post(self, request):
        # qgroup notes for shares. we need to create a qgroup prior to share
        # creation. qgroup ids 0/<subvol_id> automatically get created when a
        # subvolume(i.e., a Share or a Snapshot) is created. So let's create a
        # new qgroup: 2015/<some_number> whenever a Share is
        # created. <some_number> starts from 1 and is incremented as more
        # Shares are created. So, for the very first Share in a pool, it's
        # qgroup will be 1/1. 2015 is arbitrarily chose.

        # Before creating a new Share, we create the qgroup for it. And during
        # it's creation, we assign this qgroup to it. During it's creation a
        # 0/x qgroup will automatically be created, but it will become the
        # child of our explicitly-created qgroup(2015/x).

        # We will set the qgroup limit on our qgroup and it will enforce the
        # quota on every subvolume(i.e., Share and Snapshot) in that qgroup.

        # When a Share is deleted, we need to destroy two qgroups. One is it's
        # auto 0/x qgroup and the other is our explicitly-created 2015/y
        # qgroup.

        with self._handle_exception(request):
            pool_name = request.data.get('pool', None)
            try:
                pool = Pool.objects.get(name=pool_name)
            except:
                e_msg = 'Pool ({}) does not exist.'.format(pool_name)
                handle_exception(Exception(e_msg), request)
            compression = self._validate_compression(request)
            size = self._validate_share_size(request, pool)
            sname = request.data.get('sname', None)
            if ((sname is None or
                 re.match('%s$' % settings.SHARE_REGEX, sname) is None)):
                e_msg = ('Invalid characters in share name. Following are '
                         'allowed: letter(a-z or A-Z), digit(0-9), '
                         'hyphen(-), underscore(_) or a period(.).')
                handle_exception(Exception(e_msg), request)

            if (len(sname) > 254):
                # btrfs subvolume names cannot exceed 254 characters.
                e_msg = ('Share name length cannot exceed 254 characters.')
                handle_exception(Exception(e_msg), request)

            if (Share.objects.filter(name=sname).exists()):
                # Note e_msg is consumed by replication/util.py create_share()
                e_msg = ('Share ({}) already exists. Choose a '
                         'different name.').format(sname)
                handle_exception(Exception(e_msg), request)

            if (Pool.objects.filter(name=sname).exists()):
                e_msg = ('A pool with this name ({}) exists. Share '
                         'and pool names must be distinct. Choose '
                         'a different name.').format(sname)
                handle_exception(Exception(e_msg), request)
            replica = False
            if ('replica' in request.data):
                replica = request.data['replica']
                if (type(replica) != bool):
                    # TODO: confirm this 'type' call works as format parameter.
                    e_msg = ('Replica must be a boolean, '
                             'not ({}).').format(type(replica))
                    handle_exception(Exception(e_msg), request)
            pqid = qgroup_create(pool)
            add_share(pool, sname, pqid)
            qid = qgroup_id(pool, sname)
            s = Share(pool=pool, qgroup=qid, pqgroup=pqid, name=sname,
                      size=size, subvol_name=sname, replica=replica,
                      compression_algo=compression)
            # The following pool.save() was informed by test_share.py
            pool.save()
            s.save()
            if pqid is not PQGROUP_DEFAULT:
                update_quota(pool, pqid, size * 1024)
                share_pqgroup_assign(pqid, s)
            mnt_pt = '%s%s' % (settings.MNT_PT, sname)
            if not s.is_mounted:
                mount_share(s, mnt_pt)
            if (compression != 'no'):
                set_property(mnt_pt, 'compression', compression)
            return Response(ShareSerializer(s).data)
Пример #23
0
def import_shares(pool, request):
    # Establish known shares/subvols within our db for the given pool:
    shares_in_pool_db = [s.name for s in Share.objects.filter(pool=pool)]
    # Find the actual/current shares/subvols within the given pool:
    # Limited to Rockstor relevant subvols ie shares and clones.
    shares_in_pool = shares_info(pool)
    # List of pool's share.pqgroups so we can remove inadvertent duplication.
    # All pqgroups are removed when quotas are disabled, combined with a part
    # refresh we could have duplicates within the db.
    share_pqgroups_used = []
    # Delete db Share object if it is no longer found on disk.
    for s_in_pool_db in shares_in_pool_db:
        if s_in_pool_db not in shares_in_pool:
            Share.objects.get(pool=pool, name=s_in_pool_db).delete()
    # Check if each share in pool also has a db counterpart.
    for s_in_pool in shares_in_pool:
        logger.debug('---- Share name = {}.'.format(s_in_pool))
        if s_in_pool in shares_in_pool_db:
            logger.debug('Updating pre-existing same pool db share entry.')
            # We have a pool db share counterpart so retrieve and update it.
            share = Share.objects.get(name=s_in_pool, pool=pool)
            # Initially default our pqgroup value to db default of '-1/-1'
            # This way, unless quotas are enabled, all pqgroups will be
            # returned to db default.
            pqgroup = settings.MODEL_DEFS['pqgroup']
            if share.pool.quotas_enabled:
                # Quotas are enabled on our pool so we can validate pqgroup.
                if share.pqgroup == pqgroup or not share.pqgroup_exist \
                        or share.pqgroup in share_pqgroups_used:
                    # we have a void '-1/-1' or non existent pqgroup or
                    # this pqgroup has already been seen / used in this pool.
                    logger.debug('#### replacing void, non-existent, or '
                                 'duplicate pqgroup')
                    pqgroup = qgroup_create(pool)
                    update_quota(pool, pqgroup, share.size * 1024)
                    share_pqgroup_assign(pqgroup, share)
                else:
                    # Our share's pqgroup looks OK so use it.
                    pqgroup = share.pqgroup
                # Record our use of this pqgroup to spot duplicates later.
                share_pqgroups_used.append(deepcopy(share.pqgroup))
            if share.pqgroup != pqgroup:
                # we need to update our share.pqgroup
                share.pqgroup = pqgroup
                share.save()
            share.qgroup = shares_in_pool[s_in_pool]
            rusage, eusage, pqgroup_rusage, pqgroup_eusage = \
                volume_usage(pool, share.qgroup, pqgroup)
            if (rusage != share.rusage or eusage != share.eusage
                    or pqgroup_rusage != share.pqgroup_rusage
                    or pqgroup_eusage != share.pqgroup_eusage):
                share.rusage = rusage
                share.eusage = eusage
                share.pqgroup_rusage = pqgroup_rusage
                share.pqgroup_eusage = pqgroup_eusage
                update_shareusage_db(s_in_pool, rusage, eusage)
            else:
                update_shareusage_db(s_in_pool, rusage, eusage, UPDATE_TS)
            share.save()
            continue
        try:
            logger.debug('No prior entries in scanned pool trying all pools.')
            # Test (Try) for an existing system wide Share db entry.
            cshare = Share.objects.get(name=s_in_pool)
            # Get a list of Rockstor relevant subvols (ie shares and clones)
            # for the prior existing db share entry's pool.
            cshares_d = shares_info(cshare.pool)
            if s_in_pool in cshares_d:
                e_msg = ('Another pool ({}) has a Share with this same '
                         'name ({}) as this pool ({}). This configuration '
                         'is not supported. You can delete one of them '
                         'manually with the following command: '
                         '"btrfs subvol delete {}[pool name]/{}" WARNING this '
                         'will remove the entire contents of that subvolume.'.
                         format(cshare.pool.name, s_in_pool, pool.name,
                                settings.MNT_PT, s_in_pool))
                handle_exception(Exception(e_msg), request)
            else:
                # Update the prior existing db share entry previously
                # associated with another pool.
                logger.debug('Updating prior db entry from another pool.')
                cshare.pool = pool
                cshare.qgroup = shares_in_pool[s_in_pool]
                cshare.size = pool.size
                cshare.subvol_name = s_in_pool
                (cshare.rusage, cshare.eusage, cshare.pqgroup_rusage,
                 cshare.pqgroup_eusage) = volume_usage(pool, cshare.qgroup,
                                                       cshare.pqgroup)
                cshare.save()
                update_shareusage_db(s_in_pool, cshare.rusage, cshare.eusage)
        except Share.DoesNotExist:
            logger.debug('Db share entry does not exist - creating.')
            # We have a share on disk that has no db counterpart so create one.
            # Retrieve new pool quota id for use in db Share object creation.
            pqid = qgroup_create(pool)
            update_quota(pool, pqid, pool.size * 1024)
            rusage, eusage, pqgroup_rusage, pqgroup_eusage = \
                volume_usage(pool, shares_in_pool[s_in_pool], pqid)
            nso = Share(pool=pool,
                        qgroup=shares_in_pool[s_in_pool],
                        pqgroup=pqid,
                        name=s_in_pool,
                        size=pool.size,
                        subvol_name=s_in_pool,
                        rusage=rusage,
                        eusage=eusage,
                        pqgroup_rusage=pqgroup_rusage,
                        pqgroup_eusage=pqgroup_eusage)
            nso.save()
            update_shareusage_db(s_in_pool, rusage, eusage)
            mount_share(nso, '%s%s' % (settings.MNT_PT, s_in_pool))
Пример #24
0
def import_shares(pool, request):
    # Establish known shares/subvols within our db for the given pool:
    shares_in_pool_db = [s.name for s in Share.objects.filter(pool=pool)]
    # Find the actual/current shares/subvols within the given pool:
    # Limited to Rockstor relevant subvols ie shares and clones.
    shares_in_pool = shares_info(pool)
    # List of pool's share.pqgroups so we can remove inadvertent duplication.
    # All pqgroups are removed when quotas are disabled, combined with a part
    # refresh we could have duplicates within the db.
    share_pqgroups_used = []
    # Delete db Share object if it is no longer found on disk.
    for s_in_pool_db in shares_in_pool_db:
        if s_in_pool_db not in shares_in_pool:
            logger.debug("Removing, missing on disk, share db entry ({}) from "
                         "pool ({}).".format(s_in_pool_db, pool.name))
            Share.objects.get(pool=pool, name=s_in_pool_db).delete()
    # Check if each share in pool also has a db counterpart.
    for s_in_pool in shares_in_pool:
        logger.debug("---- Share name = {}.".format(s_in_pool))
        if s_in_pool in shares_in_pool_db:
            logger.debug("Updating pre-existing same pool db share entry.")
            # We have a pool db share counterpart so retrieve and update it.
            share = Share.objects.get(name=s_in_pool, pool=pool)
            # Initially default our pqgroup value to db default of '-1/-1'
            # This way, unless quotas are enabled, all pqgroups will be
            # returned to db default.
            pqgroup = PQGROUP_DEFAULT
            if share.pool.quotas_enabled:
                # Quotas are enabled on our pool so we can validate pqgroup.
                if (share.pqgroup == pqgroup or not share.pqgroup_exist
                        or share.pqgroup in share_pqgroups_used):
                    # we have a void '-1/-1' or non existent pqgroup or
                    # this pqgroup has already been seen / used in this pool.
                    logger.debug(
                        "#### replacing void, non-existent, or duplicate pqgroup."
                    )
                    pqgroup = qgroup_create(pool)
                    if pqgroup != PQGROUP_DEFAULT:
                        update_quota(pool, pqgroup, share.size * 1024)
                        share_pqgroup_assign(pqgroup, share)
                else:
                    # Our share's pqgroup looks OK so use it.
                    pqgroup = share.pqgroup
                # Record our use of this pqgroup to spot duplicates later.
                share_pqgroups_used.append(deepcopy(share.pqgroup))
            if share.pqgroup != pqgroup:
                # we need to update our share.pqgroup
                share.pqgroup = pqgroup
                share.save()
            share.qgroup = shares_in_pool[s_in_pool]
            rusage, eusage, pqgroup_rusage, pqgroup_eusage = volume_usage(
                pool, share.qgroup, pqgroup)
            if (rusage != share.rusage or eusage != share.eusage
                    or pqgroup_rusage != share.pqgroup_rusage
                    or pqgroup_eusage != share.pqgroup_eusage):
                share.rusage = rusage
                share.eusage = eusage
                share.pqgroup_rusage = pqgroup_rusage
                share.pqgroup_eusage = pqgroup_eusage
                update_shareusage_db(s_in_pool, rusage, eusage)
            else:
                update_shareusage_db(s_in_pool, rusage, eusage, UPDATE_TS)
            share.save()
            continue
        try:
            logger.debug("No prior entries in scanned pool trying all pools.")
            # Test (Try) for an existing system wide Share db entry.
            cshare = Share.objects.get(name=s_in_pool)
            # Get a list of Rockstor relevant subvols (ie shares and clones)
            # for the prior existing db share entry's pool.
            cshares_d = shares_info(cshare.pool)
            if s_in_pool in cshares_d:
                e_msg = ("Another pool ({}) has a share with this same "
                         "name ({}) as this pool ({}). This configuration "
                         "is not supported. You can delete one of them "
                         "manually with the following command: "
                         '"btrfs subvol delete {}[pool name]/{}" WARNING this '
                         "will remove the entire contents of that "
                         "subvolume.").format(cshare.pool.name, s_in_pool,
                                              pool.name, settings.MNT_PT,
                                              s_in_pool)
                handle_exception(Exception(e_msg), request)
            else:
                # Update the prior existing db share entry previously
                # associated with another pool.
                logger.debug("Updating prior db entry from another pool.")
                cshare.pool = pool
                cshare.qgroup = shares_in_pool[s_in_pool]
                cshare.size = pool.size
                cshare.subvol_name = s_in_pool
                (
                    cshare.rusage,
                    cshare.eusage,
                    cshare.pqgroup_rusage,
                    cshare.pqgroup_eusage,
                ) = volume_usage(pool, cshare.qgroup, cshare.pqgroup)
                cshare.save()
                update_shareusage_db(s_in_pool, cshare.rusage, cshare.eusage)
        except Share.DoesNotExist:
            logger.debug("Db share entry does not exist - creating.")
            # We have a share on disk that has no db counterpart so create one.
            # Retrieve new pool quota id for use in db Share object creation.
            # As the replication receive share is 'special' we tag it as such.
            replica = False
            share_name = s_in_pool
            if re.match(".snapshot", s_in_pool) is not None:
                # We have an initial replication share, non snap in .snapshots.
                # We could change it's name here but still a little mixing
                # of name and subvol throughout project.
                replica = True
                logger.debug("Initial receive quirk-subvol found: Importing "
                             "as share and setting replica flag.")
            qid = shares_in_pool[s_in_pool]
            pqid = qgroup_create(pool)
            if pqid != PQGROUP_DEFAULT:
                update_quota(pool, pqid, pool.size * 1024)
                qgroup_assign(qid, pqid, pool.mnt_pt)
            rusage, eusage, pqgroup_rusage, pqgroup_eusage = volume_usage(
                pool, qid, pqid)
            nso = Share(
                pool=pool,
                qgroup=qid,
                pqgroup=pqid,
                name=share_name,
                size=pool.size,
                subvol_name=s_in_pool,
                rusage=rusage,
                eusage=eusage,
                pqgroup_rusage=pqgroup_rusage,
                pqgroup_eusage=pqgroup_eusage,
                replica=replica,
            )
            nso.save()
            update_shareusage_db(s_in_pool, rusage, eusage)
            mount_share(nso, "{}{}".format(settings.MNT_PT, s_in_pool))
Пример #25
0
    def post(self, request):
        #qgroup notes for shares. we need to create a qgroup prior to share
        #creation. qgroup ids 0/<subvol_id> automatically get created when a
        #subvolume(i.e., a Share or a Snapshot) is created. So let's create a
        #new qgroup: 2015/<some_number> whenever a Share is
        #created. <some_number> starts from 1 and is incremented as more Shares
        #are created. So, for the very first Share in a pool, it's qgroup will
        #be 1/1. 2015 is arbitrarily chose.

        #Before creating a new Share, we create the qgroup for it. And during
        #it's creation, we assign this qgroup to it. During it's creation a 0/x
        #qgroup will automatically be created, but it will become the child of
        #our explicitly-created qgroup(2015/x).

        #We will set the qgroup limit on our qgroup and it will enforce the
        #quota on every subvolume(i.e., Share and Snapshot) in that qgroup.

        #When a Share is deleted, we need to destroy two qgroups. One is it's
        #auto 0/x qgroup and the other is our explicitly-created 2015/y qgroup.

        with self._handle_exception(request):
            pool_name = request.data.get('pool', None)
            try:
                pool = Pool.objects.get(name=pool_name)
            except:
                e_msg = ('Pool(%s) does not exist.' % pool_name)
                handle_exception(Exception(e_msg), request)
            compression = self._validate_compression(request)
            size = self._validate_share_size(request, pool)
            sname = request.data.get('sname', None)
            if ((sname is None or
                 re.match('%s$' % settings.SHARE_REGEX, sname) is None)):
                e_msg = ('Share name must start with a alphanumeric(a-z0-9) '
                         'character and can be followed by any of the '
                         'following characters: letter(a-z), digits(0-9), '
                         'hyphen(-), underscore(_) or a period(.).')
                handle_exception(Exception(e_msg), request)

            if (len(sname) > 254):
                #btrfs subvolume names cannot exceed 254 characters.
                e_msg = ('Share name length cannot exceed 254 characters')
                handle_exception(Exception(e_msg), request)

            if (Share.objects.filter(name=sname).exists()):
                e_msg = ('Share(%s) already exists. Choose a different name' % sname)
                handle_exception(Exception(e_msg), request)

            if (Pool.objects.filter(name=sname).exists()):
                e_msg = ('A Pool with this name(%s) exists. Share and Pool names '
                         'must be distinct. Choose a different name' % sname)
                handle_exception(Exception(e_msg), request)
            disk = Disk.objects.filter(pool=pool)[0]
            replica = False
            if ('replica' in request.data):
                replica = request.data['replica']
                if (type(replica) != bool):
                    e_msg = ('replica must be a boolean, not %s' %
                             type(replica))
                    handle_exception(Exception(e_msg), request)
            pqid = qgroup_create(pool)
            add_share(pool, sname, pqid)
            qid = qgroup_id(pool, sname)
            update_quota(pool, pqid, size * 1024)
            s = Share(pool=pool, qgroup=qid, pqgroup=pqid, name=sname,
                      size=size, subvol_name=sname, replica=replica,
                      compression_algo=compression)
            s.save()
            mnt_pt = '%s%s' % (settings.MNT_PT, sname)
            if (not is_share_mounted(sname)):
                mount_share(s, mnt_pt)
            if (compression != 'no'):
                set_property(mnt_pt, 'compression', compression)
            return Response(ShareSerializer(s).data)
Пример #26
0
    def post(self, request):
        #qgroup notes for shares. we need to create a qgroup prior to share
        #creation. qgroup ids 0/<subvol_id> automatically get created when a
        #subvolume(i.e., a Share or a Snapshot) is created. So let's create a
        #new qgroup: 2015/<some_number> whenever a Share is
        #created. <some_number> starts from 1 and is incremented as more Shares
        #are created. So, for the very first Share in a pool, it's qgroup will
        #be 1/1. 2015 is arbitrarily chose.

        #Before creating a new Share, we create the qgroup for it. And during
        #it's creation, we assign this qgroup to it. During it's creation a 0/x
        #qgroup will automatically be created, but it will become the child of
        #our explicitly-created qgroup(2015/x).

        #We will set the qgroup limit on our qgroup and it will enforce the
        #quota on every subvolume(i.e., Share and Snapshot) in that qgroup.

        #When a Share is deleted, we need to destroy two qgroups. One is it's
        #auto 0/x qgroup and the other is our explicitly-created 2015/y qgroup.

        with self._handle_exception(request):
            pool_name = request.data.get('pool', None)
            try:
                pool = Pool.objects.get(name=pool_name)
            except:
                e_msg = ('Pool(%s) does not exist.' % pool_name)
                handle_exception(Exception(e_msg), request)
            compression = self._validate_compression(request)
            size = self._validate_share_size(request, pool)
            sname = request.data.get('sname', None)
            if ((sname is None
                 or re.match('%s$' % settings.SHARE_REGEX, sname) is None)):
                e_msg = ('Share name must start with a alphanumeric(a-z0-9) '
                         'character and can be followed by any of the '
                         'following characters: letter(a-z), digits(0-9), '
                         'hyphen(-), underscore(_) or a period(.).')
                handle_exception(Exception(e_msg), request)

            if (len(sname) > 254):
                #btrfs subvolume names cannot exceed 254 characters.
                e_msg = ('Share name length cannot exceed 254 characters')
                handle_exception(Exception(e_msg), request)

            if (Share.objects.filter(name=sname).exists()):
                e_msg = ('Share(%s) already exists. Choose a different name' %
                         sname)
                handle_exception(Exception(e_msg), request)

            if (Pool.objects.filter(name=sname).exists()):
                e_msg = (
                    'A Pool with this name(%s) exists. Share and Pool names '
                    'must be distinct. Choose a different name' % sname)
                handle_exception(Exception(e_msg), request)
            disk = Disk.objects.filter(pool=pool)[0]
            replica = False
            if ('replica' in request.data):
                replica = request.data['replica']
                if (type(replica) != bool):
                    e_msg = ('replica must be a boolean, not %s' %
                             type(replica))
                    handle_exception(Exception(e_msg), request)
            pqid = qgroup_create(pool)
            add_share(pool, sname, pqid)
            qid = qgroup_id(pool, sname)
            update_quota(pool, pqid, size * 1024)
            s = Share(pool=pool,
                      qgroup=qid,
                      pqgroup=pqid,
                      name=sname,
                      size=size,
                      subvol_name=sname,
                      replica=replica,
                      compression_algo=compression)
            s.save()
            mnt_pt = '%s%s' % (settings.MNT_PT, sname)
            if (not is_share_mounted(sname)):
                mount_share(s, mnt_pt)
            if (compression != 'no'):
                set_property(mnt_pt, 'compression', compression)
            return Response(ShareSerializer(s).data)
Пример #27
0
    def post(self, request, uuid):
        """
        import a pool with given uuid
        """
        disks = Disk.objects.filter(btrfs_uuid=uuid)

        if (not btrfs_importable(disks[0].name)):
            e_msg = ('btrfs check failed on device: %s Cannot automatically '
                     'import the pool with uuid: %s' % (disks[0].name, uuid))
            handle_exception(Exception(e_msg), request)


        #get name of the pool
        pname = btrfs_label(uuid)

        #mount the pool
        mount_root(pname, '/dev/%s' % disks[0].name)
        pool_mnt_pt = '%s/%s' % (settings.MNT_PT, pname)

        #get raid level
        raid_level = btrfs_raid_level(pname)
        if (raid_level is None):
            umount_root(pool_mnt_pt)
            e_msg = ('Problem while probing for the raid level of the pool.'
                     'Cannot automatically import the pool with uuid: %s' %
                     uuid)
            handle_exception(Exception(e_msg), request)

        #check for shares in the pool
        subvols, e, rc = subvol_list_helper(pool_mnt_pt)
        snap_list = snapshot_list(pool_mnt_pt)
        share_map = {}
        for s in subvols:
            s_fields = s.split()
            if (s_fields[-1] not in snap_list):
                share_map[s_fields[-1]] = s_fields[1]

        entries = os.listdir(pool_mnt_pt)
        e_msg_prefix = ('Only btrfs filesystem with nothing but subvolumes in '
                        'it can be imported.')
        for e in entries:
            if (os.path.isfile('%s/%s' % (pool_mnt_pt, e))):
                e_msg = ('%s Unexpected file %s found. Due to this reason, '
                         'pool with uuid: %s cannot be imported' %
                         (e_msg_prefix, e, uuid))
                handle_exception(Exception(e_msg), request)
            elif (e not in share_map):
                e_msg = ('%s Unexpected directory %s found. Due to this '
                         'reason, pool with uuid: %s cannot be imported' %
                         (e_msg_prefix, e, uuid))
                handle_exception(Exception(e_msg), request)

        #add pool model
        pool_size = self._pool_size(disks, raid_level)
        p = Pool(name=pname, raid=raid_level, size=pool_size, uuid=uuid)
        p.save()

        #import shares
        for s in share_map.keys():
            so = Share(pool=p, qgroup='0/%s' % share_map[s], name=s,
                       size=qgroup_size, subvol_name=s, replica=False)
            so.save()

            #import snapshots?
            for snap in snap_list:
                snap_fields = snap.split('_')
                snap_name = snap_fields[-1]
                sname = '_'.join(snap_fields[0:-1])
                if (sname == s):
                    snapo = Snapshot(share=so, name=snap_name,
                                     real_name=snap, qgroup=qgroup_id)
                    snapo.save()
Пример #28
0
def import_shares(pool, request):
    # Establish known shares/subvols within our db for the given pool:
    shares_in_pool_db = [s.name for s in Share.objects.filter(pool=pool)]
    # Find the actual/current shares/subvols within the given pool:
    # Limited to Rockstor relevant subvols ie shares and clones.
    shares_in_pool = shares_info(pool)
    # Delete db Share object if it is no longer found on disk.
    for s_in_pool_db in shares_in_pool_db:
        if s_in_pool_db not in shares_in_pool:
            Share.objects.get(pool=pool, name=s_in_pool_db).delete()
    # Check if each share in pool also has a db counterpart.
    for s_in_pool in shares_in_pool:
        logger.debug('Share name = {}.'.format(s_in_pool))
        if s_in_pool in shares_in_pool_db:
            logger.debug('Updating pre-existing same pool db share entry.')
            # We have a pool db share counterpart so retrieve and update it.
            share = Share.objects.get(name=s_in_pool, pool=pool)
            share.qgroup = shares_in_pool[s_in_pool]
            rusage, eusage, pqgroup_rusage, pqgroup_eusage = \
                volume_usage(pool, share.qgroup, share.pqgroup)
            if (rusage != share.rusage or eusage != share.eusage
                    or pqgroup_rusage != share.pqgroup_rusage
                    or pqgroup_eusage != share.pqgroup_eusage):
                share.rusage = rusage
                share.eusage = eusage
                share.pqgroup_rusage = pqgroup_rusage
                share.pqgroup_eusage = pqgroup_eusage
                update_shareusage_db(s_in_pool, rusage, eusage)
            else:
                update_shareusage_db(s_in_pool, rusage, eusage, UPDATE_TS)
            share.save()
            continue
        try:
            logger.debug('No prior entries in scanned pool trying all pools.')
            # Test (Try) for an existing system wide Share db entry.
            cshare = Share.objects.get(name=s_in_pool)
            # Get a list of Rockstor relevant subvols (ie shares and clones)
            # for the prior existing db share entry's pool.
            cshares_d = shares_info(cshare.pool)
            if s_in_pool in cshares_d:
                e_msg = ('Another pool ({}) has a Share with this same '
                         'name ({}) as this pool ({}). This configuration '
                         'is not supported. You can delete one of them '
                         'manually with the following command: '
                         '"btrfs subvol delete {}[pool name]/{}" WARNING this '
                         'will remove the entire contents of that subvolume.'.
                         format(cshare.pool.name, s_in_pool, pool.name,
                                settings.MNT_PT, s_in_pool))
                handle_exception(Exception(e_msg), request)
            else:
                # Update the prior existing db share entry previously
                # associated with another pool.
                logger.debug('Updating prior db entry from another pool.')
                cshare.pool = pool
                cshare.qgroup = shares_in_pool[s_in_pool]
                cshare.size = pool.size
                cshare.subvol_name = s_in_pool
                (cshare.rusage, cshare.eusage, cshare.pqgroup_rusage,
                 cshare.pqgroup_eusage) = volume_usage(pool, cshare.qgroup,
                                                       cshare.pqgroup)
                cshare.save()
                update_shareusage_db(s_in_pool, cshare.rusage, cshare.eusage)
        except Share.DoesNotExist:
            logger.debug('Db share entry does not exist - creating.')
            # We have a share on disk that has no db counterpart so create one.
            # Retrieve pool quota id for use in db Share object creation.
            pqid = qgroup_create(pool)
            update_quota(pool, pqid, pool.size * 1024)
            rusage, eusage, pqgroup_rusage, pqgroup_eusage = \
                volume_usage(pool, shares_in_pool[s_in_pool], pqid)
            nso = Share(pool=pool,
                        qgroup=shares_in_pool[s_in_pool],
                        pqgroup=pqid,
                        name=s_in_pool,
                        size=pool.size,
                        subvol_name=s_in_pool,
                        rusage=rusage,
                        eusage=eusage,
                        pqgroup_rusage=pqgroup_rusage,
                        pqgroup_eusage=pqgroup_eusage)
            nso.save()
            update_shareusage_db(s_in_pool, rusage, eusage)
            mount_share(nso, '%s%s' % (settings.MNT_PT, s_in_pool))
Пример #29
0
def import_shares(pool, request):
    # Establish known shares/subvols within our db for the given pool:
    shares_in_pool_db = [s.name for s in Share.objects.filter(pool=pool)]
    # Find the actual/current shares/subvols within the given pool:
    # Limited to Rockstor relevant subvols ie shares and clones.
    shares_in_pool = shares_info(pool)
    # List of pool's share.pqgroups so we can remove inadvertent duplication.
    # All pqgroups are removed when quotas are disabled, combined with a part
    # refresh we could have duplicates within the db.
    share_pqgroups_used = []
    # Delete db Share object if it is no longer found on disk.
    for s_in_pool_db in shares_in_pool_db:
        if s_in_pool_db not in shares_in_pool:
            logger.debug('Removing, missing on disk, share db entry ({}) from '
                         'pool ({}).'.format(s_in_pool_db, pool.name))
            Share.objects.get(pool=pool, name=s_in_pool_db).delete()
    # Check if each share in pool also has a db counterpart.
    for s_in_pool in shares_in_pool:
        logger.debug('---- Share name = {}.'.format(s_in_pool))
        if s_in_pool in shares_in_pool_db:
            logger.debug('Updating pre-existing same pool db share entry.')
            # We have a pool db share counterpart so retrieve and update it.
            share = Share.objects.get(name=s_in_pool, pool=pool)
            # Initially default our pqgroup value to db default of '-1/-1'
            # This way, unless quotas are enabled, all pqgroups will be
            # returned to db default.
            pqgroup = PQGROUP_DEFAULT
            if share.pool.quotas_enabled:
                # Quotas are enabled on our pool so we can validate pqgroup.
                if share.pqgroup == pqgroup or not share.pqgroup_exist \
                        or share.pqgroup in share_pqgroups_used:
                    # we have a void '-1/-1' or non existent pqgroup or
                    # this pqgroup has already been seen / used in this pool.
                    logger.debug('#### replacing void, non-existent, or '
                                 'duplicate pqgroup.')
                    pqgroup = qgroup_create(pool)
                    if pqgroup is not PQGROUP_DEFAULT:
                        update_quota(pool, pqgroup, share.size * 1024)
                        share_pqgroup_assign(pqgroup, share)
                else:
                    # Our share's pqgroup looks OK so use it.
                    pqgroup = share.pqgroup
                # Record our use of this pqgroup to spot duplicates later.
                share_pqgroups_used.append(deepcopy(share.pqgroup))
            if share.pqgroup != pqgroup:
                # we need to update our share.pqgroup
                share.pqgroup = pqgroup
                share.save()
            share.qgroup = shares_in_pool[s_in_pool]
            rusage, eusage, pqgroup_rusage, pqgroup_eusage = \
                volume_usage(pool, share.qgroup, pqgroup)
            if (rusage != share.rusage or eusage != share.eusage or
               pqgroup_rusage != share.pqgroup_rusage or
               pqgroup_eusage != share.pqgroup_eusage):
                share.rusage = rusage
                share.eusage = eusage
                share.pqgroup_rusage = pqgroup_rusage
                share.pqgroup_eusage = pqgroup_eusage
                update_shareusage_db(s_in_pool, rusage, eusage)
            else:
                update_shareusage_db(s_in_pool, rusage, eusage, UPDATE_TS)
            share.save()
            continue
        try:
            logger.debug('No prior entries in scanned pool trying all pools.')
            # Test (Try) for an existing system wide Share db entry.
            cshare = Share.objects.get(name=s_in_pool)
            # Get a list of Rockstor relevant subvols (ie shares and clones)
            # for the prior existing db share entry's pool.
            cshares_d = shares_info(cshare.pool)
            if s_in_pool in cshares_d:
                e_msg = ('Another pool ({}) has a share with this same '
                         'name ({}) as this pool ({}). This configuration '
                         'is not supported. You can delete one of them '
                         'manually with the following command: '
                         '"btrfs subvol delete {}[pool name]/{}" WARNING this '
                         'will remove the entire contents of that '
                         'subvolume.').format(cshare.pool.name, s_in_pool,
                                              pool.name, settings.MNT_PT,
                                              s_in_pool)
                handle_exception(Exception(e_msg), request)
            else:
                # Update the prior existing db share entry previously
                # associated with another pool.
                logger.debug('Updating prior db entry from another pool.')
                cshare.pool = pool
                cshare.qgroup = shares_in_pool[s_in_pool]
                cshare.size = pool.size
                cshare.subvol_name = s_in_pool
                (cshare.rusage, cshare.eusage, cshare.pqgroup_rusage,
                 cshare.pqgroup_eusage) = volume_usage(pool, cshare.qgroup,
                                                       cshare.pqgroup)
                cshare.save()
                update_shareusage_db(s_in_pool, cshare.rusage, cshare.eusage)
        except Share.DoesNotExist:
            logger.debug('Db share entry does not exist - creating.')
            # We have a share on disk that has no db counterpart so create one.
            # Retrieve new pool quota id for use in db Share object creation.
            # As the replication receive share is 'special' we tag it as such.
            replica = False
            share_name = s_in_pool
            if re.match('.snapshot', s_in_pool) is not None:
                # We have an initial replication share, non snap in .snapshots.
                # We could change it's name here but still a little mixing
                # of name and subvol throughout project.
                replica = True
                logger.debug('Initial receive quirk-subvol found: Importing '
                             'as share and setting replica flag.')
            qid = shares_in_pool[s_in_pool]
            pqid = qgroup_create(pool)
            if pqid is not PQGROUP_DEFAULT:
                update_quota(pool, pqid, pool.size * 1024)
                pool_mnt_pt = '{}{}'.format(settings.MNT_PT, pool.name)
                qgroup_assign(qid, pqid, pool_mnt_pt)
            rusage, eusage, pqgroup_rusage, pqgroup_eusage = \
                volume_usage(pool, qid, pqid)
            nso = Share(pool=pool, qgroup=qid, pqgroup=pqid, name=share_name,
                        size=pool.size, subvol_name=s_in_pool, rusage=rusage,
                        eusage=eusage, pqgroup_rusage=pqgroup_rusage,
                        pqgroup_eusage=pqgroup_eusage,
                        replica=replica)
            nso.save()
            update_shareusage_db(s_in_pool, rusage, eusage)
            mount_share(nso, '%s%s' % (settings.MNT_PT, s_in_pool))
Пример #30
0
    def test_post_requests_2(self, mock_nfs, mock_pool, mock_share):
        """
        1. Create snapshot providing invalid uvisible bool type
        2. Create snapshot providing invalid writable bool type
        3. happy path to create snapshot
        2. Create a snapshot with duplicate name
        """

        temp_pool = Pool(id=1, name='rockstor_rockstor', size=88025459)
        mock_pool.objects.get.return_value = temp_pool

        temp_share = Share(id=3, name='share1', pool=temp_pool, size=8025459)
        mock_share.objects.get.return_value = temp_share
        # mock_snapshot.objects.get.side_effect = Snapshot.DoesNotExist

        # Invalid uvisible bool type
        data = {
            'snapshot-name': 'snap3',
            'shares': 'share1',
            'writable': False,
            'uvisible': 'invalid'
        }
        snap_name = 'snap3'
        share_name = 'share1'
        share_id = 3  # from fix5.json
        response = self.client.post('%s/%s/snapshots/%s' %
                                    (self.BASE_URL, share_id, snap_name),
                                    data=data,
                                    sname=share_name,
                                    snap_name=snap_name)
        self.assertEqual(response.status_code,
                         status.HTTP_500_INTERNAL_SERVER_ERROR,
                         msg=response.data)
        e_msg = "Element 'uvisible' must be a boolean, not (<type 'unicode'>)."
        self.assertEqual(response.data[0], e_msg)

        # Invalid writable bool type
        data = {
            'snapshot-name': 'snap3',
            'shares': 'share1',
            'writable': 'invalid',
            'uvisible': True
        }
        snap_name = 'snap3'
        share = 'share1'
        share_id = 3  # from fix5.json and above mocking object
        mock_nfs.objects.filter(share=share).exists.return_value = True
        response = self.client.post('{}/{}/snapshots/{}'.format(
            self.BASE_URL, share_id, snap_name),
                                    data=data,
                                    sname=share,
                                    snap_name=snap_name)
        self.assertEqual(response.status_code,
                         status.HTTP_500_INTERNAL_SERVER_ERROR,
                         msg=response.data)
        # TODO consider changing tested code to unify quota types to single
        # as per "Invalid uvisible bool type" to remove need for escaping here.
        e_msg = ('Element "writable" must be a boolean, not '
                 '(<type \'unicode\'>).')
        self.assertEqual(response.data[0], e_msg)

        # # Happy Path creating a snapshot by name snap3
        data = {
            'snapshot-name': 'snap3',
            'shares': 'share1',
            'writable': False,
            'uvisible': False
        }
        snap_name = 'snap3'
        share = 'share1'
        share_id = 3  # from fix5.json and above mocking object
        mock_nfs.objects.filter(share=share).exists.return_value = True
        response = self.client.post('{}/{}/snapshots/{}'.format(
            self.BASE_URL, share_id, snap_name),
                                    data=data,
                                    sname=share,
                                    snap_name=snap_name)
        self.assertEqual(response.status_code,
                         status.HTTP_200_OK,
                         msg=response.data)

        # # Create duplicate snapshot by name snap3
        data = {
            'snapshot-name': 'snap2',
            'shares': 'share2',
            'writable': True,
            'uvisible': True
        }
        snap_name = 'snap3'
        share_name = 'share1'
        share_id = 3  # from fix5.json
        response = self.client.post('{}/{}/snapshots/{}'.format(
            self.BASE_URL, share_id, snap_name),
                                    data=data,
                                    sname=share_name,
                                    snap_name=snap_name)
        self.assertEqual(response.status_code,
                         status.HTTP_500_INTERNAL_SERVER_ERROR,
                         msg=response.data)
        e_msg = ('Snapshot ({}) already exists for the '
                 'share ({}).').format(snap_name, share_name)
        self.assertEqual(response.data[0], e_msg)
Пример #31
0
    def test_delete_requests(self, mock_pool, mock_share, mock_snapshot):
        """
        1. Delete snapshot that does not exist
        2. Delete snapshot with no name specified
        """

        temp_pool = Pool(id=1, name='rockstor_rockstor', size=88025459)
        mock_pool.objects.get.return_value = temp_pool

        temp_share = Share(id=3, name='share1', pool=temp_pool, size=8025459)
        mock_share.objects.get.return_value = temp_share

        mock_snapshot.objects.get.side_effect = Snapshot.DoesNotExist

        # # Delete snapshot that does not exists
        snap_name = 'snap3'
        share_name = 'share1'
        share_id = 3  # from fix5.json
        response = self.client.delete('{}/{}/snapshots/{}'.format(
            self.BASE_URL, share_id, snap_name))
        self.assertEqual(response.status_code,
                         status.HTTP_500_INTERNAL_SERVER_ERROR,
                         msg=response.data)
        e_msg = 'Snapshot name (snap3) does not exist.'
        self.assertEqual(response.data[0], e_msg)

        temp_share2 = Share(id=4, name='share2', pool=temp_pool, size=8025459)
        mock_share.objects.get.return_value = temp_share2

        # Delete without snapshot name
        share_name = 'share1'
        share_id = 3  # from fix5.json
        response = self.client.delete('{}/{}/snapshots'.format(
            self.BASE_URL, share_id))
        self.assertEqual(response.status_code,
                         status.HTTP_200_OK,
                         msg=response.data)

        # Delete snapshot happy path
        # creating a snapshot just for the next test.
        # TODO: replace this repeat post test with a proper mock of a snapshot
        # ie attempted to use:

        # temp_snap = Snapshot(id=2, name='snap2', share=temp_share2,
        #                      snap_type='admin')
        # mock_snapshot.objects.get.return_value = temp_snap
        # mock_snapshot.objects.filter(share='share2', name='snap2'
        #                              ).exists.return_value = True
        # but received:
        # 'Snapshot name (snap2) does not exist.'

        data = {
            'snapshot-name': 'snap2',
            'shares': 'share2',
            'writable': False,
            'uvisible': False
        }
        snap_name = 'snap2'
        share = 'share2'
        share_id = 4
        response = self.client.post('{}/{}/snapshots/{}'.format(
            self.BASE_URL, share_id, snap_name),
                                    data=data,
                                    sname=share,
                                    snap_name=snap_name)
        self.assertEqual(response.status_code,
                         status.HTTP_200_OK,
                         msg=response.data)
        # now move to our happy path delete test of just created 'snap2'
        response = self.client.delete('{}/{}/snapshots/{}'.format(
            self.BASE_URL, share_id, snap_name))
        self.assertEqual(response.status_code,
                         status.HTTP_200_OK,
                         msg=response.data)
Пример #32
0
    def post(self, request, uuid):
        """
        import a pool with given uuid
        """
        disks = Disk.objects.filter(btrfs_uuid=uuid)

        if (not btrfs_importable(disks[0].name)):
            e_msg = ('btrfs check failed on device: %s Cannot automatically '
                     'import the pool with uuid: %s' % (disks[0].name, uuid))
            handle_exception(Exception(e_msg), request)

        #get name of the pool
        pname = btrfs_label(uuid)

        #mount the pool
        mount_root(pname, '/dev/%s' % disks[0].name)
        pool_mnt_pt = '%s/%s' % (settings.MNT_PT, pname)

        #get raid level
        raid_level = btrfs_raid_level(pname)
        if (raid_level is None):
            umount_root(pool_mnt_pt)
            e_msg = ('Problem while probing for the raid level of the pool.'
                     'Cannot automatically import the pool with uuid: %s' %
                     uuid)
            handle_exception(Exception(e_msg), request)

        #check for shares in the pool
        subvols, e, rc = subvol_list_helper(pool_mnt_pt)
        snap_list = snapshot_list(pool_mnt_pt)
        share_map = {}
        for s in subvols:
            s_fields = s.split()
            if (s_fields[-1] not in snap_list):
                share_map[s_fields[-1]] = s_fields[1]

        entries = os.listdir(pool_mnt_pt)
        e_msg_prefix = ('Only btrfs filesystem with nothing but subvolumes in '
                        'it can be imported.')
        for e in entries:
            if (os.path.isfile('%s/%s' % (pool_mnt_pt, e))):
                e_msg = ('%s Unexpected file %s found. Due to this reason, '
                         'pool with uuid: %s cannot be imported' %
                         (e_msg_prefix, e, uuid))
                handle_exception(Exception(e_msg), request)
            elif (e not in share_map):
                e_msg = ('%s Unexpected directory %s found. Due to this '
                         'reason, pool with uuid: %s cannot be imported' %
                         (e_msg_prefix, e, uuid))
                handle_exception(Exception(e_msg), request)

        #add pool model
        pool_size = self._pool_size(disks, raid_level)
        p = Pool(name=pname, raid=raid_level, size=pool_size, uuid=uuid)
        p.save()

        #import shares
        for s in share_map.keys():
            so = Share(pool=p,
                       qgroup='0/%s' % share_map[s],
                       name=s,
                       size=qgroup_size,
                       subvol_name=s,
                       replica=False)
            so.save()

            #import snapshots?
            for snap in snap_list:
                snap_fields = snap.split('_')
                snap_name = snap_fields[-1]
                sname = '_'.join(snap_fields[0:-1])
                if (sname == s):
                    snapo = Snapshot(share=so,
                                     name=snap_name,
                                     real_name=snap,
                                     qgroup=qgroup_id)
                    snapo.save()