Remove the Nexenta Edge Driver

The Nexenta Edge driver was marked unsupported during the
Stein release.  The 3rd Party CI has not reported in 57 days.
This continues to fall outside our 3rd Party CI Policy.

This patch proposes removal of the driver.

Change-Id: I219b5e5bfa4f77afc895ec9c219e61e3fdb1b762
This commit is contained in:
Jay S. Bryant 2019-03-26 15:42:15 -05:00
parent 9aca21f5ce
commit a1c58b50ea
8 changed files with 16 additions and 846 deletions

View File

@ -1,269 +0,0 @@
#
# Copyright 2015 Nexenta Systems, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import mock
from mock import patch
from cinder import context
from cinder import exception
from cinder import test
from cinder.volume import configuration as conf
from cinder.volume.drivers.nexenta.nexentaedge import iscsi
from cinder.volume.drivers.nexenta import utils
NEDGE_BUCKET = 'c/t/bk'
NEDGE_SERVICE = 'isc'
NEDGE_URL = 'service/%s/iscsi' % NEDGE_SERVICE
NEDGE_BLOCKSIZE = 4096
NEDGE_CHUNKSIZE = 16384
MOCK_VOL = {
'id': 'vol1',
'name': 'vol1',
'size': 1
}
MOCK_VOL2 = {
'id': 'vol2',
'name': 'vol2',
'size': 1
}
MOCK_VOL3 = {
'id': 'vol3',
'name': 'vol3',
'size': 2
}
MOCK_SNAP = {
'id': 'snap1',
'name': 'snap1',
'volume_name': 'vol1',
'volume_size': 1
}
NEW_VOL_SIZE = 2
ISCSI_TARGET_NAME = 'iscsi_target_name:'
ISCSI_TARGET_STATUS = 'Target 1: ' + ISCSI_TARGET_NAME
class TestNexentaEdgeISCSIDriver(test.TestCase):
def setUp(self):
def _safe_get(opt):
return getattr(self.cfg, opt)
super(TestNexentaEdgeISCSIDriver, self).setUp()
self.context = context.get_admin_context()
self.cfg = mock.Mock(spec=conf.Configuration)
self.cfg.safe_get = mock.Mock(side_effect=_safe_get)
self.cfg.trace_flags = 'fake_trace_flags'
self.cfg.driver_data_namespace = 'fake_driver_data_namespace'
self.cfg.nexenta_client_address = '0.0.0.0'
self.cfg.nexenta_rest_address = '0.0.0.0'
self.cfg.nexenta_rest_port = 8080
self.cfg.nexenta_rest_protocol = 'http'
self.cfg.nexenta_iscsi_target_portal_port = 3260
self.cfg.nexenta_rest_user = 'admin'
self.cfg.driver_ssl_cert_verify = False
self.cfg.nexenta_rest_password = 'admin'
self.cfg.nexenta_lun_container = NEDGE_BUCKET
self.cfg.nexenta_iscsi_service = NEDGE_SERVICE
self.cfg.nexenta_blocksize = NEDGE_BLOCKSIZE
self.cfg.nexenta_chunksize = NEDGE_CHUNKSIZE
self.cfg.nexenta_replication_count = 2
self.cfg.nexenta_encryption = True
self.cfg.replication_device = None
self.cfg.nexenta_iops_limit = 0
mock_exec = mock.Mock()
mock_exec.return_value = ('', '')
self.driver = iscsi.NexentaEdgeISCSIDriver(execute=mock_exec,
configuration=self.cfg)
self.api_patcher = mock.patch('cinder.volume.drivers.nexenta.'
'nexentaedge.jsonrpc.'
'NexentaEdgeJSONProxy.__call__')
self.mock_api = self.api_patcher.start()
self.mock_api.return_value = {
'data': {
'X-ISCSI-TargetName': ISCSI_TARGET_NAME,
'X-ISCSI-TargetID': 1}
}
self.driver.do_setup(self.context)
self.addCleanup(self.api_patcher.stop)
def test_check_do_setup(self):
self.assertEqual('%s1' % ISCSI_TARGET_NAME, self.driver.target_name)
def test_check_do_setup__vip(self):
first_vip = '/'.join((self.cfg.nexenta_client_address, '32'))
vips = [
[{'ip': first_vip}],
[{'ip': '0.0.0.1/32'}]
]
def my_side_effect(*args, **kwargs):
return {'data': {
'X-ISCSI-TargetName': ISCSI_TARGET_NAME,
'X-ISCSI-TargetID': 1,
'X-VIPS': json.dumps(vips)}
}
self.mock_api.side_effect = my_side_effect
self.driver.do_setup(self.context)
self.assertEqual(self.driver.ha_vip, first_vip.split('/')[0])
def test_check_do_setup__vip_not_in_xvips(self):
first_vip = '1.2.3.4/32'
vips = [
[{'ip': first_vip}],
[{'ip': '0.0.0.1/32'}]
]
def my_side_effect(*args, **kwargs):
return {'data': {
'X-ISCSI-TargetName': ISCSI_TARGET_NAME,
'X-ISCSI-TargetID': 1,
'X-VIPS': json.dumps(vips)}
}
self.mock_api.side_effect = my_side_effect
self.assertRaises(utils.NexentaException,
self.driver.do_setup, self.context)
def check_for_setup_error(self):
self.mock_api.side_effect = exception.VolumeBackendAPIException
self.assertRaises(exception.VolumeBackendAPIException,
self.driver.check_for_setup_error)
@patch('cinder.volume.drivers.nexenta.nexentaedge.iscsi.'
'NexentaEdgeISCSIDriver._get_lu_number')
def test_create_volume(self, lun):
lun.return_value = 1
self.driver.create_volume(MOCK_VOL)
self.mock_api.assert_called_with(NEDGE_URL, {
'objectPath': NEDGE_BUCKET + '/' + MOCK_VOL['id'],
'volSizeMB': MOCK_VOL['size'] * 1024,
'blockSize': NEDGE_BLOCKSIZE,
'chunkSize': NEDGE_CHUNKSIZE,
'optionsObject': {
'ccow-replication-count': 2,
'ccow-encryption-enabled': True,
'ccow-iops-rate-lim': 0}
})
@patch('cinder.volume.drivers.nexenta.nexentaedge.iscsi.'
'NexentaEdgeISCSIDriver._get_lu_number')
def test_create_volume__vip(self, lun):
lun.return_value = 1
self.driver.ha_vip = self.cfg.nexenta_client_address + '/32'
self.driver.create_volume(MOCK_VOL)
self.mock_api.assert_called_with(NEDGE_URL, {
'objectPath': NEDGE_BUCKET + '/' + MOCK_VOL['id'],
'volSizeMB': MOCK_VOL['size'] * 1024,
'blockSize': NEDGE_BLOCKSIZE,
'chunkSize': NEDGE_CHUNKSIZE,
'vip': self.cfg.nexenta_client_address + '/32',
'optionsObject': {
'ccow-replication-count': 2,
'ccow-encryption-enabled': True,
'ccow-iops-rate-lim': 0}
})
def test_create_volume_fail(self):
self.mock_api.side_effect = RuntimeError
self.assertRaises(RuntimeError, self.driver.create_volume, MOCK_VOL)
def test_delete_volume(self):
self.mock_api.side_effect = exception.VolumeBackendAPIException(
'No volume')
self.driver.delete_volume(MOCK_VOL)
self.mock_api.assert_called_with(NEDGE_URL, {
'objectPath': NEDGE_BUCKET + '/' + MOCK_VOL['id']
})
def test_delete_volume_fail(self):
self.mock_api.side_effect = RuntimeError
self.assertRaises(RuntimeError, self.driver.delete_volume, MOCK_VOL)
def test_extend_volume(self):
self.driver.extend_volume(MOCK_VOL, NEW_VOL_SIZE)
self.mock_api.assert_called_with(NEDGE_URL + '/resize', {
'objectPath': NEDGE_BUCKET + '/' + MOCK_VOL['id'],
'newSizeMB': NEW_VOL_SIZE * 1024
})
def test_extend_volume_fail(self):
self.mock_api.side_effect = RuntimeError
self.assertRaises(RuntimeError, self.driver.extend_volume,
MOCK_VOL, NEW_VOL_SIZE)
def test_create_snapshot(self):
self.driver.create_snapshot(MOCK_SNAP)
self.mock_api.assert_called_with(NEDGE_URL + '/snapshot', {
'objectPath': NEDGE_BUCKET + '/' + MOCK_VOL['id'],
'snapName': MOCK_SNAP['id']
})
def test_create_snapshot_fail(self):
self.mock_api.side_effect = RuntimeError
self.assertRaises(RuntimeError, self.driver.create_snapshot, MOCK_SNAP)
def test_delete_snapshot(self):
self.driver.delete_snapshot(MOCK_SNAP)
self.mock_api.assert_called_with(NEDGE_URL + '/snapshot', {
'objectPath': NEDGE_BUCKET + '/' + MOCK_VOL['id'],
'snapName': MOCK_SNAP['id']
})
def test_delete_snapshot_fail(self):
self.mock_api.side_effect = RuntimeError
self.assertRaises(RuntimeError, self.driver.delete_snapshot, MOCK_SNAP)
def test_create_volume_from_snapshot(self):
self.driver.create_volume_from_snapshot(MOCK_VOL2, MOCK_SNAP)
self.mock_api.assert_called_with(NEDGE_URL + '/snapshot/clone', {
'objectPath': NEDGE_BUCKET + '/' + MOCK_SNAP['volume_name'],
'clonePath': NEDGE_BUCKET + '/' + MOCK_VOL2['id'],
'snapName': MOCK_SNAP['id']
})
def test_create_volume_from_snapshot_fail(self):
self.mock_api.side_effect = RuntimeError
self.assertRaises(RuntimeError,
self.driver.create_volume_from_snapshot,
MOCK_VOL2, MOCK_SNAP)
def test_create_cloned_volume(self):
self.driver.create_cloned_volume(MOCK_VOL2, MOCK_VOL)
url = '%s/snapshot/clone' % NEDGE_URL
self.mock_api.assert_called_with(url, {
'objectPath': NEDGE_BUCKET + '/' + MOCK_VOL['id'],
'clonePath': NEDGE_BUCKET + '/' + MOCK_VOL2['id'],
'snapName': 'cinder-clone-snapshot-vol2'
})
def test_create_cloned_volume_larger(self):
self.driver.create_cloned_volume(MOCK_VOL3, MOCK_VOL)
# ignore the clone call, this has been tested before
self.mock_api.assert_called_with(NEDGE_URL + '/resize', {
'objectPath': NEDGE_BUCKET + '/' + MOCK_VOL3['id'],
'newSizeMB': MOCK_VOL3['size'] * 1024
})
def test_create_cloned_volume_fail(self):
self.mock_api.side_effect = RuntimeError
self.assertRaises(RuntimeError, self.driver.create_cloned_volume,
MOCK_VOL2, MOCK_VOL)

