Beispiel #1
0
def check_error(response):
    code = response.status_code
    if code not in (200, 201, 202):
        reason = response.reason
        body = response.content
        try:
            content = jsonutils.loads(body) if body else None
        except ValueError:
            msg = (_('Could not parse response from %(appliance)s: '
                     '%(code)s %(reason)s %(body)s') % {
                         'appliance': APPLIANCE,
                         'code': code,
                         'reason': reason,
                         'body': body
                     })
            raise exception.NexentaException(msg)
        if content and 'code' in content:
            raise exception.NexentaException(content)
        msg = (_('Got bad response from %(appliance)s: '
                 '%(code)s %(reason)s %(content)s') % {
                     'appliance': APPLIANCE,
                     'code': code,
                     'reason': reason,
                     'content': content
                 })
        raise exception.NexentaException(msg)
Beispiel #2
0
 def test_create_cloned_volume(self, crt_vol, dlt_snap, crt_snap):
     self._create_volume_db_entry()
     vol = self.TEST_VOLUME_REF2
     src_vref = self.TEST_VOLUME_REF
     crt_vol.side_effect = exception.NexentaException()
     dlt_snap.side_effect = exception.NexentaException()
     self.assertRaises(exception.NexentaException,
                       self.drv.create_cloned_volume, vol, src_vref)
Beispiel #3
0
    def test_do_setup(self):
        self.nef_mock.post.side_effect = exception.NexentaException(
            'Could not create volume group')
        self.assertRaises(exception.NexentaException, self.drv.do_setup,
                          self.ctxt)

        self.nef_mock.post.side_effect = exception.NexentaException(
            '{"code": "EEXIST"}')
        self.assertIsNone(self.drv.do_setup(self.ctxt))
Beispiel #4
0
 def handle_failover(self):
     if self.__proxy.backup:
         LOG.info(
             'Primary %(appliance)s %(host)s is unavailable, '
             'failing over to secondary %(backup)s', {
                 'appliance': APPLIANCE,
                 'host': self.__proxy.host,
                 'backup': self.__proxy.backup
             })
         host = '%s,%s' % (self.__proxy.backup, self.__proxy.host)
         self.__proxy.__init__(host, self.__proxy.port, self.__proxy.user,
                               self.__proxy.password,
                               self.__proxy.use_https, self.__proxy.pool,
                               self.__proxy.verify)
         url = self.get_full_url('rsf/clusters')
         response = self.__proxy.session.get(url,
                                             verify=self.__proxy.verify)
         content = response.json() if response.content else None
         if not content:
             raise exception.NexentaException(response)
         cluster_name = content['data'][0]['clusterName']
         for node in content['data'][0]['nodes']:
             if node['ipAddress'] == self.__proxy.host:
                 node_name = node['machineName']
         counter = 0
         interval = 5
         url = self.get_full_url('rsf/clusters/%s/services' % cluster_name)
         while counter < 24:
             counter += 1
             response = self.__proxy.session.get(url,
                                                 verify=self.__proxy.verify)
             content = response.json() if response.content else None
             if content:
                 for service in content['data']:
                     if service['serviceName'] == self.__proxy.pool:
                         if len(service['vips']) == 0:
                             continue
                         for mapping in service['vips'][0]['nodeMapping']:
                             if (mapping['node'] == node_name
                                     and mapping['status'] == 'up'):
                                 return
             LOG.debug(
                 'Pool %(pool)s service is not ready, '
                 'sleeping for %(interval)ss', {
                     'pool': self.__proxy.pool,
                     'interval': interval
                 })
             time.sleep(interval)
         msg = (_('Waited for %(period)ss, but pool %(pool)s '
                  'service is still not running') % {
                      'period': counter * interval,
                      'pool': self.__proxy.pool
                  })
         raise exception.NexentaException(msg)
     else:
         raise
