LeftHand: Implement v2 replication (unmanaged)
This patch implements the unmanaged side of v2 replication in the HPE LeftHand driver. With unmanaged replication, the original driver instance will handle all provisioning requests even after a failover. cinder.conf should have the replication config group: [lefthandrep] hpelefthand_api_url = https://10.10.10.10:8081/lhos hpelefthand_username = user hpelefthand_password = pass hpelefthand_clustername = vsa-12-5-mgmt1-vip volume_backend_name = lefthandrep volume_driver = cinder.volume.drivers.hpe.hpe_lefthand_iscsi.\ HPELeftHandISCSIDriver replication_device = target_device_id:lh-id, hpelefthand_api_url:https://11.11.11.11:8081/lhos, hpelefthand_username:user2, hpelefthand_password:pass2, hpelefthand_clustername:vsa-12-5-mgmt2-vip Change-Id: I3c489e986648eee16b3bf5a19799a4ea0c0240b0 Implements: blueprint hp-lefthand-v2-replication DocImpact
This commit is contained in:
parent
e1349f8b61
commit
aba098e575
@ -88,6 +88,17 @@ class HPELeftHandBaseDriver(object):
|
||||
'cluster_id': 6,
|
||||
'cluster_vip': '10.0.1.6'}]
|
||||
|
||||
repl_targets_unmgd = [{'target_device_id': 'target',
|
||||
'hpelefthand_api_url': HPELEFTHAND_API_URL2,
|
||||
'hpelefthand_username': HPELEFTHAND_USERNAME,
|
||||
'hpelefthand_password': HPELEFTHAND_PASSWORD,
|
||||
'hpelefthand_clustername': HPELEFTHAND_CLUSTER_NAME,
|
||||
'hpelefthand_ssh_port': HPELEFTHAND_SSH_PORT,
|
||||
'ssh_conn_timeout': HPELEFTHAND_SAN_SSH_CON_TIMEOUT,
|
||||
'san_private_key': HPELEFTHAND_SAN_SSH_PRIVATE,
|
||||
'cluster_id': 6,
|
||||
'cluster_vip': '10.0.1.6'}]
|
||||
|
||||
list_rep_targets = [{'target_device_id': 'target'}]
|
||||
|
||||
serverName = 'fakehost'
|
||||
@ -98,7 +109,8 @@ class HPELeftHandBaseDriver(object):
|
||||
snapshot_id = 3
|
||||
snapshot = {
|
||||
'name': snapshot_name,
|
||||
'volume_name': volume_name}
|
||||
'volume_name': volume_name,
|
||||
'volume': volume}
|
||||
|
||||
cloned_volume_name = "clone_volume"
|
||||
cloned_volume = {'name': cloned_volume_name}
|
||||
@ -1921,6 +1933,67 @@ class TestHPELeftHandISCSIDriver(HPELeftHandBaseDriver, test.TestCase):
|
||||
'provider_location': prov_location},
|
||||
return_model)
|
||||
|
||||
@mock.patch('hpelefthandclient.version', "2.0.1")
|
||||
@mock.patch.object(volume_types, 'get_volume_type')
|
||||
def test_create_volume_replicated_unmanaged(self, _mock_get_volume_type):
|
||||
# set up driver with default config
|
||||
conf = self.default_mock_conf()
|
||||
conf.replication_device = self.repl_targets_unmgd
|
||||
mock_client = self.setup_driver(config=conf)
|
||||
mock_client.createVolume.return_value = {
|
||||
'iscsiIqn': self.connector['initiator']}
|
||||
mock_client.doesRemoteSnapshotScheduleExist.return_value = False
|
||||
mock_replicated_client = self.setup_driver(config=conf)
|
||||
|
||||
_mock_get_volume_type.return_value = {
|
||||
'name': 'replicated',
|
||||
'extra_specs': {
|
||||
'replication_enabled': '<is> True'}}
|
||||
|
||||
with mock.patch.object(
|
||||
hpe_lefthand_iscsi.HPELeftHandISCSIDriver,
|
||||
'_create_client') as mock_do_setup, \
|
||||
mock.patch.object(
|
||||
hpe_lefthand_iscsi.HPELeftHandISCSIDriver,
|
||||
'_create_replication_client') as mock_replication_client:
|
||||
mock_do_setup.return_value = mock_client
|
||||
mock_replication_client.return_value = mock_replicated_client
|
||||
return_model = self.driver.create_volume(self.volume_replicated)
|
||||
|
||||
expected = [
|
||||
mock.call.createVolume(
|
||||
'fakevolume_replicated',
|
||||
1,
|
||||
units.Gi,
|
||||
{'isThinProvisioned': True,
|
||||
'clusterName': 'CloudCluster1'}),
|
||||
mock.call.doesRemoteSnapshotScheduleExist(
|
||||
'fakevolume_replicated_SCHED_Pri'),
|
||||
mock.call.createRemoteSnapshotSchedule(
|
||||
'fakevolume_replicated',
|
||||
'fakevolume_replicated_SCHED',
|
||||
1800,
|
||||
'1970-01-01T00:00:00Z',
|
||||
5,
|
||||
'CloudCluster1',
|
||||
5,
|
||||
'fakevolume_replicated',
|
||||
'1.1.1.1',
|
||||
'foo1',
|
||||
'bar2'),
|
||||
mock.call.logout()]
|
||||
|
||||
mock_client.assert_has_calls(
|
||||
self.driver_startup_call_stack +
|
||||
self.driver_startup_ssh +
|
||||
expected)
|
||||
prov_location = '10.0.1.6:3260,1 iqn.1993-08.org.debian:01:222 0'
|
||||
rep_data = json.dumps({"location": HPELEFTHAND_API_URL})
|
||||
self.assertEqual({'replication_status': 'enabled',
|
||||
'replication_driver_data': rep_data,
|
||||
'provider_location': prov_location},
|
||||
return_model)
|
||||
|
||||
@mock.patch('hpelefthandclient.version', "2.0.1")
|
||||
@mock.patch.object(volume_types, 'get_volume_type')
|
||||
def test_delete_volume_replicated(self, _mock_get_volume_type):
|
||||
@ -2203,3 +2276,50 @@ class TestHPELeftHandISCSIDriver(HPELeftHandBaseDriver, test.TestCase):
|
||||
'replication_driver_data': rep_data,
|
||||
'host': FAKE_FAILOVER_HOST},
|
||||
return_model)
|
||||
|
||||
@mock.patch('hpelefthandclient.version', "2.0.1")
|
||||
@mock.patch.object(volume_types, 'get_volume_type')
|
||||
def test_replication_failover_unmanaged(self, _mock_get_volume_type):
|
||||
ctxt = context.get_admin_context()
|
||||
# set up driver with default config
|
||||
conf = self.default_mock_conf()
|
||||
conf.replication_device = self.repl_targets_unmgd
|
||||
mock_client = self.setup_driver(config=conf)
|
||||
mock_replicated_client = self.setup_driver(config=conf)
|
||||
mock_replicated_client.getVolumeByName.return_value = {
|
||||
'iscsiIqn': self.connector['initiator']}
|
||||
|
||||
_mock_get_volume_type.return_value = {
|
||||
'name': 'replicated',
|
||||
'extra_specs': {
|
||||
'replication_enabled': '<is> True'}}
|
||||
|
||||
with mock.patch.object(
|
||||
hpe_lefthand_iscsi.HPELeftHandISCSIDriver,
|
||||
'_create_client') as mock_do_setup, \
|
||||
mock.patch.object(
|
||||
hpe_lefthand_iscsi.HPELeftHandISCSIDriver,
|
||||
'_create_replication_client') as mock_replication_client:
|
||||
mock_do_setup.return_value = mock_client
|
||||
mock_replication_client.return_value = mock_replicated_client
|
||||
valid_target_device_id = (self.repl_targets[0]['target_device_id'])
|
||||
invalid_target_device_id = 'INVALID'
|
||||
|
||||
# test invalid secondary target
|
||||
self.assertRaises(
|
||||
exception.VolumeBackendAPIException,
|
||||
self.driver.replication_failover,
|
||||
ctxt,
|
||||
self.volume_replicated,
|
||||
invalid_target_device_id)
|
||||
|
||||
# test a successful failover
|
||||
return_model = self.driver.replication_failover(
|
||||
context.get_admin_context(),
|
||||
self.volume_replicated,
|
||||
valid_target_device_id)
|
||||
rep_data = json.dumps({"location": HPELEFTHAND_API_URL2})
|
||||
prov_location = '10.0.1.6:3260,1 iqn.1993-08.org.debian:01:222 0'
|
||||
self.assertEqual({'provider_location': prov_location,
|
||||
'replication_driver_data': rep_data},
|
||||
return_model)
|
||||
|
@ -147,9 +147,10 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
2.0.0 - Rebranded HP to HPE
|
||||
2.0.1 - Remove db access for consistency groups
|
||||
2.0.2 - Adds v2 managed replication support
|
||||
2.0.3 - Adds v2 unmanaged replication support
|
||||
"""
|
||||
|
||||
VERSION = "2.0.2"
|
||||
VERSION = "2.0.3"
|
||||
|
||||
device_stats = {}
|
||||
|
||||
@ -176,21 +177,56 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
# blank is the only invalid character for cluster names
|
||||
# so we need to use it as a separator
|
||||
self.DRIVER_LOCATION = self.__class__.__name__ + ' %(cluster)s %(vip)s'
|
||||
self._client_conf = {}
|
||||
self._replication_targets = []
|
||||
self._replication_enabled = False
|
||||
|
||||
def _login(self, timeout=None):
|
||||
def _login(self, volume=None, timeout=None):
|
||||
conf = self._get_lefthand_config(volume)
|
||||
if conf:
|
||||
self._client_conf['hpelefthand_username'] = (
|
||||
conf['hpelefthand_username'])
|
||||
self._client_conf['hpelefthand_password'] = (
|
||||
conf['hpelefthand_password'])
|
||||
self._client_conf['hpelefthand_clustername'] = (
|
||||
conf['hpelefthand_clustername'])
|
||||
self._client_conf['hpelefthand_api_url'] = (
|
||||
conf['hpelefthand_api_url'])
|
||||
self._client_conf['hpelefthand_ssh_port'] = (
|
||||
conf['hpelefthand_ssh_port'])
|
||||
self._client_conf['hpelefthand_iscsi_chap_enabled'] = (
|
||||
conf['hpelefthand_iscsi_chap_enabled'])
|
||||
self._client_conf['ssh_conn_timeout'] = conf['ssh_conn_timeout']
|
||||
self._client_conf['san_private_key'] = conf['san_private_key']
|
||||
else:
|
||||
self._client_conf['hpelefthand_username'] = (
|
||||
self.configuration.hpelefthand_username)
|
||||
self._client_conf['hpelefthand_password'] = (
|
||||
self.configuration.hpelefthand_password)
|
||||
self._client_conf['hpelefthand_clustername'] = (
|
||||
self.configuration.hpelefthand_clustername)
|
||||
self._client_conf['hpelefthand_api_url'] = (
|
||||
self.configuration.hpelefthand_api_url)
|
||||
self._client_conf['hpelefthand_ssh_port'] = (
|
||||
self.configuration.hpelefthand_ssh_port)
|
||||
self._client_conf['hpelefthand_iscsi_chap_enabled'] = (
|
||||
self.configuration.hpelefthand_iscsi_chap_enabled)
|
||||
self._client_conf['ssh_conn_timeout'] = (
|
||||
self.configuration.ssh_conn_timeout)
|
||||
self._client_conf['san_private_key'] = (
|
||||
self.configuration.san_private_key)
|
||||
|
||||
client = self._create_client(timeout=timeout)
|
||||
try:
|
||||
if self.configuration.hpelefthand_debug:
|
||||
client.debug_rest(True)
|
||||
|
||||
client.login(
|
||||
self.configuration.hpelefthand_username,
|
||||
self.configuration.hpelefthand_password)
|
||||
self._client_conf['hpelefthand_username'],
|
||||
self._client_conf['hpelefthand_password'])
|
||||
|
||||
cluster_info = client.getClusterByName(
|
||||
self.configuration.hpelefthand_clustername)
|
||||
self._client_conf['hpelefthand_clustername'])
|
||||
self.cluster_id = cluster_info['id']
|
||||
virtual_ips = cluster_info['virtualIPAddresses']
|
||||
self.cluster_vip = virtual_ips[0]['ipV4Address']
|
||||
@ -200,18 +236,18 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
if hpelefthandclient.version >= MIN_REP_CLIENT_VERSION:
|
||||
# Extract IP address from API URL
|
||||
ssh_ip = self._extract_ip_from_url(
|
||||
self.configuration.hpelefthand_api_url)
|
||||
self._client_conf['hpelefthand_api_url'])
|
||||
known_hosts_file = CONF.ssh_hosts_key_file
|
||||
policy = "AutoAddPolicy"
|
||||
if CONF.strict_ssh_host_key_policy:
|
||||
policy = "RejectPolicy"
|
||||
client.setSSHOptions(
|
||||
ssh_ip,
|
||||
self.configuration.hpelefthand_username,
|
||||
self.configuration.hpelefthand_password,
|
||||
port=self.configuration.hpelefthand_ssh_port,
|
||||
conn_timeout=self.configuration.ssh_conn_timeout,
|
||||
privatekey=self.configuration.san_private_key,
|
||||
self._client_conf['hpelefthand_username'],
|
||||
self._client_conf['hpelefthand_password'],
|
||||
port=self._client_conf['hpelefthand_ssh_port'],
|
||||
conn_timeout=self._client_conf['ssh_conn_timeout'],
|
||||
privatekey=self._client_conf['san_private_key'],
|
||||
missing_key_policy=policy,
|
||||
known_hosts_file=known_hosts_file)
|
||||
|
||||
@ -229,12 +265,12 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
def _create_client(self, timeout=None):
|
||||
# Timeout is only supported in version 2.0.1 and greater of the
|
||||
# python-lefthandclient.
|
||||
hpelefthand_api_url = self._client_conf['hpelefthand_api_url']
|
||||
if hpelefthandclient.version >= MIN_REP_CLIENT_VERSION:
|
||||
client = hpe_lh_client.HPELeftHandClient(
|
||||
self.configuration.hpelefthand_api_url, timeout=timeout)
|
||||
hpelefthand_api_url, timeout=timeout)
|
||||
else:
|
||||
client = hpe_lh_client.HPELeftHandClient(
|
||||
self.configuration.hpelefthand_api_url)
|
||||
client = hpe_lh_client.HPELeftHandClient(hpelefthand_api_url)
|
||||
return client
|
||||
|
||||
def _create_replication_client(self, remote_array):
|
||||
@ -312,6 +348,14 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
finally:
|
||||
self._logout(client)
|
||||
|
||||
def check_replication_flags(self, options, required_flags):
|
||||
for flag in required_flags:
|
||||
if not options.get(flag, None):
|
||||
msg = _('%s is not set and is required for the replicaiton '
|
||||
'device to be valid.') % flag
|
||||
LOG.error(msg)
|
||||
raise exception.InvalidInput(reason=msg)
|
||||
|
||||
def get_version_string(self):
|
||||
return (_('REST %(proxy_ver)s hpelefthandclient %(rest_ver)s') % {
|
||||
'proxy_ver': self.VERSION,
|
||||
@ -319,7 +363,7 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
|
||||
def create_volume(self, volume):
|
||||
"""Creates a volume."""
|
||||
client = self._login()
|
||||
client = self._login(volume)
|
||||
try:
|
||||
# get the extra specs of interest from this volume's volume type
|
||||
volume_extra_specs = self._get_volume_extra_specs(volume)
|
||||
@ -344,7 +388,7 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
if optional.get('isAdaptiveOptimizationEnabled'):
|
||||
del optional['isAdaptiveOptimizationEnabled']
|
||||
|
||||
clusterName = self.configuration.hpelefthand_clustername
|
||||
clusterName = self._client_conf['hpelefthand_clustername']
|
||||
optional['clusterName'] = clusterName
|
||||
|
||||
volume_info = client.createVolume(
|
||||
@ -359,7 +403,7 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
self._do_volume_replication_setup(volume, client, optional)):
|
||||
model_update['replication_status'] = 'enabled'
|
||||
model_update['replication_driver_data'] = (json.dumps(
|
||||
{'location': self.configuration.hpelefthand_api_url}))
|
||||
{'location': self._client_conf['hpelefthand_api_url']}))
|
||||
|
||||
return model_update
|
||||
except Exception as ex:
|
||||
@ -369,7 +413,7 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
|
||||
def delete_volume(self, volume):
|
||||
"""Deletes a volume."""
|
||||
client = self._login()
|
||||
client = self._login(volume)
|
||||
# v2 replication check
|
||||
# If the volume type is replication enabled, we want to call our own
|
||||
# method of deconstructing the volume and its dependencies
|
||||
@ -389,7 +433,7 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
|
||||
def extend_volume(self, volume, new_size):
|
||||
"""Extend the size of an existing volume."""
|
||||
client = self._login()
|
||||
client = self._login(volume)
|
||||
try:
|
||||
volume_info = client.getVolumeByName(volume['name'])
|
||||
|
||||
@ -538,7 +582,7 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
|
||||
def create_snapshot(self, snapshot):
|
||||
"""Creates a snapshot."""
|
||||
client = self._login()
|
||||
client = self._login(snapshot['volume'])
|
||||
try:
|
||||
volume_info = client.getVolumeByName(snapshot['volume_name'])
|
||||
|
||||
@ -553,7 +597,7 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
|
||||
def delete_snapshot(self, snapshot):
|
||||
"""Deletes a snapshot."""
|
||||
client = self._login()
|
||||
client = self._login(snapshot['volume'])
|
||||
try:
|
||||
snap_info = client.getSnapshotByName(snapshot['name'])
|
||||
client.deleteSnapshot(snap_info['id'])
|
||||
@ -592,7 +636,7 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
data['storage_protocol'] = 'iSCSI'
|
||||
data['vendor_name'] = 'Hewlett Packard Enterprise'
|
||||
data['location_info'] = (self.DRIVER_LOCATION % {
|
||||
'cluster': self.configuration.hpelefthand_clustername,
|
||||
'cluster': self._client_conf['hpelefthand_clustername'],
|
||||
'vip': self.cluster_vip})
|
||||
data['thin_provisioning_support'] = True
|
||||
data['thick_provisioning_support'] = True
|
||||
@ -618,7 +662,7 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
total_volumes = 0
|
||||
provisioned_size = 0
|
||||
volumes = client.getVolumes(
|
||||
cluster=self.configuration.hpelefthand_clustername,
|
||||
cluster=self._client_conf['hpelefthand_clustername'],
|
||||
fields=['members[id]', 'members[clusterName]', 'members[size]'])
|
||||
if volumes:
|
||||
total_volumes = volumes['total']
|
||||
@ -645,7 +689,7 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
used from that host. HPE VSA requires a volume to be assigned
|
||||
to a server.
|
||||
"""
|
||||
client = self._login()
|
||||
client = self._login(volume)
|
||||
try:
|
||||
server_info = self._create_server(connector, client)
|
||||
volume_info = client.getVolumeByName(volume['name'])
|
||||
@ -682,7 +726,7 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
|
||||
def terminate_connection(self, volume, connector, **kwargs):
|
||||
"""Unassign the volume from the host."""
|
||||
client = self._login()
|
||||
client = self._login(volume)
|
||||
try:
|
||||
volume_info = client.getVolumeByName(volume['name'])
|
||||
server_info = client.getServerByName(connector['host'])
|
||||
@ -707,7 +751,7 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
|
||||
def create_volume_from_snapshot(self, volume, snapshot):
|
||||
"""Creates a volume from a snapshot."""
|
||||
client = self._login()
|
||||
client = self._login(volume)
|
||||
try:
|
||||
snap_info = client.getSnapshotByName(snapshot['name'])
|
||||
volume_info = client.cloneSnapshot(
|
||||
@ -721,7 +765,7 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
self._do_volume_replication_setup(volume, client)):
|
||||
model_update['replication_status'] = 'enabled'
|
||||
model_update['replication_driver_data'] = (json.dumps(
|
||||
{'location': self.configuration.hpelefthand_api_url}))
|
||||
{'location': self._client_conf['hpelefthand_api_url']}))
|
||||
|
||||
return model_update
|
||||
except Exception as ex:
|
||||
@ -730,7 +774,7 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
self._logout(client)
|
||||
|
||||
def create_cloned_volume(self, volume, src_vref):
|
||||
client = self._login()
|
||||
client = self._login(volume)
|
||||
try:
|
||||
volume_info = client.getVolumeByName(src_vref['name'])
|
||||
clone_info = client.cloneVolume(volume['name'], volume_info['id'])
|
||||
@ -742,7 +786,7 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
self._do_volume_replication_setup(volume, client)):
|
||||
model_update['replication_status'] = 'enabled'
|
||||
model_update['replication_driver_data'] = (json.dumps(
|
||||
{'location': self.configuration.hpelefthand_api_url}))
|
||||
{'location': self._client_conf['hpelefthand_api_url']}))
|
||||
|
||||
return model_update
|
||||
except Exception as ex:
|
||||
@ -802,7 +846,7 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
|
||||
def _create_server(self, connector, client):
|
||||
server_info = None
|
||||
chap_enabled = self.configuration.hpelefthand_iscsi_chap_enabled
|
||||
chap_enabled = self._client_conf['hpelefthand_iscsi_chap_enabled']
|
||||
try:
|
||||
server_info = client.getServerByName(connector['host'])
|
||||
chap_secret = server_info['chapTargetSecret']
|
||||
@ -857,7 +901,7 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
'new_type': new_type,
|
||||
'diff': diff,
|
||||
'host': host})
|
||||
client = self._login()
|
||||
client = self._login(volume)
|
||||
try:
|
||||
volume_info = client.getVolumeByName(volume['name'])
|
||||
|
||||
@ -911,19 +955,18 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
host['host'] is its name, and host['capabilities'] is a
|
||||
dictionary of its reported capabilities.
|
||||
"""
|
||||
LOG.debug('enter: migrate_volume: id=%(id)s, host=%(host)s, '
|
||||
'cluster=%(cluster)s', {
|
||||
'id': volume['id'],
|
||||
'host': host,
|
||||
'cluster': self.configuration.hpelefthand_clustername})
|
||||
|
||||
false_ret = (False, None)
|
||||
if 'location_info' not in host['capabilities']:
|
||||
return false_ret
|
||||
|
||||
host_location = host['capabilities']['location_info']
|
||||
(driver, cluster, vip) = host_location.split(' ')
|
||||
client = self._login()
|
||||
client = self._login(volume)
|
||||
LOG.debug('enter: migrate_volume: id=%(id)s, host=%(host)s, '
|
||||
'cluster=%(cluster)s', {
|
||||
'id': volume['id'],
|
||||
'host': host,
|
||||
'cluster': self._client_conf['hpelefthand_clustername']})
|
||||
try:
|
||||
# get the cluster info, if it exists and compare
|
||||
cluster_info = client.getClusterByName(cluster)
|
||||
@ -1003,7 +1046,7 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
# volume isn't attached and can be updated
|
||||
original_name = CONF.volume_name_template % volume['id']
|
||||
current_name = CONF.volume_name_template % new_volume['id']
|
||||
client = self._login()
|
||||
client = self._login(volume)
|
||||
try:
|
||||
volume_info = client.getVolumeByName(current_name)
|
||||
volumeMods = {'name': original_name}
|
||||
@ -1038,7 +1081,7 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
target_vol_name = self._get_existing_volume_ref_name(existing_ref)
|
||||
|
||||
# Check for the existence of the virtual volume.
|
||||
client = self._login()
|
||||
client = self._login(volume)
|
||||
try:
|
||||
volume_info = client.getVolumeByName(target_vol_name)
|
||||
except hpeexceptions.HTTPNotFound:
|
||||
@ -1136,7 +1179,7 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
reason=reason)
|
||||
|
||||
# Check for the existence of the virtual volume.
|
||||
client = self._login()
|
||||
client = self._login(volume)
|
||||
try:
|
||||
volume_info = client.getVolumeByName(target_vol_name)
|
||||
except hpeexceptions.HTTPNotFound:
|
||||
@ -1156,7 +1199,7 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
|
||||
# Rename the volume's name to unm-* format so that it can be
|
||||
# easily found later.
|
||||
client = self._login()
|
||||
client = self._login(volume)
|
||||
try:
|
||||
volume_info = client.getVolumeByName(volume['name'])
|
||||
new_vol_name = 'unm-' + six.text_type(volume['id'])
|
||||
@ -1218,7 +1261,7 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
LOG.error(msg)
|
||||
model_update['replication_status'] = "error"
|
||||
else:
|
||||
client = self._login()
|
||||
client = self._login(volume)
|
||||
try:
|
||||
if self._do_volume_replication_setup(volume, client):
|
||||
model_update['replication_status'] = "enabled"
|
||||
@ -1238,7 +1281,7 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
model_update['replication_status'] = 'disabled'
|
||||
vol_name = volume['name']
|
||||
|
||||
client = self._login()
|
||||
client = self._login(volume)
|
||||
try:
|
||||
name = vol_name + self.REP_SCHEDULE_SUFFIX + "_Pri"
|
||||
client.stopRemoteSnapshotSchedule(name)
|
||||
@ -1354,32 +1397,19 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
# as a failover can still occur, so we need out replication
|
||||
# devices to exist.
|
||||
for dev in replication_devices:
|
||||
remote_array = {}
|
||||
is_managed = dev.get('managed_backend_name')
|
||||
if not is_managed:
|
||||
msg = _("Unmanaged replication is not supported at this "
|
||||
"time. Please configure cinder.conf for managed "
|
||||
"replication.")
|
||||
LOG.error(msg)
|
||||
raise exception.VolumeBackendAPIException(data=msg)
|
||||
|
||||
remote_array['managed_backend_name'] = is_managed
|
||||
remote_array['target_device_id'] = (
|
||||
dev.get('target_device_id'))
|
||||
remote_array['hpelefthand_api_url'] = (
|
||||
dev.get('hpelefthand_api_url'))
|
||||
remote_array['hpelefthand_username'] = (
|
||||
dev.get('hpelefthand_username'))
|
||||
remote_array['hpelefthand_password'] = (
|
||||
dev.get('hpelefthand_password'))
|
||||
remote_array['hpelefthand_clustername'] = (
|
||||
dev.get('hpelefthand_clustername'))
|
||||
remote_array = dict(dev.items())
|
||||
# Override and set defaults for certain entries
|
||||
remote_array['managed_backend_name'] = (
|
||||
dev.get('managed_backend_name'))
|
||||
remote_array['hpelefthand_ssh_port'] = (
|
||||
dev.get('hpelefthand_ssh_port', default_san_ssh_port))
|
||||
remote_array['ssh_conn_timeout'] = (
|
||||
dev.get('ssh_conn_timeout', default_ssh_conn_timeout))
|
||||
remote_array['san_private_key'] = (
|
||||
dev.get('san_private_key', default_san_private_key))
|
||||
# Format hpe3par_iscsi_chap_enabled as a bool
|
||||
remote_array['hpelefthand_iscsi_chap_enabled'] = (
|
||||
dev.get('hpelefthand_iscsi_chap_enabled') == 'True')
|
||||
remote_array['cluster_id'] = None
|
||||
remote_array['cluster_vip'] = None
|
||||
array_name = remote_array['target_device_id']
|
||||
@ -1432,10 +1462,14 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
self._replication_enabled = True
|
||||
|
||||
def _is_valid_replication_array(self, target):
|
||||
for k, v in target.items():
|
||||
if v is None:
|
||||
return False
|
||||
return True
|
||||
required_flags = ['hpelefthand_api_url', 'hpelefthand_username',
|
||||
'hpelefthand_password', 'target_device_id',
|
||||
'hpelefthand_clustername']
|
||||
try:
|
||||
self.check_replication_flags(target, required_flags)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def _is_replication_configured_correct(self):
|
||||
rep_flag = True
|
||||
@ -1466,6 +1500,22 @@ class HPELeftHandISCSIDriver(driver.ISCSIDriver):
|
||||
exists = False
|
||||
return exists
|
||||
|
||||
def _get_lefthand_config(self, volume):
|
||||
conf = None
|
||||
if volume:
|
||||
rep_location = None
|
||||
rep_data = volume.get('replication_driver_data')
|
||||
if rep_data:
|
||||
rep_data = json.loads(rep_data)
|
||||
rep_location = rep_data.get('location')
|
||||
if rep_location:
|
||||
for target in self._replication_targets:
|
||||
if target['hpelefthand_api_url'] == rep_location:
|
||||
conf = target
|
||||
break
|
||||
|
||||
return conf
|
||||
|
||||
def _do_volume_replication_setup(self, volume, client, optional=None):
|
||||
"""This function will do or ensure the following:
|
||||
|
||||
|
@ -0,0 +1,3 @@
|
||||
---
|
||||
features:
|
||||
- Added unmanaged v2 replication support to the HPE LeftHand driver.
|
Loading…
Reference in New Issue
Block a user