View File

@ -1,345 +0,0 @@
# Copyright 2015 Nexenta Systems, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import log as logging
from oslo_utils import excutils
from oslo_utils import units
from cinder import exception
from cinder.i18n import _
from cinder import interface
from cinder.volume import driver
from cinder.volume.drivers.nexenta.nexentaedge import jsonrpc
from cinder.volume.drivers.nexenta import options
from cinder.volume.drivers.nexenta import utils as nexenta_utils
LOG = logging.getLogger(__name__)
@interface.volumedriver
class NexentaEdgeISCSIDriver(driver.ISCSIDriver):
"""Executes volume driver commands on NexentaEdge cluster.
.. code-block:: none
Version history:
1.0.0 - Initial driver version.
1.0.1 - Moved opts to options.py.
1.0.2 - Added HA support.
1.0.3 - Added encryption and replication count support.
1.0.4 - Added initialize_connection.
1.0.5 - Driver re-introduced in OpenStack.
"""
VERSION = '1.0.5'
# ThirdPartySystems wiki page
CI_WIKI_NAME = "Nexenta_Edge_CI"
# TODO(jsbryant) Remove driver in the 'T' release if CI is not fixed
SUPPORTED = False
def __init__(self, *args, **kwargs):
super(NexentaEdgeISCSIDriver, self).__init__(*args, **kwargs)
if self.configuration:
self.configuration.append_config_values(
options.NEXENTA_CONNECTION_OPTS)
self.configuration.append_config_values(
options.NEXENTA_ISCSI_OPTS)
self.configuration.append_config_values(
options.NEXENTA_DATASET_OPTS)
self.configuration.append_config_values(
options.NEXENTA_EDGE_OPTS)
if self.configuration.nexenta_rest_address:
self.restapi_host = self.configuration.nexenta_rest_address
else:
self.restapi_host = self.configuration.san_ip
if self.configuration.nexenta_rest_port:
self.restapi_port = self.configuration.nexenta_rest_port
else:
self.restapi_port = self.configuration.san_api_port
if self.configuration.nexenta_client_address:
self.target_vip = self.configuration.nexenta_client_address
else:
self.target_vip = self.configuration.target_ip_address
if self.configuration.nexenta_rest_password:
self.restapi_password = (
self.configuration.nexenta_rest_password)
else:
self.restapi_password = (
self.configuration.san_password)
if self.configuration.nexenta_rest_user:
self.restapi_user = self.configuration.nexenta_rest_user
else:
self.restapi_user = self.configuration.san_login
self.verify_ssl = self.configuration.driver_ssl_cert_verify
self.restapi_protocol = self.configuration.nexenta_rest_protocol
self.iscsi_service = self.configuration.nexenta_iscsi_service
self.bucket_path = self.configuration.nexenta_lun_container
self.blocksize = self.configuration.nexenta_blocksize
self.chunksize = self.configuration.nexenta_chunksize
self.cluster, self.tenant, self.bucket = self.bucket_path.split('/')
self.repcount = self.configuration.nexenta_replication_count
self.encryption = self.configuration.nexenta_encryption
self.iscsi_target_port = (self.configuration.
nexenta_iscsi_target_portal_port)
self.ha_vip = None
@staticmethod
def get_driver_options():
return (
options.NEXENTA_CONNECTION_OPTS +
options.NEXENTA_ISCSI_OPTS +
options.NEXENTA_DATASET_OPTS +
options.NEXENTA_EDGE_OPTS
)
@property
def backend_name(self):
backend_name = None
if self.configuration:
backend_name = self.configuration.safe_get('volume_backend_name')
if not backend_name:
backend_name = self.__class__.__name__
return backend_name
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 nexenta_utils.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})
def check_for_setup_error(self):
url = 'clusters/%s/tenants/%s/buckets' % (self.cluster, self.tenant)
if self.bucket not in self.restapi.get(url):
raise exception.VolumeBackendAPIException(
message=_('Bucket %s does not exist') % self.bucket)
def _get_lu_number(self, volname):
rsp = self.restapi.get('service/' + self.iscsi_service + '/iscsi')
path = '%s/%s' % (self.bucket_path, volname)
for mapping in rsp['data']:
if mapping['objectPath'] == path:
return mapping['number']
return None
def _get_provider_location(self, volume):
lun = self._get_lu_number(volume['name'])
if not lun:
return None
return '%(host)s:%(port)s,1 %(name)s %(number)s' % {
'host': self.target_vip,
'port': self.iscsi_target_port,
'name': self.target_name,
'number': lun
}
def create_volume(self, volume):
data = {
'objectPath': '%s/%s' % (
self.bucket_path, volume['name']),
'volSizeMB': int(volume['size']) * units.Ki,
'blockSize': self.blocksize,
'chunkSize': self.chunksize,
'optionsObject': {
'ccow-replication-count': self.repcount,
'ccow-iops-rate-lim': self.configuration.nexenta_iops_limit}
}
if self.encryption:
data['optionsObject']['ccow-encryption-enabled'] = True
if self.ha_vip:
data['vip'] = self.ha_vip
try:
self.restapi.post('service/' + self.iscsi_service + '/iscsi', data)
except exception.VolumeBackendAPIException:
with excutils.save_and_reraise_exception():
LOG.exception(
'Error creating LUN for volume %s', volume['name'])
return {'provider_location': self._get_provider_location(volume)}
def delete_volume(self, volume):
data = {
'objectPath': '%s/%s' % (
self.bucket_path, volume['name'])
}
try:
self.restapi.delete(
'service/' + self.iscsi_service + '/iscsi', data)
except exception.VolumeBackendAPIException:
LOG.info(
'Error deleting LUN for volume %s', volume['name'])
def create_export(self, context, volume, connector=None):
pass
def ensure_export(self, context, volume):
pass
def remove_export(self, context, volume):
pass
def initialize_connection(self, volume, connector):
return {
'driver_volume_type': 'iscsi',
'data': {
'target_discovered': False,
'encrypted': False,
'qos_specs': None,
'target_iqn': self.target_name,
'target_portal': '%s:%s' % (
self.target_vip, self.iscsi_target_port),
'volume_id': volume['id'],
'target_lun': self._get_lu_number(volume['name']),
'access_mode': 'rw',
}
}
def extend_volume(self, volume, new_size):
try:
self.restapi.put('service/' + self.iscsi_service + '/iscsi/resize',
{'objectPath': '%s/%s' % (
self.bucket_path, volume['name']),
'newSizeMB': new_size * units.Ki})
except exception.VolumeBackendAPIException:
with excutils.save_and_reraise_exception():
LOG.exception('Error extending volume %s', volume['name'])
def create_volume_from_snapshot(self, volume, snapshot):
try:
self.restapi.put(
'service/' + self.iscsi_service + '/iscsi/snapshot/clone',
{
'objectPath': '%s/%s' % (
self.bucket_path, snapshot['volume_name']),
'clonePath': '%s/%s' % (
self.bucket_path, volume['name']),
'snapName': snapshot['name']
})
except exception.VolumeBackendAPIException:
with excutils.save_and_reraise_exception():
LOG.exception(
'Error creating volume from snapshot %s', snapshot['name'])
if (('size' in volume) and (
volume['size'] > snapshot['volume_size'])):
self.extend_volume(volume, volume['size'])
def create_snapshot(self, snapshot):
try:
self.restapi.post(
'service/' + self.iscsi_service + '/iscsi/snapshot',
{
'objectPath': '%s/%s' % (
self.bucket_path, snapshot['volume_name']),
'snapName': snapshot['name']
})
except exception.VolumeBackendAPIException:
with excutils.save_and_reraise_exception():
LOG.exception('Error creating snapshot %s', snapshot['name'])
def delete_snapshot(self, snapshot):
try:
self.restapi.delete(
'service/' + self.iscsi_service + '/iscsi/snapshot',
{
'objectPath': '%s/%s' % (
self.bucket_path, snapshot['volume_name']),
'snapName': snapshot['name']
})
except exception.VolumeBackendAPIException:
LOG.info('Error deleting snapshot %s', snapshot['name'])
@staticmethod
def _get_clone_snapshot_name(volume):
"""Return name for snapshot that will be used to clone the volume."""
return 'cinder-clone-snapshot-%(id)s' % volume
def create_cloned_volume(self, volume, src_vref):
snapshot = {'volume_name': src_vref['name'],
'volume_id': src_vref['id'],
'volume_size': src_vref['size'],
'name': self._get_clone_snapshot_name(volume)}
LOG.debug('Creating temp snapshot of the original volume: '
'%s@%s', snapshot['volume_name'], snapshot['name'])
self.create_snapshot(snapshot)
try:
self.create_volume_from_snapshot(volume, snapshot)
except nexenta_utils.NexentaException:
LOG.error('Volume creation failed, deleting created snapshot '
'%s', '@'.join([snapshot['volume_name'],
snapshot['name']]))
try:
self.delete_snapshot(snapshot)
except (nexenta_utils.NexentaException, exception.SnapshotIsBusy):
LOG.warning('Failed to delete zfs snapshot '
'%s', '@'.join([snapshot['volume_name'],
snapshot['name']]))
raise
if volume['size'] > src_vref['size']:
self.extend_volume(volume, volume['size'])
def local_path(self, volume):
raise NotImplementedError
def get_volume_stats(self, refresh=False):
resp = self.restapi.get('system/stats')
summary = resp['stats']['summary']
total = nexenta_utils.str2gib_size(summary['total_capacity'])
free = nexenta_utils.str2gib_size(summary['total_available'])
location_info = '%(driver)s:%(host)s:%(bucket)s' % {
'driver': self.__class__.__name__,
'host': self.target_vip,
'bucket': self.bucket_path
}
return {
'vendor_name': 'Nexenta',
'driver_version': self.VERSION,
'storage_protocol': 'iSCSI',
'reserved_percentage': 0,
'total_capacity_gb': total,
'free_capacity_gb': free,
'QoS_support': False,
'volume_backend_name': self.backend_name,
'location_info': location_info,
'iscsi_target_portal_port': self.iscsi_target_port,
'restapi_url': self.restapi.url
}