Beispiel #5
0
    def test_delete_snapshot(self):
        self._create_volume_db_entry()
        self.nef_mock.delete.side_effect = exception.NexentaException('EBUSY')
        self.drv.delete_snapshot(self.TEST_SNAPSHOT_REF)
        url = ('storage/pools/pool/volumeGroups/dsg/'
               'volumes/volume-1/snapshots/snapshot1')
        self.nef_mock.delete.assert_called_with(url)

        self.nef_mock.delete.side_effect = exception.NexentaException('Error')
        self.drv.delete_snapshot(self.TEST_SNAPSHOT_REF)
        self.nef_mock.delete.assert_called_with(url)
Beispiel #6
0
    def test_delete_snapshot(self):
        self._create_volume_db_entry()
        url = ('storage/snapshots/pool%2Fvg%2Fvolume-1@snapshot1')

        self.nef_mock.delete.side_effect = exception.NexentaException(
            'Failed to destroy snapshot')
        self.drv.delete_snapshot(self.TEST_SNAPSHOT_REF)
        self.nef_mock.delete.assert_called_with(url)

        self.nef_mock.delete.side_effect = exception.NexentaException('Error')
        self.assertIsNone(self.drv.delete_snapshot(self.TEST_SNAPSHOT_REF))
Beispiel #7
0
 def check_for_setup_error(self):
     try:
         if not self.symlinks_dir:
             msg = _("nexenta_nbd_symlinks_dir option is not specified")
             raise exception.NexentaException(message=msg)
         if not os.path.exists(self.symlinks_dir):
             msg = _("NexentaEdge NBD symlinks directory doesn't exist")
             raise exception.NexentaException(message=msg)
         self.restapi.get(self.bucket_url + '/objects/')
     except exception.VolumeBackendAPIException:
         with excutils.save_and_reraise_exception():
             LOG.exception(_LE('Error verifying container %(bkt)s'),
                           {'bkt': self.bucket_path})
Beispiel #8
0
    def test_delete_snapshot(self):
        self.drv.collect_zfs_garbage = lambda x: None
        self._create_volume_db_entry()
        url = ('storage/pools/pool/volumeGroups/dsg/'
               'volumes/volume-1/snapshots/snapshot1')

        self.nef_mock.delete.side_effect = exception.NexentaException(
            'Failed to destroy snapshot')
        self.drv.delete_snapshot(self.TEST_SNAPSHOT_REF)
        self.nef_mock.delete.assert_called_with(url)

        self.nef_mock.delete.side_effect = exception.NexentaException('Error')
        self.assertRaises(exception.NexentaException, self.drv.delete_snapshot,
                          self.TEST_SNAPSHOT_REF)
Beispiel #9
0
    def test_remove_export(self, lun_id, tg_name):
        lun_id.return_value = '0'
        tg_name.return_value = '1.1.1.1-0'
        self.nef_mock.delete.side_effect = exception.NexentaException(
            'No such logical unit in target group')
        self.assertIsNone(
            self.drv.remove_export(self.ctxt, self.TEST_VOLUME_REF))

        self.nef_mock.delete.side_effect = exception.NexentaException('Error')
        self.assertRaises(exception.NexentaException, self.drv.remove_export,
                          self.ctxt, self.TEST_VOLUME_REF)

        lun_id.side_effect = LookupError()
        self.assertIsNone(
            self.drv.remove_export(self.ctxt, self.TEST_VOLUME_REF))
Beispiel #10
0
    def do_setup(self, context):
        if self.restapi_protocol == 'auto':
            protocol, auto = 'http', True
        else:
            protocol, auto = self.restapi_protocol, False

        try:
            self.restapi = jsonrpc.NexentaEdgeJSONProxy(protocol,
                                                        self.restapi_host,
                                                        self.restapi_port,
                                                        '/',
                                                        self.restapi_user,
                                                        self.restapi_password,
                                                        self.verify_ssl,
                                                        auto=auto)

            data = self.restapi.get('service/' + self.iscsi_service)['data']
            self.target_name = '%s%s' % (data['X-ISCSI-TargetName'],
                                         data['X-ISCSI-TargetID'])
            if 'X-VIPS' in data:
                if self.target_vip not in data['X-VIPS']:
                    raise exception.NexentaException(
                        'Configured client IP address does not match any VIP'
                        ' provided by iSCSI service %s' % self.iscsi_service)
                else:
                    self.ha_vip = self.target_vip
        except exception.VolumeBackendAPIException:
            with excutils.save_and_reraise_exception():
                LOG.exception(
                    'Error verifying iSCSI service %(serv)s on '
                    'host %(hst)s', {
                        'serv': self.iscsi_service,
                        'hst': self.restapi_host
                    })
