Huawei: Support huawei consistency group
Adding support for consistency groups in huawei driver. supports the following interfaces: 1.create_consistencygroup 2.delete_consistencygroup 3.update_consistencygroup 4.create_cgsnapshot 5.delete_cgsnapshot DocImpact Implements: blueprint support-huawei-consistency-group Change-Id: Ib35c382d1cc008f483a60da557781435dde098e1
This commit is contained in:
parent
af0cddbaea
commit
d32d9966b6
@ -22,6 +22,7 @@ import tempfile
|
||||
import time
|
||||
from xml.dom import minidom
|
||||
|
||||
from cinder import context
|
||||
from cinder import exception
|
||||
from cinder import test
|
||||
from cinder.tests.unit import utils
|
||||
@ -35,6 +36,7 @@ from cinder.volume.drivers.huawei import hypermetro
|
||||
from cinder.volume.drivers.huawei import replication
|
||||
from cinder.volume.drivers.huawei import rest_client
|
||||
from cinder.volume.drivers.huawei import smartx
|
||||
from cinder.volume import volume_types
|
||||
|
||||
|
||||
hypermetro_devices = """{
|
||||
@ -109,6 +111,9 @@ async_replica_specs = {'replication_enabled': '<is> True',
|
||||
'replication_type': '<in> async'}
|
||||
|
||||
TEST_PAIR_ID = "3400a30d844d0004"
|
||||
replica_hypermetro_specs = {'hypermetro': '<is> True',
|
||||
'replication_enabled': '<is> True'}
|
||||
|
||||
replication_volume = {
|
||||
'name': 'volume-21ec7341-9256-497b-97d9-ef48edcf0635',
|
||||
'size': 2,
|
||||
@ -141,10 +146,16 @@ test_snap = {
|
||||
'volume_type_id': None,
|
||||
'provider_location': '11',
|
||||
'volume': {'provider_location': '12',
|
||||
'id': '21ec7341-9256-497b-97d9-ef48edcf0635',
|
||||
'admin_metadata': {
|
||||
'huawei_lun_wwn': '6643e8c1004c5f6723e9f454003'}},
|
||||
}
|
||||
|
||||
test_cgsnapshot = {'id': '21ec7341-9256-497b-97d9-ef48edcf0635',
|
||||
'consistencygroup_id': '21ec7341-9256-497b-'
|
||||
'97d9-ef48edcf0635',
|
||||
'status': 'available'}
|
||||
|
||||
test_host = {'host': 'ubuntu001@backend001#OpenStack_Pool',
|
||||
'capabilities': {'smartcache': True,
|
||||
'location_info': '210235G7J20000000000',
|
||||
@ -205,6 +216,21 @@ test_new_replication_type = {
|
||||
'description': None,
|
||||
}
|
||||
|
||||
test_hypermetro_type = {
|
||||
'name': u'new_type',
|
||||
'qos_specs_id': None,
|
||||
'deleted': False,
|
||||
'created_at': None,
|
||||
'updated_at': None,
|
||||
'extra_specs': {
|
||||
'hypermetro': '<is> True'
|
||||
},
|
||||
'is_public': True,
|
||||
'deleted_at': None,
|
||||
'id': u'550c089b-bfdd-4f7f-86e1-3ba88125555c',
|
||||
'description': None,
|
||||
}
|
||||
|
||||
hypermetro_devices = """
|
||||
{
|
||||
"remote_device": {
|
||||
@ -216,6 +242,9 @@ hypermetro_devices = """
|
||||
}
|
||||
"""
|
||||
|
||||
CONSISTGROUP = {'id': "21ec7341-9256-497b-97d9-ef48edcf0635",
|
||||
'status': "available", }
|
||||
|
||||
FAKE_FIND_POOL_RESPONSE = {'CAPACITY': '985661440',
|
||||
'ID': '0',
|
||||
'TOTALCAPACITY': '985661440'}
|
||||
@ -1003,12 +1032,13 @@ FAKE_HYPERMETRODOMAIN_RESPONSE = """
|
||||
"error":{
|
||||
"code": 0
|
||||
},
|
||||
"data":{
|
||||
"data":[{
|
||||
"PRODUCTVERSION": "V100R001C10",
|
||||
"ID": "11",
|
||||
"NAME": "hypermetro_test",
|
||||
"RUNNINGSTATUS": "42"
|
||||
}
|
||||
"RUNNINGSTATUS": "1",
|
||||
"HEALTHSTATUS": "0"
|
||||
}]
|
||||
}
|
||||
"""
|
||||
|
||||
@ -1072,7 +1102,7 @@ FAKE_SMARTCACHEPARTITION_RESPONSE = """
|
||||
}
|
||||
"""
|
||||
|
||||
FAKE_CONNECT_FC_RESPONCE = {
|
||||
FAKE_CONNECT_FC_RESPONSE = {
|
||||
"driver_volume_type": 'fibre_channel',
|
||||
"data": {
|
||||
"target_wwn": ["10000090fa0d6754"],
|
||||
@ -1081,7 +1111,15 @@ FAKE_CONNECT_FC_RESPONCE = {
|
||||
}
|
||||
}
|
||||
|
||||
FAKE_METRO_INFO_RESPONCE = {
|
||||
FAKE_METRO_INFO_RESPONSE = {
|
||||
"PRODUCTVERSION": "V100R001C10",
|
||||
"ID": "11",
|
||||
"NAME": "hypermetro_test",
|
||||
"RUNNINGSTATUS": "42",
|
||||
"HEALTHSTATUS": "0"
|
||||
}
|
||||
|
||||
FAKE_METRO_INFO_NEW_RESPONSE = """{
|
||||
"error": {
|
||||
"code": 0
|
||||
},
|
||||
@ -1089,9 +1127,85 @@ FAKE_METRO_INFO_RESPONCE = {
|
||||
"PRODUCTVERSION": "V100R001C10",
|
||||
"ID": "11",
|
||||
"NAME": "hypermetro_test",
|
||||
"RUNNINGSTATUS": "42"
|
||||
"RUNNINGSTATUS": "1",
|
||||
"HEALTHSTATUS": "1"
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
FAKE_CREATE_METROROUP_RESPONSE = """
|
||||
{
|
||||
"data": {
|
||||
"DESCRIPTION": "",
|
||||
"DOMAINID": "643e8c4c5f670100",
|
||||
"DOMAINNAME": "hypermetro-domain",
|
||||
"HEALTHSTATUS": "1",
|
||||
"ID": "3400a30d844d8002",
|
||||
"ISEMPTY": "true",
|
||||
"NAME": "6F7kdHZcQJ2zbzxHmBl4FQ",
|
||||
"PRIORITYSTATIONTYPE": "0",
|
||||
"RECOVERYPOLICY": "1",
|
||||
"RESOURCETYPE": "11",
|
||||
"RUNNINGSTATUS": "41",
|
||||
"SPEED": "2",
|
||||
"SYNCDIRECTION": "1",
|
||||
"TYPE": 15364
|
||||
},
|
||||
"error": {
|
||||
"code": 0,
|
||||
"description": "0"
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
FAKE_GET_METROROUP_RESPONSE = {
|
||||
"data": [{
|
||||
"DESCRIPTION": "",
|
||||
"DOMAINID": "643e8c4c5f670100",
|
||||
"DOMAINNAME": "hypermetro-domain",
|
||||
"HEALTHSTATUS": "1",
|
||||
"ID": "11",
|
||||
"ISEMPTY": "true",
|
||||
"NAME": huawei_utils.encode_name(test_volume['id']),
|
||||
"PRIORITYSTATIONTYPE": "0",
|
||||
"RECOVERYPOLICY": "1",
|
||||
"RESOURCETYPE": "11",
|
||||
"RUNNINGSTATUS": "41",
|
||||
"SPEED": "2",
|
||||
"SYNCDIRECTION": "1",
|
||||
"TYPE": 15364
|
||||
}],
|
||||
"error": {
|
||||
"code": 0,
|
||||
"description": "0"
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
FAKE_GET_METROROUP_ID_RESPONSE = """
|
||||
{
|
||||
"data": {
|
||||
"DESCRIPTION": "",
|
||||
"DOMAINID": "643e8c4c5f670100",
|
||||
"DOMAINNAME": "hypermetro-domain",
|
||||
"HEALTHSTATUS": "1",
|
||||
"ID": "11",
|
||||
"ISEMPTY": "false",
|
||||
"NAME": "IexzQZJWSXuX2e9I7c8GNQ",
|
||||
"PRIORITYSTATIONTYPE": "0",
|
||||
"RECOVERYPOLICY": "1",
|
||||
"RESOURCETYPE": "11",
|
||||
"RUNNINGSTATUS": "1",
|
||||
"SPEED": "2",
|
||||
"SYNCDIRECTION": "1",
|
||||
"TYPE": 15364
|
||||
},
|
||||
"error": {
|
||||
"code": 0,
|
||||
"description": "0"
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
# mock login info map
|
||||
MAP_COMMAND_TO_FAKE_RESPONSE = {}
|
||||
@ -1453,24 +1567,33 @@ MAP_COMMAND_TO_FAKE_RESPONSE['/HyperMetroDomain?range=[0-32]/GET'] = (
|
||||
FAKE_HYPERMETRODOMAIN_RESPONSE)
|
||||
|
||||
MAP_COMMAND_TO_FAKE_RESPONSE['/HyperMetroPair/POST'] = (
|
||||
FAKE_HYPERMETRODOMAIN_RESPONSE)
|
||||
FAKE_HYPERMETRO_RESPONSE)
|
||||
|
||||
MAP_COMMAND_TO_FAKE_RESPONSE['/HyperMetroPair/11/GET'] = (
|
||||
FAKE_HYPERMETRODOMAIN_RESPONSE)
|
||||
MAP_COMMAND_TO_FAKE_RESPONSE['/HyperMetroPair/3400a30d844d0007/GET'] = (
|
||||
FAKE_METRO_INFO_NEW_RESPONSE)
|
||||
|
||||
MAP_COMMAND_TO_FAKE_RESPONSE['/HyperMetroPair/disable_hcpair/PUT'] = (
|
||||
FAKE_COMMON_SUCCESS_RESPONSE)
|
||||
|
||||
MAP_COMMAND_TO_FAKE_RESPONSE['/hyperMetro/associate/pair/POST'] = (
|
||||
FAKE_COMMON_SUCCESS_RESPONSE)
|
||||
|
||||
MAP_COMMAND_TO_FAKE_RESPONSE['/hyperMetro/associate/pair/DELETE'] = (
|
||||
FAKE_COMMON_SUCCESS_RESPONSE)
|
||||
|
||||
MAP_COMMAND_TO_FAKE_RESPONSE['/HyperMetroPair/11/DELETE'] = (
|
||||
FAKE_COMMON_SUCCESS_RESPONSE)
|
||||
|
||||
MAP_COMMAND_TO_FAKE_RESPONSE['/HyperMetroPair/1/GET'] = (
|
||||
FAKE_HYPERMETRO_RESPONSE)
|
||||
|
||||
MAP_COMMAND_TO_FAKE_RESPONSE['/HyperMetroPair?range=[0-65535]/GET'] = (
|
||||
MAP_COMMAND_TO_FAKE_RESPONSE['/HyperMetroPair?range=[0-4095]/GET'] = (
|
||||
FAKE_COMMON_SUCCESS_RESPONSE)
|
||||
|
||||
MAP_COMMAND_TO_FAKE_RESPONSE['/splitmirror?range=[0-512]/GET'] = (
|
||||
MAP_COMMAND_TO_FAKE_RESPONSE['/HyperMetroPair/synchronize_hcpair/PUT'] = (
|
||||
FAKE_COMMON_SUCCESS_RESPONSE)
|
||||
|
||||
MAP_COMMAND_TO_FAKE_RESPONSE['/splitmirror?range=[0-8191]/GET'] = (
|
||||
FAKE_COMMON_SUCCESS_RESPONSE)
|
||||
|
||||
FAKE_GET_PORTG_BY_VIEW = """
|
||||
@ -1659,8 +1782,25 @@ MAP_COMMAND_TO_FAKE_RESPONSE['/fc_port/associate?TYPE=213&ASSOCIATEOBJTYPE='
|
||||
'257&ASSOCIATEOBJID=0/GET'] = (
|
||||
FAKE_PORTS_IN_PG_RESPONSE)
|
||||
|
||||
MAP_COMMAND_TO_FAKE_RESPONSE['/HyperMetro_ConsistentGroup/POST'] = (
|
||||
FAKE_CREATE_METROROUP_RESPONSE)
|
||||
|
||||
MAP_COMMAND_TO_FAKE_RESPONSE["/HyperMetro_ConsistentGroup?type"
|
||||
"='15364'/GET"] = (
|
||||
json.dumps(FAKE_GET_METROROUP_RESPONSE))
|
||||
|
||||
MAP_COMMAND_TO_FAKE_RESPONSE["/HyperMetro_ConsistentGroup/11/GET"] = (
|
||||
FAKE_GET_METROROUP_ID_RESPONSE)
|
||||
|
||||
MAP_COMMAND_TO_FAKE_RESPONSE["/HyperMetro_ConsistentGroup/11/DELETE"] = (
|
||||
FAKE_COMMON_SUCCESS_RESPONSE)
|
||||
|
||||
MAP_COMMAND_TO_FAKE_RESPONSE["/HyperMetro_ConsistentGroup/stop/PUT"] = (
|
||||
FAKE_COMMON_SUCCESS_RESPONSE)
|
||||
|
||||
MAP_COMMAND_TO_FAKE_RESPONSE["/HyperMetro_ConsistentGroup/sync/PUT"] = (
|
||||
FAKE_COMMON_SUCCESS_RESPONSE)
|
||||
|
||||
# Replication response
|
||||
FAKE_GET_REMOTEDEV_RESPONSE = """
|
||||
{
|
||||
"data":[{
|
||||
@ -1677,6 +1817,7 @@ FAKE_GET_REMOTEDEV_RESPONSE = """
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
MAP_COMMAND_TO_FAKE_RESPONSE['/remote_device/GET'] = (
|
||||
FAKE_GET_REMOTEDEV_RESPONSE)
|
||||
|
||||
@ -2291,7 +2432,7 @@ class HuaweiISCSIDriverTestCase(test.TestCase):
|
||||
|
||||
def test_get_volume_status(self):
|
||||
data = self.driver.get_volume_stats()
|
||||
self.assertEqual('2.0.6', data['driver_version'])
|
||||
self.assertEqual('2.0.7', data['driver_version'])
|
||||
|
||||
@mock.patch.object(rest_client.RestClient, 'get_lun_info',
|
||||
return_value={"CAPACITY": 6291456})
|
||||
@ -2657,7 +2798,7 @@ class HuaweiISCSIDriverTestCase(test.TestCase):
|
||||
@mock.patch.object(rest_client.RestClient, 'check_hypermetro_exist',
|
||||
return_value=True)
|
||||
@mock.patch.object(rest_client.RestClient, 'get_hypermetro_by_id',
|
||||
return_value=FAKE_METRO_INFO_RESPONCE)
|
||||
return_value=FAKE_METRO_INFO_RESPONSE)
|
||||
@mock.patch.object(rest_client.RestClient, 'delete_hypermetro')
|
||||
@mock.patch.object(rest_client.RestClient, 'delete_lun',
|
||||
return_value=None)
|
||||
@ -3567,6 +3708,50 @@ class HuaweiISCSIDriverTestCase(test.TestCase):
|
||||
iqn = self.driver.client._get_tgt_iqn_from_rest(ip)
|
||||
self.assertIsNone(iqn)
|
||||
|
||||
def test_create_cgsnapshot(self):
|
||||
test_snapshots = [test_snap]
|
||||
ctxt = context.get_admin_context()
|
||||
model, snapshots = self.driver.create_cgsnapshot(ctxt,
|
||||
test_cgsnapshot,
|
||||
test_snapshots)
|
||||
snapshots_model_update = [{'id': '21ec7341-9256-497b-97d9'
|
||||
'-ef48edcf0635',
|
||||
'status': 'available',
|
||||
'provider_location': 11}]
|
||||
self.assertEqual(snapshots_model_update, snapshots)
|
||||
self.assertEqual('available', model['status'])
|
||||
|
||||
def test_create_cgsnapshot_create_snapshot_fail(self):
|
||||
test_snapshots = [test_snap]
|
||||
ctxt = context.get_admin_context()
|
||||
self.mock_object(rest_client.RestClient, 'create_snapshot',
|
||||
mock.Mock(side_effect=(
|
||||
exception.VolumeBackendAPIException(data='err'))))
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.create_cgsnapshot,
|
||||
ctxt,
|
||||
test_cgsnapshot,
|
||||
test_snapshots)
|
||||
|
||||
def test_create_cgsnapshot_active_snapshot_fail(self):
|
||||
test_snapshots = [test_snap]
|
||||
ctxt = context.get_admin_context()
|
||||
self.mock_object(rest_client.RestClient, 'activate_snapshot',
|
||||
mock.Mock(side_effect=(
|
||||
exception.VolumeBackendAPIException(data='err'))))
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.create_cgsnapshot,
|
||||
ctxt,
|
||||
test_cgsnapshot,
|
||||
test_snapshots)
|
||||
|
||||
def test_delete_cgsnapshot(self):
|
||||
test_snapshots = [test_snap]
|
||||
ctxt = context.get_admin_context()
|
||||
self.driver.delete_cgsnapshot(ctxt,
|
||||
test_cgsnapshot,
|
||||
test_snapshots)
|
||||
|
||||
|
||||
class FCSanLookupService(object):
|
||||
|
||||
@ -3685,7 +3870,7 @@ class HuaweiFCDriverTestCase(test.TestCase):
|
||||
'get_remote_device_by_wwn',
|
||||
mock.Mock(return_value=remote_device_info))
|
||||
data = self.driver.get_volume_stats()
|
||||
self.assertEqual('2.0.5', data['driver_version'])
|
||||
self.assertEqual('2.0.7', data['driver_version'])
|
||||
self.assertTrue(data['pools'][0]['replication_enabled'])
|
||||
self.assertListEqual(['sync', 'async'],
|
||||
data['pools'][0]['replication_type'])
|
||||
@ -3702,7 +3887,7 @@ class HuaweiFCDriverTestCase(test.TestCase):
|
||||
'try_get_remote_wwn',
|
||||
mock.Mock(return_value={}))
|
||||
data = self.driver.get_volume_stats()
|
||||
self.assertEqual('2.0.5', data['driver_version'])
|
||||
self.assertEqual('2.0.7', data['driver_version'])
|
||||
self.assertNotIn('replication_enabled', data['pools'][0])
|
||||
|
||||
def test_extend_volume(self):
|
||||
@ -4091,6 +4276,96 @@ class HuaweiFCDriverTestCase(test.TestCase):
|
||||
lun_info = self.driver.create_volume(hyper_volume)
|
||||
self.assertEqual(metadata, lun_info['metadata'])
|
||||
|
||||
@mock.patch.object(huawei_driver.HuaweiBaseDriver, '_get_volume_params',
|
||||
return_value=fake_hypermetro_opts)
|
||||
@mock.patch.object(rest_client.RestClient, 'get_all_pools',
|
||||
return_value=FAKE_STORAGE_POOL_RESPONSE)
|
||||
@mock.patch.object(rest_client.RestClient, 'get_pool_info',
|
||||
return_value=FAKE_FIND_POOL_RESPONSE)
|
||||
@mock.patch.object(rest_client.RestClient, 'get_hyper_domain_id',
|
||||
return_value='11')
|
||||
@mock.patch.object(hypermetro.HuaweiHyperMetro, '_wait_volume_ready',
|
||||
return_value=True)
|
||||
@mock.patch.object(rest_client.RestClient, 'create_hypermetro')
|
||||
def test_create_hypermetro_fail(self,
|
||||
mock_pair_info,
|
||||
mock_hypermetro_opts,
|
||||
mock_all_pool_info,
|
||||
mock_pool_info,
|
||||
mock_hyper_domain,
|
||||
mock_volume_ready,
|
||||
):
|
||||
mock_pair_info.side_effect = (
|
||||
exception.VolumeBackendAPIException(data='Error occurred.'))
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.metro.create_hypermetro, "11", {})
|
||||
|
||||
@mock.patch.object(huawei_driver.huawei_utils, 'get_volume_metadata',
|
||||
return_value={'hypermetro_id': '3400a30d844d0007',
|
||||
'remote_lun_id': '1'})
|
||||
@mock.patch.object(rest_client.RestClient, 'do_mapping',
|
||||
return_value={'lun_id': '1',
|
||||
'view_id': '1',
|
||||
'aval_luns': '[1]'})
|
||||
def test_hypermetro_connection_success_2(self, mock_map, mock_metadata):
|
||||
fc_properties = self.driver.metro.connect_volume_fc(test_volume,
|
||||
FakeConnector)
|
||||
self.assertEqual(1, fc_properties['data']['target_lun'])
|
||||
|
||||
@mock.patch.object(huawei_driver.huawei_utils, 'get_volume_metadata',
|
||||
return_value={'hypermetro_id': '3400a30d844d0007',
|
||||
'remote_lun_id': '1'})
|
||||
def test_terminate_hypermetro_connection_success(self, mock_metradata):
|
||||
self.driver.metro.disconnect_volume_fc(test_volume, FakeConnector)
|
||||
|
||||
@mock.patch.object(huawei_driver.huawei_utils, 'get_volume_metadata',
|
||||
return_value={'hypermetro_id': '3400a30d844d0007',
|
||||
'remote_lun_id': None})
|
||||
@mock.patch.object(rest_client.RestClient, 'get_lun_id_by_name',
|
||||
return_value=None)
|
||||
def test_hypermetroid_none_fail(self, mock_metadata, moke_metro_name):
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.metro.connect_volume_fc,
|
||||
test_volume,
|
||||
FakeConnector)
|
||||
|
||||
def test_wait_volume_ready_success(self):
|
||||
flag = self.driver.metro._wait_volume_ready("11")
|
||||
self.assertIsNone(flag)
|
||||
|
||||
@mock.patch.object(huawei_driver.huawei_utils, 'get_volume_metadata',
|
||||
return_value={'hypermetro_id': '3400a30d844d0007',
|
||||
'remote_lun_id': '1'})
|
||||
@mock.patch.object(rest_client.RestClient, 'get_online_free_wwns',
|
||||
return_value=[])
|
||||
@mock.patch.object(rest_client.RestClient, 'get_host_iscsi_initiators',
|
||||
return_value=[])
|
||||
def test_hypermetro_connection_fail(self, mock_metadata,
|
||||
mock_fc_initiator,
|
||||
mock_host_initiators):
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.metro.connect_volume_fc,
|
||||
test_volume,
|
||||
FakeConnector)
|
||||
|
||||
def test_create_snapshot_fail_hypermetro(self):
|
||||
self.mock_object(
|
||||
huawei_driver.HuaweiBaseDriver,
|
||||
'_get_volume_type',
|
||||
mock.Mock(return_value={'extra_specs': replica_hypermetro_specs}))
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.create_volume_from_snapshot,
|
||||
test_volume, test_snap)
|
||||
|
||||
def test_create_snapshot_fail_no_snapshot_id(self):
|
||||
temp_snap = copy.deepcopy(test_snap)
|
||||
temp_snap.pop('provider_location')
|
||||
self.mock_object(rest_client.RestClient, 'get_snapshot_id_by_name',
|
||||
mock.Mock(return_value=None))
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.create_volume_from_snapshot,
|
||||
test_volume, temp_snap)
|
||||
|
||||
@mock.patch.object(rest_client.RestClient, 'call',
|
||||
return_value={"data": [{"RUNNINGSTATUS": "27",
|
||||
"ID": '1'},
|
||||
@ -4130,6 +4405,97 @@ class HuaweiFCDriverTestCase(test.TestCase):
|
||||
res = self.driver.client.is_host_associated_to_hostgroup('1')
|
||||
self.assertFalse(res)
|
||||
|
||||
@mock.patch.object(huawei_driver.HuaweiBaseDriver,
|
||||
'_get_consistencygroup_type',
|
||||
return_value={"hypermetro": "true"})
|
||||
def test_create_hypermetro_consistencygroup_success(self, mock_grouptype):
|
||||
"""Test that create_consistencygroup return successfully."""
|
||||
ctxt = context.get_admin_context()
|
||||
# Create consistency group
|
||||
model_update = self.driver.create_consistencygroup(ctxt, CONSISTGROUP)
|
||||
|
||||
self.assertEqual('available',
|
||||
model_update['status'],
|
||||
"Consistency Group created failed")
|
||||
|
||||
@mock.patch.object(huawei_driver.HuaweiBaseDriver,
|
||||
'_get_consistencygroup_type',
|
||||
return_value={"hypermetro": "false"})
|
||||
def test_create_normal_consistencygroup_success(self,
|
||||
mock_grouptype):
|
||||
"""Test that create_consistencygroup return successfully."""
|
||||
ctxt = context.get_admin_context()
|
||||
# Create consistency group
|
||||
model_update = self.driver.create_consistencygroup(ctxt, CONSISTGROUP)
|
||||
|
||||
self.assertEqual('available',
|
||||
model_update['status'],
|
||||
"Consistency Group created failed")
|
||||
|
||||
@mock.patch.object(huawei_driver.HuaweiBaseDriver,
|
||||
'_get_consistencygroup_type',
|
||||
return_value={"hypermetro": "true"})
|
||||
def test_delete_hypermetro_consistencygroup_success(self, mock_grouptype):
|
||||
"""Test that create_consistencygroup return successfully."""
|
||||
test_volumes = [test_volume]
|
||||
ctxt = context.get_admin_context()
|
||||
# Create consistency group
|
||||
model, volumes = self.driver.delete_consistencygroup(ctxt,
|
||||
CONSISTGROUP,
|
||||
test_volumes)
|
||||
self.assertEqual('available',
|
||||
model['status'],
|
||||
"Consistency Group created failed")
|
||||
|
||||
def test_delete_normal_consistencygroup_success(self):
|
||||
ctxt = context.get_admin_context()
|
||||
test_volumes = [test_volume]
|
||||
self.mock_object(huawei_driver.HuaweiBaseDriver,
|
||||
'_get_consistencygroup_type',
|
||||
mock.Mock(return_value={"hypermetro": "false"}))
|
||||
|
||||
model, volumes = self.driver.delete_consistencygroup(ctxt,
|
||||
CONSISTGROUP,
|
||||
test_volumes)
|
||||
self.assertEqual('available',
|
||||
model['status'],
|
||||
"Consistency Group created failed")
|
||||
|
||||
@mock.patch.object(huawei_driver.HuaweiBaseDriver,
|
||||
'_get_consistencygroup_type',
|
||||
return_value={"hypermetro": "true"})
|
||||
@mock.patch.object(huawei_driver.huawei_utils, 'get_volume_metadata',
|
||||
return_value={'hypermetro_id': '3400a30d844d0007',
|
||||
'remote_lun_id': '59'})
|
||||
def test_update_consistencygroup_success(self,
|
||||
mock_grouptype,
|
||||
mock_metadata):
|
||||
"""Test that create_consistencygroup return successfully."""
|
||||
ctxt = context.get_admin_context()
|
||||
add_volumes = [test_volume]
|
||||
remove_volumes = [test_volume]
|
||||
# Create consistency group
|
||||
model_update = self.driver.update_consistencygroup(ctxt,
|
||||
CONSISTGROUP,
|
||||
add_volumes,
|
||||
remove_volumes)
|
||||
self.assertEqual('available',
|
||||
model_update[0]['status'],
|
||||
"Consistency Group update failed")
|
||||
|
||||
def test_create_hypermetro_consistencygroup_success_2(self):
|
||||
ctxt = context.get_admin_context()
|
||||
# Create consistency group
|
||||
temp_cg = copy.deepcopy(CONSISTGROUP)
|
||||
temp_cg['volume_type_id'] = '550c089b-bfdd-4f7f-86e1-3ba88125555c,'
|
||||
self.mock_object(volume_types, 'get_volume_type',
|
||||
mock.Mock(return_value=test_hypermetro_type))
|
||||
model_update = self.driver.create_consistencygroup(ctxt, temp_cg)
|
||||
|
||||
self.assertEqual('available',
|
||||
model_update['status'],
|
||||
"Consistency Group created failed")
|
||||
|
||||
|
||||
class HuaweiConfTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
|
@ -48,8 +48,11 @@ ERROR_VOLUME_ALREADY_EXIST = 1077948993
|
||||
LOGIN_SOCKET_TIMEOUT = 4
|
||||
ERROR_VOLUME_NOT_EXIST = 1077939726
|
||||
RELOGIN_ERROR_PASS = [ERROR_VOLUME_NOT_EXIST]
|
||||
HYPERMETRO_RUNNSTATUS_STOP = 41
|
||||
HYPERMETRO_RUNNSTATUS_NORMAL = 1
|
||||
RUNNING_NORMAL = '1'
|
||||
RUNNING_SYNC = '23'
|
||||
RUNNING_STOP = '41'
|
||||
HEALTH_NORMAL = '1'
|
||||
|
||||
NO_SPLITMIRROR_LICENSE = 1077950233
|
||||
NO_MIGRATION_LICENSE = 1073806606
|
||||
|
||||
|
@ -51,6 +51,21 @@ huawei_opts = [
|
||||
cfg.StrOpt('hypermetro_devices',
|
||||
default=None,
|
||||
help='The remote device hypermetro will use.'),
|
||||
cfg.StrOpt('metro_san_user',
|
||||
default=None,
|
||||
help='The remote metro device san user.'),
|
||||
cfg.StrOpt('metro_san_password',
|
||||
default=None,
|
||||
help='The remote metro device san password.'),
|
||||
cfg.StrOpt('metro_domain_name',
|
||||
default=None,
|
||||
help='The remote metro device domain name.'),
|
||||
cfg.StrOpt('metro_san_address',
|
||||
default=None,
|
||||
help='The remote metro device request url.'),
|
||||
cfg.StrOpt('metro_storage_pools',
|
||||
default=None,
|
||||
help='The remote metro device pool names.'),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
@ -110,14 +125,17 @@ class HuaweiBaseDriver(driver.VolumeDriver):
|
||||
metro_san_user = self.configuration.safe_get("metro_san_user")
|
||||
metro_san_password = self.configuration.safe_get("metro_san_password")
|
||||
if metro_san_address and metro_san_user and metro_san_password:
|
||||
self.metro_flag = True
|
||||
metro_san_address = metro_san_address.split(";")
|
||||
self.rmt_client = rest_client.RestClient(self.configuration,
|
||||
metro_san_address,
|
||||
metro_san_user,
|
||||
metro_san_password)
|
||||
self.rmt_client.login()
|
||||
|
||||
self.rmt_client.login()
|
||||
self.metro_flag = True
|
||||
else:
|
||||
self.metro_flag = False
|
||||
LOG.warning(_LW("Remote device not configured in cinder.conf"))
|
||||
# init replication manager
|
||||
if replica_client_conf:
|
||||
self.replica_client = rest_client.RestClient(self.configuration,
|
||||
@ -133,10 +151,8 @@ class HuaweiBaseDriver(driver.VolumeDriver):
|
||||
def get_volume_stats(self, refresh=False):
|
||||
"""Get volume status and reload huawei config file."""
|
||||
self.huawei_conf.update_config_value()
|
||||
if self.metro_flag:
|
||||
self.rmt_client.get_all_pools()
|
||||
|
||||
stats = self.client.update_volume_stats()
|
||||
stats = self.update_hypermetro_capability(stats)
|
||||
|
||||
if self.replica:
|
||||
stats = self.replica.update_replica_capability(stats)
|
||||
@ -146,6 +162,18 @@ class HuaweiBaseDriver(driver.VolumeDriver):
|
||||
|
||||
return stats
|
||||
|
||||
def update_hypermetro_capability(self, stats):
|
||||
if self.metro_flag:
|
||||
version = self.client.find_array_version()
|
||||
rmt_version = self.rmt_client.find_array_version()
|
||||
if (version >= constants.ARRAY_VERSION
|
||||
and rmt_version >= constants.ARRAY_VERSION):
|
||||
for pool in stats['pools']:
|
||||
pool['hypermetro'] = True
|
||||
pool['consistencygroup_support'] = True
|
||||
|
||||
return stats
|
||||
|
||||
def _get_volume_type(self, volume):
|
||||
volume_type = None
|
||||
type_id = volume['volume_type_id']
|
||||
@ -164,6 +192,17 @@ class HuaweiBaseDriver(driver.VolumeDriver):
|
||||
opts = self._get_volume_params_from_specs(specs)
|
||||
return opts
|
||||
|
||||
def _get_consistencygroup_type(self, group):
|
||||
specs = {}
|
||||
opts = {}
|
||||
type_id = group['volume_type_id'].split(",")
|
||||
if type_id[0] and len(type_id) == 2:
|
||||
ctxt = context.get_admin_context()
|
||||
volume_type = volume_types.get_volume_type(ctxt, type_id[0])
|
||||
specs = dict(volume_type).get('extra_specs')
|
||||
opts = self._get_volume_params_from_specs(specs)
|
||||
return opts
|
||||
|
||||
def _get_volume_params_from_specs(self, specs):
|
||||
"""Return the volume parameters from extra specs."""
|
||||
opts_capability = {
|
||||
@ -1480,6 +1519,134 @@ class HuaweiBaseDriver(driver.VolumeDriver):
|
||||
self.client.is_host_associated_to_hostgroup(host_id)):
|
||||
self.client.remove_host(host_id)
|
||||
|
||||
def create_consistencygroup(self, context, group):
|
||||
"""Creates a consistencygroup."""
|
||||
model_update = {'status': 'available'}
|
||||
opts = self._get_consistencygroup_type(group)
|
||||
if (opts.get('hypermetro') == 'true'):
|
||||
metro = hypermetro.HuaweiHyperMetro(self.client,
|
||||
self.rmt_client,
|
||||
self.configuration)
|
||||
metro.create_consistencygroup(group)
|
||||
return model_update
|
||||
|
||||
# Array will create CG at create_cgsnapshot time. Cinder will
|
||||
# maintain the CG and volumes relationship in the db.
|
||||
return model_update
|
||||
|
||||
def delete_consistencygroup(self, context, group, volumes):
|
||||
opts = self._get_consistencygroup_type(group)
|
||||
if opts.get('hypermetro') == 'true':
|
||||
metro = hypermetro.HuaweiHyperMetro(self.client,
|
||||
self.rmt_client,
|
||||
self.configuration)
|
||||
return metro.delete_consistencygroup(context, group, volumes)
|
||||
|
||||
model_update = {}
|
||||
volumes_model_update = []
|
||||
model_update.update({'status': group['status']})
|
||||
|
||||
for volume_ref in volumes:
|
||||
try:
|
||||
self.delete_volume(volume_ref)
|
||||
volumes_model_update.append(
|
||||
{'id': volume_ref['id'], 'status': 'deleted'})
|
||||
except Exception:
|
||||
volumes_model_update.append(
|
||||
{'id': volume_ref['id'], 'status': 'error_deleting'})
|
||||
|
||||
return model_update, volumes_model_update
|
||||
|
||||
def update_consistencygroup(self, context, group,
|
||||
add_volumes,
|
||||
remove_volumes):
|
||||
model_update = {'status': 'available'}
|
||||
opts = self._get_consistencygroup_type(group)
|
||||
if opts.get('hypermetro') == 'true':
|
||||
metro = hypermetro.HuaweiHyperMetro(self.client,
|
||||
self.rmt_client,
|
||||
self.configuration)
|
||||
metro.update_consistencygroup(context, group,
|
||||
add_volumes,
|
||||
remove_volumes)
|
||||
return model_update, None, None
|
||||
|
||||
# Array will create CG at create_cgsnapshot time. Cinder will
|
||||
# maintain the CG and volumes relationship in the db.
|
||||
return model_update, None, None
|
||||
|
||||
def create_cgsnapshot(self, context, cgsnapshot, snapshots):
|
||||
"""Create cgsnapshot."""
|
||||
LOG.info(_LI('Create cgsnapshot for consistency group'
|
||||
': %(group_id)s'),
|
||||
{'group_id': cgsnapshot['consistencygroup_id']})
|
||||
|
||||
model_update = {}
|
||||
snapshots_model_update = []
|
||||
added_snapshots_info = []
|
||||
|
||||
try:
|
||||
for snapshot in snapshots:
|
||||
volume = snapshot.get('volume')
|
||||
if not volume:
|
||||
msg = (_("Can't get volume id from snapshot, "
|
||||
"snapshot: %(id)s") % {"id": snapshot['id']})
|
||||
LOG.error(msg)
|
||||
raise exception.VolumeBackendAPIException(data=msg)
|
||||
|
||||
volume_name = huawei_utils.encode_name(volume['id'])
|
||||
|
||||
lun_id = self.client.get_lun_id(volume, volume_name)
|
||||
snapshot_name = huawei_utils.encode_name(snapshot['id'])
|
||||
snapshot_description = snapshot['id']
|
||||
info = self.client.create_snapshot(lun_id,
|
||||
snapshot_name,
|
||||
snapshot_description)
|
||||
snapshot_model_update = {'id': snapshot['id'],
|
||||
'status': 'available',
|
||||
'provider_location': info['ID']}
|
||||
snapshots_model_update.append(snapshot_model_update)
|
||||
added_snapshots_info.append(info)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_LE("Create cgsnapshots failed. "
|
||||
"Cgsnapshot id: %s."), cgsnapshot['id'])
|
||||
snapshot_ids = [added_snapshot['ID']
|
||||
for added_snapshot in added_snapshots_info]
|
||||
try:
|
||||
self.client.activate_snapshot(snapshot_ids)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_LE("Active cgsnapshots failed. "
|
||||
"Cgsnapshot id: %s."), cgsnapshot['id'])
|
||||
|
||||
model_update['status'] = 'available'
|
||||
|
||||
return model_update, snapshots_model_update
|
||||
|
||||
def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
|
||||
"""Delete consistency group snapshot."""
|
||||
LOG.info(_LI('Delete cgsnapshot %(snap_id)s for consistency group: '
|
||||
'%(group_id)s'),
|
||||
{'snap_id': cgsnapshot['id'],
|
||||
'group_id': cgsnapshot['consistencygroup_id']})
|
||||
|
||||
model_update = {}
|
||||
snapshots_model_update = []
|
||||
model_update['status'] = cgsnapshot['status']
|
||||
|
||||
for snapshot in snapshots:
|
||||
try:
|
||||
self.delete_snapshot(snapshot)
|
||||
snapshots_model_update.append({'id': snapshot['id'],
|
||||
'status': 'deleted'})
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_LE("Delete cg snapshots failed. "
|
||||
"Cgsnapshot id: %s"), cgsnapshot['id'])
|
||||
|
||||
return model_update, snapshots_model_update
|
||||
|
||||
def _classify_volume(self, volumes):
|
||||
normal_volumes = []
|
||||
replica_volumes = []
|
||||
@ -1608,9 +1775,13 @@ class HuaweiISCSIDriver(HuaweiBaseDriver, driver.ISCSIDriver):
|
||||
2.0.3 - Manage/unmanage snapshot support
|
||||
2.0.5 - Replication V2 support
|
||||
2.0.6 - Support iSCSI configuration in Replication
|
||||
2.0.7 - Hypermetro support
|
||||
Hypermetro consistency group support
|
||||
Consistency group support
|
||||
Cgsnapshot support
|
||||
"""
|
||||
|
||||
VERSION = "2.0.6"
|
||||
VERSION = "2.0.7"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(HuaweiISCSIDriver, self).__init__(*args, **kwargs)
|
||||
@ -1801,9 +1972,13 @@ class HuaweiFCDriver(HuaweiBaseDriver, driver.FibreChannelDriver):
|
||||
2.0.3 - Manage/unmanage snapshot support
|
||||
2.0.4 - Balanced FC port selection
|
||||
2.0.5 - Replication V2 support
|
||||
2.0.7 - Hypermetro support
|
||||
Hypermetro consistency group support
|
||||
Consistency group support
|
||||
Cgsnapshot support
|
||||
"""
|
||||
|
||||
VERSION = "2.0.5"
|
||||
VERSION = "2.0.7"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(HuaweiFCDriver, self).__init__(*args, **kwargs)
|
||||
|
@ -79,17 +79,10 @@ class HuaweiHyperMetro(object):
|
||||
remote_lun_id = metadata['remote_lun_id']
|
||||
|
||||
if metro_id:
|
||||
exst_flag = self.client.check_hypermetro_exist(metro_id)
|
||||
if exst_flag:
|
||||
metro_info = self.client.get_hypermetro_by_id(metro_id)
|
||||
metro_status = int(metro_info['data']['RUNNINGSTATUS'])
|
||||
self.check_metro_need_to_stop(volume)
|
||||
|
||||
LOG.debug("Hypermetro status is: %s.", metro_status)
|
||||
if constants.HYPERMETRO_RUNNSTATUS_STOP != metro_status:
|
||||
self.client.stop_hypermetro(metro_id)
|
||||
|
||||
# Delete hypermetro
|
||||
self.client.delete_hypermetro(metro_id)
|
||||
# Delete hypermetro
|
||||
self.client.delete_hypermetro(metro_id)
|
||||
|
||||
# Delete remote lun.
|
||||
if remote_lun_id and self.rmt_client.check_lun_exist(remote_lun_id):
|
||||
@ -274,3 +267,100 @@ class HuaweiHyperMetro(object):
|
||||
|
||||
def get_hypermetro_stats(self, hypermetro_id):
|
||||
pass
|
||||
|
||||
def create_consistencygroup(self, group):
|
||||
LOG.info(_LI("Create Consistency Group: %(group)s."),
|
||||
{'group': group['id']})
|
||||
group_name = huawei_utils.encode_name(group['id'])
|
||||
domain_name = self.configuration.metro_domain_name
|
||||
domain_id = self.client.get_hyper_domain_id(domain_name)
|
||||
if not domain_name or not domain_id:
|
||||
msg = _("The domain_name config in cinder.conf is wrong.")
|
||||
LOG.error(msg)
|
||||
raise exception.VolumeBackendAPIException(data=msg)
|
||||
|
||||
self.client.create_metrogroup(group_name, group['id'], domain_id)
|
||||
|
||||
def delete_consistencygroup(self, context, group, volumes):
|
||||
LOG.info(_LI("Delete Consistency Group: %(group)s."),
|
||||
{'group': group['id']})
|
||||
model_update = {}
|
||||
volumes_model_update = []
|
||||
model_update['status'] = group['status']
|
||||
metrogroup_id = self.check_consistencygroup_need_to_stop(group)
|
||||
if metrogroup_id:
|
||||
self.client.delete_metrogroup(metrogroup_id)
|
||||
|
||||
# Deal with the return volumes info
|
||||
for volume_ref in volumes:
|
||||
volume_update = {'id': volume_ref['id']}
|
||||
volume_update['status'] = 'deleted'
|
||||
volumes_model_update.append(volume_update)
|
||||
|
||||
return model_update, volumes_model_update
|
||||
|
||||
def update_consistencygroup(self, context, group,
|
||||
add_volumes, remove_volumes):
|
||||
LOG.info(_LI("Update Consistency Group: %(group)s. "
|
||||
"This adds or removes volumes from a CG."),
|
||||
{'group': group['id']})
|
||||
model_update = {}
|
||||
model_update['status'] = group['status']
|
||||
metrogroup_id = self.check_consistencygroup_need_to_stop(group)
|
||||
if metrogroup_id:
|
||||
# Deal with add volumes to CG
|
||||
for volume in add_volumes:
|
||||
metro_id = self.check_metro_need_to_stop(volume)
|
||||
self.client.add_metro_to_metrogroup(metrogroup_id,
|
||||
metro_id)
|
||||
|
||||
# Deal with remove volumes from CG
|
||||
for volume in remove_volumes:
|
||||
metro_id = self.check_metro_need_to_stop(volume)
|
||||
self.client.remove_metro_from_metrogroup(metrogroup_id,
|
||||
metro_id)
|
||||
self.client.sync_hypermetro(metro_id)
|
||||
|
||||
new_group_info = self.client.get_metrogroup_by_id(metrogroup_id)
|
||||
is_empty = new_group_info["ISEMPTY"]
|
||||
if is_empty == 'false':
|
||||
self.client.sync_metrogroup(metrogroup_id)
|
||||
|
||||
# if CG not exist on array
|
||||
else:
|
||||
msg = _("The CG does not exist on array.")
|
||||
LOG.error(msg)
|
||||
raise exception.VolumeBackendAPIException(data=msg)
|
||||
|
||||
def check_metro_need_to_stop(self, volume):
|
||||
metadata = huawei_utils.get_volume_metadata(volume)
|
||||
metro_id = metadata['hypermetro_id']
|
||||
metro_existed = self.client.check_hypermetro_exist(metro_id)
|
||||
|
||||
if metro_existed:
|
||||
metro_info = self.client.get_hypermetro_by_id(metro_id)
|
||||
metro_health_status = metro_info['HEALTHSTATUS']
|
||||
metro_running_status = metro_info['RUNNINGSTATUS']
|
||||
|
||||
if (metro_health_status == constants.HEALTH_NORMAL and
|
||||
(metro_running_status == constants.RUNNING_NORMAL or
|
||||
metro_running_status == constants.RUNNING_SYNC)):
|
||||
self.client.stop_hypermetro(metro_id)
|
||||
|
||||
return metro_id
|
||||
|
||||
def check_consistencygroup_need_to_stop(self, group):
|
||||
group_name = huawei_utils.encode_name(group['id'])
|
||||
metrogroup_id = self.client.get_metrogroup_by_name(group_name)
|
||||
|
||||
if metrogroup_id:
|
||||
metrogroup_info = self.client.get_metrogroup_by_id(metrogroup_id)
|
||||
health_status = metrogroup_info['HEALTHSTATUS']
|
||||
running_status = metrogroup_info['RUNNINGSTATUS']
|
||||
|
||||
if (health_status == constants.HEALTH_NORMAL
|
||||
and (running_status == constants.RUNNING_NORMAL
|
||||
or running_status == constants.RUNNING_SYNC)):
|
||||
self.client.stop_metrogroup(metrogroup_id)
|
||||
|
||||
return metrogroup_id
|
||||
|
@ -286,7 +286,9 @@ class RestClient(object):
|
||||
|
||||
def activate_snapshot(self, snapshot_id):
|
||||
url = "/snapshot/activate"
|
||||
data = {"SNAPSHOTLIST": [snapshot_id]}
|
||||
data = ({"SNAPSHOTLIST": snapshot_id}
|
||||
if type(snapshot_id) in (list, tuple)
|
||||
else {"SNAPSHOTLIST": [snapshot_id]})
|
||||
result = self.call(url, data)
|
||||
self._assert_rest_result(result, _('Activate snapshot error.'))
|
||||
|
||||
@ -1156,6 +1158,7 @@ class RestClient(object):
|
||||
smartcache=True,
|
||||
smartpartition=True,
|
||||
hypermetro=True,
|
||||
consistencygroup_support=True,
|
||||
))
|
||||
data['pools'].append(pool)
|
||||
return data
|
||||
@ -1885,7 +1888,8 @@ class RestClient(object):
|
||||
|
||||
msg = _('get_hypermetro_by_id error.')
|
||||
self._assert_rest_result(result, msg)
|
||||
return result
|
||||
self._assert_data_in_result(result, msg)
|
||||
return result['data']
|
||||
|
||||
def check_hypermetro_exist(self, metro_id):
|
||||
url = "/HyperMetroPair/" + metro_id
|
||||
@ -1936,8 +1940,97 @@ class RestClient(object):
|
||||
if 'data' in result:
|
||||
return result["data"]["AVAILABLEHOSTLUNIDLIST"]
|
||||
|
||||
def get_metrogroup_by_name(self, name):
|
||||
url = "/HyperMetro_ConsistentGroup?type='15364'"
|
||||
result = self.call(url, None, "GET")
|
||||
|
||||
msg = _('Get hypermetro group by name error.')
|
||||
self._assert_rest_result(result, msg)
|
||||
return self._get_id_from_result(result, name, 'NAME')
|
||||
|
||||
def get_metrogroup_by_id(self, id):
|
||||
url = "/HyperMetro_ConsistentGroup/" + id
|
||||
result = self.call(url, None, "GET")
|
||||
|
||||
msg = _('Get hypermetro group by id error.')
|
||||
self._assert_rest_result(result, msg)
|
||||
self._assert_data_in_result(result, msg)
|
||||
return result['data']
|
||||
|
||||
def create_metrogroup(self, name, description, domain_id):
|
||||
url = "/HyperMetro_ConsistentGroup"
|
||||
data = {"NAME": name,
|
||||
"TYPE": "15364",
|
||||
"DESCRIPTION": description,
|
||||
"RECOVERYPOLICY": "1",
|
||||
"SPEED": "2",
|
||||
"PRIORITYSTATIONTYPE": "0",
|
||||
"DOMAINID": domain_id}
|
||||
result = self.call(url, data, "POST")
|
||||
|
||||
msg = _('create hypermetro group error.')
|
||||
self._assert_rest_result(result, msg)
|
||||
if 'data' in result:
|
||||
return result["data"]["ID"]
|
||||
|
||||
def delete_metrogroup(self, metrogroup_id):
|
||||
url = "/HyperMetro_ConsistentGroup/" + metrogroup_id
|
||||
result = self.call(url, None, "DELETE")
|
||||
|
||||
msg = _('Delete hypermetro group error.')
|
||||
self._assert_rest_result(result, msg)
|
||||
|
||||
def get_metrogroup(self, metrogroup_id):
|
||||
url = "/HyperMetro_ConsistentGroup/" + metrogroup_id
|
||||
result = self.call(url, None, "GET")
|
||||
|
||||
msg = _('Get hypermetro group error.')
|
||||
self._assert_rest_result(result, msg)
|
||||
|
||||
def stop_metrogroup(self, metrogroup_id):
|
||||
url = "/HyperMetro_ConsistentGroup/stop"
|
||||
data = {"TYPE": "15364",
|
||||
"ID": metrogroup_id
|
||||
}
|
||||
result = self.call(url, data, "PUT")
|
||||
|
||||
msg = _('stop hypermetro group error.')
|
||||
self._assert_rest_result(result, msg)
|
||||
|
||||
def sync_metrogroup(self, metrogroup_id):
|
||||
url = "/HyperMetro_ConsistentGroup/sync"
|
||||
data = {"TYPE": "15364",
|
||||
"ID": metrogroup_id
|
||||
}
|
||||
result = self.call(url, data, "PUT")
|
||||
|
||||
msg = _('sync hypermetro group error.')
|
||||
self._assert_rest_result(result, msg)
|
||||
|
||||
def add_metro_to_metrogroup(self, metrogroup_id, metro_id):
|
||||
url = "/hyperMetro/associate/pair"
|
||||
data = {"TYPE": "15364",
|
||||
"ID": metrogroup_id,
|
||||
"ASSOCIATEOBJTYPE": "15361",
|
||||
"ASSOCIATEOBJID": metro_id}
|
||||
result = self.call(url, data, "POST")
|
||||
|
||||
msg = _('Add hypermetro to metrogroup error.')
|
||||
self._assert_rest_result(result, msg)
|
||||
|
||||
def remove_metro_from_metrogroup(self, metrogroup_id, metro_id):
|
||||
url = "/hyperMetro/associate/pair"
|
||||
data = {"TYPE": "15364",
|
||||
"ID": metrogroup_id,
|
||||
"ASSOCIATEOBJTYPE": "15361",
|
||||
"ASSOCIATEOBJID": metro_id}
|
||||
result = self.call(url, data, "DELETE")
|
||||
|
||||
msg = _('Delete hypermetro from metrogroup error.')
|
||||
self._assert_rest_result(result, msg)
|
||||
|
||||
def get_hypermetro_pairs(self):
|
||||
url = "/HyperMetroPair?range=[0-65535]"
|
||||
url = "/HyperMetroPair?range=[0-4095]"
|
||||
result = self.call(url, None, "GET")
|
||||
msg = _('Get HyperMetroPair error.')
|
||||
self._assert_rest_result(result, msg)
|
||||
@ -1945,7 +2038,7 @@ class RestClient(object):
|
||||
return result.get('data', [])
|
||||
|
||||
def get_split_mirrors(self):
|
||||
url = "/splitmirror?range=[0-512]"
|
||||
url = "/splitmirror?range=[0-8191]"
|
||||
result = self.call(url, None, "GET")
|
||||
if result['error']['code'] == constants.NO_SPLITMIRROR_LICENSE:
|
||||
msg = _('License is unavailable.')
|
||||
|
@ -0,0 +1,3 @@
|
||||
---
|
||||
features:
|
||||
- Added consistency group support to the Huawei driver.
|
Loading…
Reference in New Issue
Block a user