View File

@ -1,97 +0,0 @@
# Copyright 2015 Nexenta Systems, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import requests
from oslo_log import log as logging
from cinder import exception
from cinder.i18n import _
from cinder.utils import retry
LOG = logging.getLogger(__name__)
TIMEOUT = 60
class NexentaEdgeJSONProxy(object):
retry_exc_tuple = (
requests.exceptions.ConnectionError,
requests.exceptions.ConnectTimeout
)
def __init__(self, protocol, host, port, path, user, password, verify,
auto=False, method=None, session=None):
if session:
self.session = session
else:
self.session = requests.Session()
self.session.auth = (user, password)
self.session.headers.update({'Content-Type': 'application/json'})
self.protocol = protocol.lower()
self.verify = verify
self.host = host
self.port = port
self.path = path
self.user = user
self.password = password
self.auto = auto
self.method = method
@property
def url(self):
return '%s://%s:%s/%s' % (
self.protocol, self.host, self.port, self.path)
def __getattr__(self, name):
if name in ('get', 'post', 'put', 'delete'):
return NexentaEdgeJSONProxy(
self.protocol, self.host, self.port, self.path, self.user,
self.password, self.verify, self.auto, name, self.session)
return super(NexentaEdgeJSONProxy, self).__getattr__(name)
def __hash__(self):
return self.url.__hash__()
def __repr__(self):
return 'HTTP JSON proxy: %s' % self.url
@retry(retry_exc_tuple, interval=1, retries=6)
def __call__(self, *args):
self.path = args[0]
kwargs = {'timeout': TIMEOUT, 'verify': self.verify}
data = None
if len(args) > 1:
data = json.dumps(args[1])
kwargs['data'] = data
LOG.debug('Sending JSON data: %s, method: %s, data: %s',
self.url, self.method, data)
func = getattr(self.session, self.method)
if func:
req = func(self.url, **kwargs)
else:
raise exception.VolumeDriverException(
message=_('Unsupported method: %s') % self.method)
rsp = req.json()
LOG.debug('Got response: %s', rsp)
if rsp.get('response') is None:
raise exception.VolumeBackendAPIException(
data=_('Error response: %s') % rsp)
return rsp.get('response')