Beispiel #11
0
    def test_delete_volume(self):
        self.drv.share2nms = {self.TEST_EXPORT1: self.nms_mock}
        self._create_volume_db_entry()

        self.drv._ensure_share_mounted = lambda *_, **__: 0
        self.drv._execute = lambda *_, **__: 0

        self.nms_mock.server.get_prop.return_value = '/volumes'
        self.nms_mock.folder.get_child_props.return_value = {
            'available': 1, 'used': 1}
        self.drv.delete_volume({
            'id': '1',
            'name': 'volume-1',
            'provider_location': self.TEST_EXPORT1
        })
        self.nms_mock.folder.destroy.assert_called_with(
            'stack/share/volume-1', '-r')

        # Check that exception not raised if folder does not exist on
        # NexentaStor appliance.
        mock = self.nms_mock.folder.destroy
        mock.side_effect = exception.NexentaException('Folder does not exist')
        self.drv.delete_volume({
            'id': '1',
            'name': 'volume-1',
            'provider_location': self.TEST_EXPORT1
        })
Beispiel #12
0
 def https_auth(self):
     LOG.debug('Sending auth request to %(appliance)s: %(url)s', {
         'appliance': APPLIANCE,
         'url': self.url
     })
     url = '/'.join((self.url, 'auth/login'))
     headers = {'Content-Type': 'application/json'}
     data = {'username': self.username, 'password': self.password}
     response = requests.post(url,
                              json=data,
                              verify=self.verify,
                              headers=headers,
                              timeout=TIMEOUT)
     content = json.loads(response.content) if response.content else None
     LOG.debug(
         'Auth response from %(appliance)s: '
         '%(code)s %(reason)s %(content)s', {
             'appliance': APPLIANCE,
             'code': response.status_code,
             'reason': response.reason,
             'content': content
         })
     check_error(response)
     response.close()
     if response.content:
         token = content['token']
         del content['token']
         return token
     msg = (_('Got bad response from %(appliance)s: '
              '%(code)s %(reason)s') % {
                  'appliance': APPLIANCE,
                  'code': response.status_code,
                  'reason': response.reason
              })
     raise exception.NexentaException(msg)
Beispiel #13
0
    def test_do_create_volume(self):
        volume = {
            'provider_location': self.TEST_EXPORT1,
            'size': 1,
            'name': 'volume-1'
        }
        self.drv.shares = {self.TEST_EXPORT1: None}
        self.drv.share2nms = {self.TEST_EXPORT1: self.nms_mock}

        compression = self.cfg.nexenta_dataset_compression
        self.nms_mock.folder.get_child_props.return_value = {
            'available': 1, 'used': 1}
        self.nms_mock.server.get_prop.return_value = '/volumes'
        self.nms_mock.netsvc.get_confopts('svc:/network/nfs/server:default',
                                          'configure').AndReturn({
                                              'nfs_server_versmax': {
                                                  'current': u'3'}})
        self.nms_mock.netsvc.get_confopts.return_value = {
            'nfs_server_versmax': {'current': 4}}
        self.nms_mock._ensure_share_mounted.return_value = True
        self.drv._do_create_volume(volume)
        self.nms_mock.folder.create_with_props.assert_called_with(
            'stack', 'share/volume-1', {'compression': compression})
        self.nms_mock.netstorsvc.share_folder.assert_called_with(
            self.TEST_SHARE_SVC, 'stack/share/volume-1', self.TEST_SHARE_OPTS)
        mock_chmod = self.nms_mock.appliance.execute
        mock_chmod.assert_called_with(
            'chmod ugo+rw /volumes/stack/share/volume-1/volume')
        mock_truncate = self.nms_mock.appliance.execute
        mock_truncate.side_effect = exception.NexentaException()
        self.nms_mock.server.get_prop.return_value = '/volumes'
        self.nms_mock.folder.get_child_props.return_value = {
            'available': 1, 'used': 1}
        self.assertRaises(exception.NexentaException,
                          self.drv._do_create_volume, volume)
 def test_delete_volume(self):
     self.drv.collect_zfs_garbage = lambda x: None
     self.nef_mock.delete.side_effect = exception.NexentaException(
         'Failed to destroy snapshot')
     self.assertIsNone(self.drv.delete_volume(self.TEST_VOLUME_REF))
     url = 'storage/pools/pool/volumeGroups'
     data = {'name': 'dsg', 'volumeBlockSize': 32768}
     self.nef_mock.post.assert_called_with(url, data)
    def test_check_for_setup_error(self):
        self.nef_mock.get.return_value = {
            'data': [{'name': 'iscsit', 'state': 'offline'}]}
        self.assertRaises(
            exception.NexentaException, self.drv.check_for_setup_error)

        self.nef_mock.get.side_effect = exception.NexentaException()
        self.assertRaises(LookupError, self.drv.check_for_setup_error)
Beispiel #16
0
 def handle_failover(self):
     if self.__proxy.backup:
         LOG.info('Server %s is unavailable, failing over to %s',
                  self.__proxy.host, self.__proxy.backup)
         host = '%s,%s' % (self.__proxy.backup, self.__proxy.host)
         self.__proxy.__init__(host, self.__proxy.port, self.__proxy.user,
                               self.__proxy.password,
                               self.__proxy.use_https, self.__proxy.pool,
                               self.__proxy.verify)
         url = self.get_full_url('rsf/clusters')
         response = self.__proxy.session.get(url,
                                             verify=self.__proxy.verify)
         content = response.json() if response.content else None
         if not content:
             raise exception.NexentaException(response)
         cluster_name = content['data'][0]['clusterName']
         for node in content['data'][0]['nodes']:
             if node['ipAddress'] == self.__proxy.host:
                 node_name = node['machineName']
         counter = 0
         interval = 5
         url = self.get_full_url('rsf/clusters/%s/services' % cluster_name)
         while counter < 24:
             counter += 1
             response = self.__proxy.session.get(url)
             content = response.json() if response.content else None
             if content:
                 for service in content['data']:
                     if service['serviceName'] == self.__proxy.pool:
                         if len(service['vips']) == 0:
                             continue
                         for mapping in service['vips'][0]['nodeMapping']:
                             if (mapping['node'] == node_name
                                     and mapping['status'] == 'up'):
                                 return
             LOG.debug('Pool not ready, sleeping for %ss' % interval)
             time.sleep(interval)
         raise exception.NexentaException(
             'Waited for %ss, but pool %s service is still not running' %
             (counter * interval, self.__proxy.pool))
     else:
         raise
Beispiel #17
0
 def check_for_setup_error(self):
     """Verify that the zfs pool, vg and iscsi service exists."""
     url = 'storage/pools/%s' % self.storage_pool
     self.nef.get(url)
     url = 'storage/volumeGroups/%s' % '%2F'.join(
         [self.storage_pool, self.volume_group])
     try:
         self.nef.get(url)
     except exception.NexentaException:
         msg = (_('Volume group %(group)s not found') % {
             'group': self.volume_group
         })
         raise exception.NexentaException(msg)
     services = self.nef.get('services')
     for service in services['data']:
         if service['name'] == 'iscsit':
             if service['state'] != 'online':
                 msg = _('iSCSI target service is not running')
                 raise exception.NexentaException(msg)
             break