View File

@ -1,89 +0,0 @@
===============================
NexentaEdge NBD & iSCSI drivers
===============================
NexentaEdge is designed from the ground-up to deliver high performance Block
and Object storage services and limitless scalability to next generation
OpenStack clouds, petabyte scale active archives and Big Data applications.
NexentaEdge runs on shared nothing clusters of industry standard Linux
servers, and builds on Nexenta IP and patent pending Cloud Copy On Write (CCOW)
technology to break new ground in terms of reliability, functionality and cost
efficiency.
For NexentaEdge user documentation, visit https://nexentaedge.github.io.
iSCSI driver
~~~~~~~~~~~~
The NexentaEdge cluster must be installed and configured according to the
relevant Nexenta documentation. A cluster, tenant, bucket must be pre-created,
as well as an iSCSI service on the NexentaEdge gateway node.
The NexentaEdge iSCSI driver is selected using the normal procedures for one
or multiple back-end volume drivers.
You must configure these items for each NexentaEdge cluster that the iSCSI
volume driver controls:
#. Make the following changes on the volume node ``/etc/cinder/cinder.conf``
file.
.. code-block:: ini
# Enable Nexenta iSCSI driver
volume_driver = cinder.volume.drivers.nexenta.nexentaedge.iscsi.NexentaEdgeISCSIDriver
# Specify the ip address for Rest API (string value)
nexenta_rest_address = MANAGEMENT-NODE-IP
# Port for Rest API (integer value)
nexenta_rest_port=8080
# Protocol used for Rest calls (string value, default=htpp)
nexenta_rest_protocol = http
# Username for NexentaEdge Rest (string value)
nexenta_rest_user=USERNAME
# Password for NexentaEdge Rest (string value)
nexenta_rest_password=PASSWORD
# Path to bucket containing iSCSI LUNs (string value)
nexenta_lun_container = CLUSTER/TENANT/BUCKET
# Name of pre-created iSCSI service (string value)
nexenta_iscsi_service = SERVICE-NAME
# IP address of the gateway node attached to iSCSI service above or
# virtual IP address if an iSCSI Storage Service Group is configured in
# HA mode (string value)
nexenta_client_address = GATEWAY-NODE-IP
#. Save the changes to the ``/etc/cinder/cinder.conf`` file and
restart the ``cinder-volume`` service.
Supported operations
--------------------
* Create, delete, attach, and detach volumes.
* Create, list, and delete volume snapshots.
* Create a volume from a snapshot.
* Copy an image to a volume.
* Copy a volume to an image.
* Clone a volume.
* Extend a volume.
Driver options
~~~~~~~~~~~~~~
Nexenta Driver supports these options:
.. include:: ../../tables/cinder-nexenta_edge.inc