Beispiel #18
0
 def _stub_all_export_methods(self):
     self.nms_mock.scsidisk.lu_exists.return_value = False
     self.nms_mock.scsidisk.lu_shared.side_effect = (
         exception.NexentaException(['does not exist for zvol']))
     self.nms_mock.scsidisk.create_lu.return_value = {'lun': 0}
     self.nms_mock.stmf.list_targets.return_value = []
     self.nms_mock.stmf.list_targetgroups.return_value = []
     self.nms_mock.stmf.list_targetgroup_members.return_value = []
     self.nms_mock._get_target_name.return_value = ['iqn:1.1.1.1-0']
     self.nms_mock.iscsitarget.create_targetgroup.return_value = ({
         'target_name': 'cinder/1.1.1.1-0'})
     self.nms_mock.scsidisk.add_lun_mapping_entry.return_value = {'lun': 0}
Beispiel #19
0
    def test_delete_snapshot(self):
        self._create_volume_db_entry()
        self.drv._collect_garbage = lambda vol: vol
        self.drv.delete_snapshot(self.TEST_SNAPSHOT_REF)
        self.nms_mock.snapshot.destroy.assert_called_with(
            'cinder/volume1@snapshot1', '')

        # Check that exception not raised if snapshot does not exist
        self.drv.delete_snapshot(self.TEST_SNAPSHOT_REF)
        self.nms_mock.snapshot.destroy.side_effect = (
            exception.NexentaException('does not exist'))
        self.nms_mock.snapshot.destroy.assert_called_with(
            'cinder/volume1@snapshot1', '')
Beispiel #20
0
    def check_for_setup_error(self):
        """Verify that the volume for our folder exists.

        :raise: :py:exc:`LookupError`
        """
        pool_name, fs = self._get_share_datasets(self.share)
        url = 'storage/pools/%s' % (pool_name)
        self.nef.get(url)

        url = 'nas/nfs?filesystem=%s' % urllib.parse.quote_plus(self.share)
        data = self.nef.get(url).get('data')
        if not (data and data[0].get('shareState') == 'online'):
            raise exception.NexentaException(
                _('NFS share %s is not accessible') % self.share)
Beispiel #21
0
    def __call__(self, *args):
        data = jsonutils.dumps({
            'object': self.obj,
            'method': self.method,
            'params': args
        })

        LOG.debug('Sending JSON data: %s', data)
        r = self.session.post(self.url, data=data, timeout=TIMEOUT)
        response = r.json()

        LOG.debug('Got response: %s', response)
        if response.get('error') is not None:
            message = response['error'].get('message', '')
            raise exception.NexentaException(message)
        return response.get('result')
Beispiel #22
0
    def __call__(self, path, data=None):
        auth = ('%s:%s' % (self.user, self.password)).encode('base64')[:-1]
        headers = {
            'Content-Type': 'application/json',
            'Authorization': 'Basic %s' % auth
        }
        url = self.url + path

        if data:
            data = jsonutils.dumps(data)

        LOG.debug('Sending JSON to url: %s, data: %s, method: %s',
                  path, data, self.method)
        if self.method == 'get':
            resp = requests.get(url, headers=headers)
        if self.method == 'post':
            resp = requests.post(url, data=data, headers=headers)
        if self.method == 'put':
            resp = requests.put(url, data=data, headers=headers)
        if self.method == 'delete':
            resp = requests.delete(url, data=data, headers=headers)

        if resp.status_code == 201 or (
                resp.status_code == 200 and not resp.content):
            LOG.debug('Got response: Success')
            return 'Success'

        response = resp.json()
        resp.close()
        if response and resp.status_code == 202:
            url = self.url + response['links'][0]['href']
            while resp.status_code == 202:
                time.sleep(1)
                resp = requests.get(url)
                if resp.status_code == 201 or (
                        resp.status_code == 200 and not resp.content):
                    LOG.debug('Got response: Success')
                    return 'Success'
                else:
                    response = resp.json()
                resp.close()
        if response.get('code'):
            raise exception.NexentaException(response)
        LOG.debug('Got response: %s', response)
        return response
Beispiel #23
0
def check_error(response):
    code = response.status_code
    if code not in (200, 201, 202):
        reason = response.reason
        body = response.content
        try:
            content = jsonutils.loads(body) if body else None
        except ValueError:
            raise exception.VolumeBackendAPIException(
                data=_(
                    'Could not parse response: %(code)s %(reason)s '
                    '%(content)s') % {
                        'code': code, 'reason': reason, 'content': body})
        if content and 'code' in content:
            raise exception.NexentaException(content)
        raise exception.VolumeBackendAPIException(
            data=_(
                'Got bad response: %(code)s %(reason)s %(content)s') % {
                    'code': code, 'reason': reason, 'content': content})
Beispiel #24
0
    def check_for_setup_error(self):
        """Verify that the zfs volumes exist.

        :raise: :py:exc:`LookupError`
        """
        url = 'storage/pools/%(pool)s/volumeGroups/%(group)s' % {
            'pool': self.storage_pool,
            'group': self.volume_group,
        }
        try:
            self.nef.get(url)
        except exception.NexentaException:
            raise LookupError(_("Dataset group %s not found at Nexenta SA"),
                              '/'.join([self.storage_pool, self.volume_group]))
        services = self.nef.get('services')
        for service in services['data']:
            if service['name'] == 'iscsit':
                if service['state'] != 'online':
                    raise exception.NexentaException(
                        'iSCSI service is not running on NS appliance')
                break
Beispiel #25
0
    def __call__(self, *args):
        data = jsonutils.dumps({
            'object': self.obj,
            'method': self.method,
            'params': args
        })
        auth = ('%s:%s' % (self.user, self.password)).encode('base64')[:-1]
        headers = {
            'Content-Type': 'application/json',
            'Authorization': 'Basic %s' % auth
        }
        LOG.debug('Sending JSON data: %s', data)
        req = requests.post(self.url, data=data, headers=headers)
        response = req.json()
        req.close()

        LOG.debug('Got response: %s', response)
        if response.get('error') is not None:
            message = response['error'].get('message', '')
            raise exception.NexentaException(message)
        return response.get('result')
Beispiel #26
0
    def __call__(self, *args):
        if self.obj in NMS_PLUGINS:
            kind, name = 'plugin', NMS_PLUGINS[self.obj]
        else:
            kind, name = 'object', self.obj

        data = jsonutils.dumps({
            kind: name,
            'method': self.method,
            'params': args
        })

        LOG.debug('Sending JSON data: %s', data)
        r = self.session.post(self.url, data=data, timeout=TIMEOUT,
                              verify=self.verify)
        response = r.json()

        LOG.debug('Got response: %s', response)
        if response.get('error') is not None:
            message = response['error'].get('message', '')
            raise exception.NexentaException(message)
        return response.get('result')
Beispiel #27
0
 def test_delete_snapshot__nexenta_error_on_delete(self):
     vol = 'pool/group/vol-1@snap-1'
     self.gc.mark_as_garbage(vol)
     self.nef_mock.delete.side_effect = exception.NexentaException('Error')
     self.gc.collect_zfs_garbage(vol)
Beispiel #28
0
 def test_extend_volume(self):
     self.nef_mock.put.side_effect = exception.NexentaException()
     self.assertRaises(exception.NexentaException, self.drv.extend_volume,
                       self.TEST_VOLUME_REF, 2)
Beispiel #29
0
 def test_delete_volume(self):
     self.nef_mock.delete.side_effect = exception.NexentaException()
     self.assertIsNone(self.drv.delete_volume(self.TEST_VOLUME_REF))
     url = 'storage/pools/pool/volumeGroups'
     data = {'name': 'dsg', 'volumeBlockSize': 32768}
     self.nef_mock.post.assert_called_with(url, data)