View File

@ -1,46 +0,0 @@
..
Warning: Do not edit this file. It is automatically generated from the
software project's code and your changes will be overwritten.
The tool to generate this file lives in openstack-doc-tools repository.
Please make any changes needed in the code, then run the
autogenerate-config-doc tool from the openstack-doc-tools repository, or
ask for help on the documentation mailing list, IRC channel or meeting.
.. _cinder-nexenta_edge:
.. list-table:: Description of NexentaEdge driver configuration options
:header-rows: 1
:class: config-ref-table
* - Configuration option = Default value
- Description
* - **[DEFAULT]**
-
* - ``nexenta_blocksize`` = ``4096``
- (Integer) Block size for datasets
* - ``nexenta_chunksize`` = ``32768``
- (Integer) NexentaEdge iSCSI LUN object chunk size
* - ``nexenta_client_address`` =
- (String) NexentaEdge iSCSI Gateway client address for non-VIP service
* - ``nexenta_iscsi_service`` =
- (String) NexentaEdge iSCSI service name
* - ``nexenta_iscsi_target_portal_port`` = ``3260``
- (Integer) Nexenta target portal port
* - ``nexenta_lun_container`` =
- (String) NexentaEdge logical path of bucket for LUNs
* - ``nexenta_rest_address`` =
- (String) IP address of NexentaEdge management REST API endpoint
* - ``nexenta_rest_password`` = ``nexenta``
- (String) Password to connect to NexentaEdge
* - ``nexenta_rest_port`` = ``8080``
- (Integer) HTTP port to connect to Nexenta REST API server
* - ``nexenta_rest_protocol`` = ``auto``
- (String) Use http or https for REST connection (default auto)
* - ``nexenta_rest_user`` = ``admin``
- (String) User name to connect to NexentaEdge
* - ``nexenta_replication_count`` = ``3``
- (String) NexentaEdge iSCSI LUN object replication count.
* - ``nexenta_encryption`` = ``False``
- (String) NexentaEdge iSCSI LUN object encryption

View File

@ -82,3 +82,4 @@ release.
* Train
* Tintri Storage Driver
* Veritas HyperScale Storage Driver
* Nexenta Edge Storage Driver

View File

@ -0,0 +1,15 @@
---
upgrade:
- |
The Nexenta Edge storage driver has been removed after completion of its
deprecation period without a reliable 3rd Party CI system being
supported. Customers using the Nexenta Edge driver should not upgrade
Cinder without first migrating all volumes from their Nexenta backend
to a supported storage backend. Failure to migrate volumes will
result in no longer being able to access volumes back by the Nexenta Edge
storage backend.
other:
- |
The Nexenta Edge storage driver was marked unsupported in Stein due to
3rd Party CI not meeting Cinder's requirements. As a result the
driver is removed starting from the Train release.