NetApp: Improve REST API cover and fix internals
Improve coverage of REST API feature merged in stable 2023.1. Fix Netapp internals tests partially-implements: bp netapp-ontap-rest-api-client Co-authored-by: Caique Mello <caiquemellosbo@gmail.com> Co-authored-by: Helena Dantas <helenamylena@gmail.com> Co-authored-by: Lucas Oliveira <lucasmoliveira059@gmail.com> Co-authored-by: Matheus Andrade <matheus.andrade@netapp.com> Co-authored-by: Renan Vitor <renanpiranguinho@gmail.com> Change-Id: Ia5fe1834cc6643d5df0a25f9f4a074911d8ad550
This commit is contained in:
parent
afd0d723bb
commit
b4cc96d5fd
@ -2180,6 +2180,8 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
|||||||
raise exception.NetAppException(msg)
|
raise exception.NetAppException(msg)
|
||||||
else:
|
else:
|
||||||
api_args['encrypt'] = 'true'
|
api_args['encrypt'] = 'true'
|
||||||
|
else:
|
||||||
|
api_args['encrypt'] = 'false'
|
||||||
|
|
||||||
return api_args
|
return api_args
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
import copy
|
import copy
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from http import client as http_client
|
from http import client as http_client
|
||||||
|
import math
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@ -276,11 +277,12 @@ class NetAppRestClient(object):
|
|||||||
|
|
||||||
# NOTE(nahimsouza): SVM scoped account is not authorized to access
|
# NOTE(nahimsouza): SVM scoped account is not authorized to access
|
||||||
# the /cluster/nodes endpoint, that's why we use /private/cli
|
# the /cluster/nodes endpoint, that's why we use /private/cli
|
||||||
|
|
||||||
response = self.send_request('/private/cli/version', 'get',
|
response = self.send_request('/private/cli/version', 'get',
|
||||||
query=query)
|
query=query)
|
||||||
# Response is formatted as:
|
# Response is formatted as:
|
||||||
# 'NetApp Release 9.12.1: Wed Feb 01 01:10:18 UTC 2023'
|
# 'NetApp Release 9.12.1: Wed Feb 01 01:10:18 UTC 2023'
|
||||||
version_full = response['records'][0]['version']
|
version_full = response['records'][0]['version']['full']
|
||||||
version_parsed = re.findall(r'\d+\.\d+\.\d+', version_full)[0]
|
version_parsed = re.findall(r'\d+\.\d+\.\d+', version_full)[0]
|
||||||
version_splited = version_parsed.split('.')
|
version_splited = version_parsed.split('.')
|
||||||
return {
|
return {
|
||||||
@ -707,8 +709,16 @@ class NetAppRestClient(object):
|
|||||||
'svm.name': vserver,
|
'svm.name': vserver,
|
||||||
}
|
}
|
||||||
if max_throughput:
|
if max_throughput:
|
||||||
body['fixed.max_throughput_iops'] = (
|
value = max_throughput.lower()
|
||||||
int(''.join(filter(str.isdigit, max_throughput))))
|
if 'iops' in max_throughput:
|
||||||
|
value = value.replace('iops', '')
|
||||||
|
value = int(value)
|
||||||
|
body['fixed.max_throughput_iops'] = value
|
||||||
|
else:
|
||||||
|
value = value.replace('b/s', '')
|
||||||
|
value = int(value)
|
||||||
|
body['fixed.max_throughput_mbps'] = math.ceil(value /
|
||||||
|
units.Mi)
|
||||||
return self.send_request('/storage/qos/policies', 'post',
|
return self.send_request('/storage/qos/policies', 'post',
|
||||||
body=body)
|
body=body)
|
||||||
|
|
||||||
@ -775,7 +785,16 @@ class NetAppRestClient(object):
|
|||||||
"""Set NFS the export policy for the specified volume."""
|
"""Set NFS the export policy for the specified volume."""
|
||||||
query = {"name": volume_name}
|
query = {"name": volume_name}
|
||||||
body = {'nas.export_policy.name': policy_name}
|
body = {'nas.export_policy.name': policy_name}
|
||||||
self.send_request('/storage/volumes/', 'patch', query=query, body=body)
|
|
||||||
|
try:
|
||||||
|
self.send_request('/storage/volumes/', 'patch', query=query,
|
||||||
|
body=body)
|
||||||
|
except netapp_api.api.NaApiError as e:
|
||||||
|
# NOTE(nahimsouza): Since this error is ignored in ZAPI, we are
|
||||||
|
# replicating the behavior here.
|
||||||
|
if e.code == netapp_api.EREST_CANNOT_MODITY_OFFLINE_VOLUME:
|
||||||
|
LOG.debug('Cannot modify offline volume: %s', volume_name)
|
||||||
|
return
|
||||||
|
|
||||||
@na_utils.trace
|
@na_utils.trace
|
||||||
def create_nfs_export_policy(self, policy_name):
|
def create_nfs_export_policy(self, policy_name):
|
||||||
@ -862,15 +881,15 @@ class NetAppRestClient(object):
|
|||||||
volume = {
|
volume = {
|
||||||
'aggregate': aggregate,
|
'aggregate': aggregate,
|
||||||
'aggr-list': aggregate_list,
|
'aggr-list': aggregate_list,
|
||||||
'junction-path': volume_infos.get('nas', {}).get('path', ''),
|
'junction-path': volume_infos.get('nas', {}).get('path'),
|
||||||
'name': volume_infos.get('name', ''),
|
'name': volume_infos.get('name'),
|
||||||
'owning-vserver-name': volume_infos.get('svm', {}).get('name', ''),
|
'owning-vserver-name': volume_infos.get('svm', {}).get('name'),
|
||||||
'type': volume_infos.get('type', ''),
|
'type': volume_infos.get('type'),
|
||||||
'style': volume_infos.get('style', ''),
|
'style': volume_infos.get('style'),
|
||||||
'size': volume_infos.get('space', {}).get('size', ''),
|
'size': volume_infos.get('space', {}).get('size'),
|
||||||
'qos-policy-group-name': (
|
'qos-policy-group-name': (
|
||||||
volume_infos.get('qos', {}).get('policy', {}).get('name', '')),
|
volume_infos.get('qos', {}).get('policy', {}).get('name')),
|
||||||
'style-extended': volume_infos.get('style', '')
|
'style-extended': volume_infos.get('style')
|
||||||
}
|
}
|
||||||
return volume
|
return volume
|
||||||
|
|
||||||
@ -887,12 +906,11 @@ class NetAppRestClient(object):
|
|||||||
return self._has_records(result)
|
return self._has_records(result)
|
||||||
|
|
||||||
@na_utils.trace
|
@na_utils.trace
|
||||||
def create_cifs_share(self, share_name):
|
def create_cifs_share(self, share_name, path):
|
||||||
"""Create a CIFS share."""
|
"""Create a CIFS share."""
|
||||||
share_path = f'/{share_name}'
|
|
||||||
body = {
|
body = {
|
||||||
'name': share_name,
|
'name': share_name,
|
||||||
'path': share_path,
|
'path': path,
|
||||||
'svm.name': self.vserver,
|
'svm.name': self.vserver,
|
||||||
}
|
}
|
||||||
self.send_request('/protocols/cifs/shares', 'post', body=body)
|
self.send_request('/protocols/cifs/shares', 'post', body=body)
|
||||||
@ -1025,8 +1043,15 @@ class NetAppRestClient(object):
|
|||||||
body['qos.policy.name'] = qos_policy_group
|
body['qos.policy.name'] = qos_policy_group
|
||||||
if adaptive_qos_policy_group is not None:
|
if adaptive_qos_policy_group is not None:
|
||||||
body['qos.policy.name'] = adaptive_qos_policy_group
|
body['qos.policy.name'] = adaptive_qos_policy_group
|
||||||
|
|
||||||
if encrypt is True:
|
if encrypt is True:
|
||||||
|
if not self.features.FLEXVOL_ENCRYPTION:
|
||||||
|
msg = 'Flexvol encryption is not supported on this backend.'
|
||||||
|
raise exception.NetAppException(msg)
|
||||||
|
else:
|
||||||
body['encryption.enabled'] = 'true'
|
body['encryption.enabled'] = 'true'
|
||||||
|
else:
|
||||||
|
body['encryption.enabled'] = 'false'
|
||||||
|
|
||||||
return body
|
return body
|
||||||
|
|
||||||
@ -1166,7 +1191,14 @@ class NetAppRestClient(object):
|
|||||||
@na_utils.trace
|
@na_utils.trace
|
||||||
def set_volume_snapdir_access(self, volume_name, hide_snapdir):
|
def set_volume_snapdir_access(self, volume_name, hide_snapdir):
|
||||||
"""Set volume snapshot directory visibility."""
|
"""Set volume snapshot directory visibility."""
|
||||||
|
|
||||||
|
try:
|
||||||
volume = self._get_volume_by_args(vol_name=volume_name)
|
volume = self._get_volume_by_args(vol_name=volume_name)
|
||||||
|
except exception.NetAppException:
|
||||||
|
msg = _('Could not find volume %s to set snapdir access')
|
||||||
|
LOG.error(msg, volume_name)
|
||||||
|
raise exception.SnapshotResourceNotFound(name=volume_name)
|
||||||
|
|
||||||
uuid = volume['uuid']
|
uuid = volume['uuid']
|
||||||
|
|
||||||
body = {
|
body = {
|
||||||
@ -1194,6 +1226,7 @@ class NetAppRestClient(object):
|
|||||||
try:
|
try:
|
||||||
volume = self._get_volume_by_args(vol_name=share_name)
|
volume = self._get_volume_by_args(vol_name=share_name)
|
||||||
svm_uuid = volume['svm']['uuid']
|
svm_uuid = volume['svm']['uuid']
|
||||||
|
|
||||||
except exception.NetAppException:
|
except exception.NetAppException:
|
||||||
LOG.debug('Could not find fpolicy. Share not found: %s.',
|
LOG.debug('Could not find fpolicy. Share not found: %s.',
|
||||||
share_name)
|
share_name)
|
||||||
@ -1392,7 +1425,7 @@ class NetAppRestClient(object):
|
|||||||
except exception.NetAppException:
|
except exception.NetAppException:
|
||||||
msg = _("FPolicy event %s not found.")
|
msg = _("FPolicy event %s not found.")
|
||||||
LOG.debug(msg, event_name)
|
LOG.debug(msg, event_name)
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
self.send_request(
|
self.send_request(
|
||||||
f'/protocols/fpolicy/{svm_uuid}/events/{event_name}', 'delete')
|
f'/protocols/fpolicy/{svm_uuid}/events/{event_name}', 'delete')
|
||||||
@ -1415,7 +1448,7 @@ class NetAppRestClient(object):
|
|||||||
except exception.NetAppException:
|
except exception.NetAppException:
|
||||||
msg = _("FPolicy policy %s not found.")
|
msg = _("FPolicy policy %s not found.")
|
||||||
LOG.debug(msg, policy_name)
|
LOG.debug(msg, policy_name)
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
self.send_request(
|
self.send_request(
|
||||||
f'/protocols/fpolicy/{svm_uuid}/policies/{policy_name}',
|
f'/protocols/fpolicy/{svm_uuid}/policies/{policy_name}',
|
||||||
@ -1593,9 +1626,7 @@ class NetAppRestClient(object):
|
|||||||
LOG.debug('Volume %s unmounted.', volume_name)
|
LOG.debug('Volume %s unmounted.', volume_name)
|
||||||
return
|
return
|
||||||
except netapp_api.api.NaApiError as e:
|
except netapp_api.api.NaApiError as e:
|
||||||
# TODO(felipe_rodrigues): test the clone split mount error
|
if (e.code == netapp_api.EREST_UNMOUNT_FAILED_LOCK
|
||||||
# code for REST.
|
|
||||||
if (e.code == netapp_api.api.EAPIERROR
|
|
||||||
and 'job ID' in e.message):
|
and 'job ID' in e.message):
|
||||||
msg = ('Could not unmount volume %(volume)s due to '
|
msg = ('Could not unmount volume %(volume)s due to '
|
||||||
'ongoing volume operation: %(exception)s')
|
'ongoing volume operation: %(exception)s')
|
||||||
@ -1637,7 +1668,8 @@ class NetAppRestClient(object):
|
|||||||
|
|
||||||
query = {
|
query = {
|
||||||
'name': qos_policy_group_name,
|
'name': qos_policy_group_name,
|
||||||
'fields': 'name,object_count,fixed.max_throughput_iops,svm.name',
|
'fields': 'name,object_count,fixed.max_throughput_iops,'
|
||||||
|
'fixed.max_throughput_mbps,svm.name',
|
||||||
}
|
}
|
||||||
try:
|
try:
|
||||||
res = self.send_request('/storage/qos/policies', 'get',
|
res = self.send_request('/storage/qos/policies', 'get',
|
||||||
@ -1659,10 +1691,21 @@ class NetAppRestClient(object):
|
|||||||
policy_info = {
|
policy_info = {
|
||||||
'policy-group': qos_policy_group_info.get('name'),
|
'policy-group': qos_policy_group_info.get('name'),
|
||||||
'vserver': qos_policy_group_info.get('svm', {}).get('name'),
|
'vserver': qos_policy_group_info.get('svm', {}).get('name'),
|
||||||
'max-throughput': qos_policy_group_info.get('fixed', {}).get(
|
|
||||||
'max_throughput_iops'),
|
|
||||||
'num-workloads': int(qos_policy_group_info.get('object_count')),
|
'num-workloads': int(qos_policy_group_info.get('object_count')),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iops = qos_policy_group_info.get('fixed', {}).get(
|
||||||
|
'max_throughput_iops')
|
||||||
|
mbps = qos_policy_group_info.get('fixed', {}).get(
|
||||||
|
'max_throughput_mbps')
|
||||||
|
|
||||||
|
if iops:
|
||||||
|
policy_info['max-throughput'] = f'{iops}iops'
|
||||||
|
elif mbps:
|
||||||
|
policy_info['max-throughput'] = f'{mbps * 1024 * 1024}b/s'
|
||||||
|
else:
|
||||||
|
policy_info['max-throughput'] = None
|
||||||
|
|
||||||
return policy_info
|
return policy_info
|
||||||
|
|
||||||
@na_utils.trace
|
@na_utils.trace
|
||||||
@ -1734,13 +1777,6 @@ class NetAppRestClient(object):
|
|||||||
# Attempt to delete any QoS policies named "deleted_manila-*".
|
# Attempt to delete any QoS policies named "deleted_manila-*".
|
||||||
self.remove_unused_qos_policy_groups()
|
self.remove_unused_qos_policy_groups()
|
||||||
|
|
||||||
@na_utils.trace
|
|
||||||
def _sanitize_qos_spec_value(self, value):
|
|
||||||
value = value.lower()
|
|
||||||
value = value.replace('iops', '').replace('b/s', '')
|
|
||||||
value = int(value)
|
|
||||||
return value
|
|
||||||
|
|
||||||
@na_utils.trace
|
@na_utils.trace
|
||||||
def qos_policy_group_modify(self, qos_policy_group_name, max_throughput):
|
def qos_policy_group_modify(self, qos_policy_group_name, max_throughput):
|
||||||
"""Modifies a QoS policy group."""
|
"""Modifies a QoS policy group."""
|
||||||
@ -1748,10 +1784,19 @@ class NetAppRestClient(object):
|
|||||||
query = {
|
query = {
|
||||||
'name': qos_policy_group_name,
|
'name': qos_policy_group_name,
|
||||||
}
|
}
|
||||||
body = {
|
body = {}
|
||||||
'fixed.max_throughput_iops':
|
value = max_throughput.lower()
|
||||||
self._sanitize_qos_spec_value(max_throughput)
|
if 'iops' in value:
|
||||||
}
|
value = value.replace('iops', '')
|
||||||
|
value = int(value)
|
||||||
|
body['fixed.max_throughput_iops'] = value
|
||||||
|
body['fixed.max_throughput_mbps'] = 0
|
||||||
|
elif 'b/s' in value:
|
||||||
|
value = value.replace('b/s', '')
|
||||||
|
value = int(value)
|
||||||
|
body['fixed.max_throughput_mbps'] = math.ceil(value /
|
||||||
|
units.Mi)
|
||||||
|
body['fixed.max_throughput_iops'] = 0
|
||||||
res = self.send_request('/storage/qos/policies', 'get', query=query)
|
res = self.send_request('/storage/qos/policies', 'get', query=query)
|
||||||
if not res.get('records'):
|
if not res.get('records'):
|
||||||
msg = ('QoS %s not found.') % qos_policy_group_name
|
msg = ('QoS %s not found.') % qos_policy_group_name
|
||||||
@ -1839,8 +1884,13 @@ class NetAppRestClient(object):
|
|||||||
@na_utils.trace
|
@na_utils.trace
|
||||||
def get_snapshot(self, volume_name, snapshot_name):
|
def get_snapshot(self, volume_name, snapshot_name):
|
||||||
"""Gets a single snapshot."""
|
"""Gets a single snapshot."""
|
||||||
|
try:
|
||||||
volume = self._get_volume_by_args(vol_name=volume_name)
|
volume = self._get_volume_by_args(vol_name=volume_name)
|
||||||
|
except exception.NetAppException:
|
||||||
|
msg = _('Could not find volume %s to get snapshot')
|
||||||
|
LOG.error(msg, volume_name)
|
||||||
|
raise exception.SnapshotResourceNotFound(name=snapshot_name)
|
||||||
|
|
||||||
uuid = volume['uuid']
|
uuid = volume['uuid']
|
||||||
query = {
|
query = {
|
||||||
'name': snapshot_name,
|
'name': snapshot_name,
|
||||||
@ -1902,7 +1952,12 @@ class NetAppRestClient(object):
|
|||||||
def delete_snapshot(self, volume_name, snapshot_name, ignore_owners=False):
|
def delete_snapshot(self, volume_name, snapshot_name, ignore_owners=False):
|
||||||
"""Deletes a volume snapshot."""
|
"""Deletes a volume snapshot."""
|
||||||
|
|
||||||
|
try:
|
||||||
volume = self._get_volume_by_args(vol_name=volume_name)
|
volume = self._get_volume_by_args(vol_name=volume_name)
|
||||||
|
except exception.NetAppException:
|
||||||
|
msg = _('Could not find volume %s to delete snapshot')
|
||||||
|
LOG.warning(msg, volume_name)
|
||||||
|
return
|
||||||
uuid = volume['uuid']
|
uuid = volume['uuid']
|
||||||
|
|
||||||
query = {
|
query = {
|
||||||
@ -2118,15 +2173,15 @@ class NetAppRestClient(object):
|
|||||||
|
|
||||||
aggregate = res.get('aggregates')
|
aggregate = res.get('aggregates')
|
||||||
|
|
||||||
|
if not aggregate:
|
||||||
|
msg = _('Could not find aggregate for volume %s.')
|
||||||
|
raise exception.NetAppException(msg % volume_name)
|
||||||
|
|
||||||
aggregate_size = len(res.get('aggregates'))
|
aggregate_size = len(res.get('aggregates'))
|
||||||
|
|
||||||
if aggregate_size > 1:
|
if aggregate_size > 1:
|
||||||
aggregate = [aggr.get('name') for aggr in res.get('aggregates')]
|
aggregate = [aggr.get('name') for aggr in res.get('aggregates')]
|
||||||
|
|
||||||
if not aggregate:
|
|
||||||
msg = _('Could not find aggregate for volume %s.')
|
|
||||||
raise exception.NetAppException(msg % volume_name)
|
|
||||||
|
|
||||||
return aggregate
|
return aggregate
|
||||||
|
|
||||||
@na_utils.trace
|
@na_utils.trace
|
||||||
@ -2193,7 +2248,7 @@ class NetAppRestClient(object):
|
|||||||
fields = ['state', 'source.svm.name', 'source.path',
|
fields = ['state', 'source.svm.name', 'source.path',
|
||||||
'destination.svm.name', 'destination.path',
|
'destination.svm.name', 'destination.path',
|
||||||
'transfer.end_time', 'uuid', 'policy.type',
|
'transfer.end_time', 'uuid', 'policy.type',
|
||||||
'transfer_schedule.name']
|
'transfer_schedule.name', 'transfer.state']
|
||||||
|
|
||||||
query = {}
|
query = {}
|
||||||
query['fields'] = ','.join(fields)
|
query['fields'] = ','.join(fields)
|
||||||
@ -2222,7 +2277,11 @@ class NetAppRestClient(object):
|
|||||||
snapmirrors = []
|
snapmirrors = []
|
||||||
for record in response.get('records', []):
|
for record in response.get('records', []):
|
||||||
snapmirrors.append({
|
snapmirrors.append({
|
||||||
'relationship-status': record.get('state'),
|
'relationship-status': (
|
||||||
|
'idle'
|
||||||
|
if record.get('state') == 'snapmirrored'
|
||||||
|
else record.get('state')),
|
||||||
|
'transferring-state': record.get('transfer', {}).get('state'),
|
||||||
'mirror-state': record.get('state'),
|
'mirror-state': record.get('state'),
|
||||||
'schedule': record['transfer_schedule']['name'],
|
'schedule': record['transfer_schedule']['name'],
|
||||||
'source-vserver': record['source']['svm']['name'],
|
'source-vserver': record['source']['svm']['name'],
|
||||||
@ -2255,7 +2314,8 @@ class NetAppRestClient(object):
|
|||||||
def get_snapmirrors(self, source_path=None, dest_path=None,
|
def get_snapmirrors(self, source_path=None, dest_path=None,
|
||||||
source_vserver=None, dest_vserver=None,
|
source_vserver=None, dest_vserver=None,
|
||||||
source_volume=None, dest_volume=None,
|
source_volume=None, dest_volume=None,
|
||||||
desired_attributes=None):
|
desired_attributes=None, enable_tunneling=None,
|
||||||
|
list_destinations_only=None):
|
||||||
"""Gets one or more SnapMirror relationships.
|
"""Gets one or more SnapMirror relationships.
|
||||||
|
|
||||||
Either the source or destination info may be omitted.
|
Either the source or destination info may be omitted.
|
||||||
@ -2269,7 +2329,9 @@ class NetAppRestClient(object):
|
|||||||
source_vserver=source_vserver,
|
source_vserver=source_vserver,
|
||||||
source_volume=source_volume,
|
source_volume=source_volume,
|
||||||
dest_vserver=dest_vserver,
|
dest_vserver=dest_vserver,
|
||||||
dest_volume=dest_volume)
|
dest_volume=dest_volume,
|
||||||
|
enable_tunneling=enable_tunneling,
|
||||||
|
list_destinations_only=list_destinations_only)
|
||||||
|
|
||||||
return snapmirrors
|
return snapmirrors
|
||||||
|
|
||||||
@ -2752,7 +2814,7 @@ class NetAppRestClient(object):
|
|||||||
clear_checkpoint=False):
|
clear_checkpoint=False):
|
||||||
"""Stops ongoing transfers for a SnapMirror relationship."""
|
"""Stops ongoing transfers for a SnapMirror relationship."""
|
||||||
|
|
||||||
snapmirror = self._get_snapmirrors(
|
snapmirror = self.get_snapmirrors(
|
||||||
source_path=source_path,
|
source_path=source_path,
|
||||||
dest_path=dest_path,
|
dest_path=dest_path,
|
||||||
source_vserver=source_vserver,
|
source_vserver=source_vserver,
|
||||||
@ -2817,10 +2879,11 @@ class NetAppRestClient(object):
|
|||||||
def get_snapmirror_destinations(self, source_path=None, dest_path=None,
|
def get_snapmirror_destinations(self, source_path=None, dest_path=None,
|
||||||
source_vserver=None, source_volume=None,
|
source_vserver=None, source_volume=None,
|
||||||
dest_vserver=None, dest_volume=None,
|
dest_vserver=None, dest_volume=None,
|
||||||
desired_attributes=None):
|
desired_attributes=None,
|
||||||
|
enable_tunneling=None):
|
||||||
"""Gets one or more SnapMirror at source endpoint."""
|
"""Gets one or more SnapMirror at source endpoint."""
|
||||||
|
|
||||||
snapmirrors = self._get_snapmirrors(
|
snapmirrors = self.get_snapmirrors(
|
||||||
source_path=source_path,
|
source_path=source_path,
|
||||||
dest_path=dest_path,
|
dest_path=dest_path,
|
||||||
source_vserver=source_vserver,
|
source_vserver=source_vserver,
|
||||||
@ -2964,9 +3027,12 @@ class NetAppRestClient(object):
|
|||||||
wait_result=True, schedule=None):
|
wait_result=True, schedule=None):
|
||||||
"""Change the snapmirror state between two volumes."""
|
"""Change the snapmirror state between two volumes."""
|
||||||
|
|
||||||
snapmirror = self.get_snapmirrors(source_path, destination_path,
|
snapmirror = self.get_snapmirrors(source_path=source_path,
|
||||||
source_vserver, destination_vserver,
|
dest_path=destination_path,
|
||||||
source_volume, destination_volume)
|
source_vserver=source_vserver,
|
||||||
|
source_volume=source_volume,
|
||||||
|
dest_vserver=destination_vserver,
|
||||||
|
dest_volume=destination_volume)
|
||||||
|
|
||||||
if not snapmirror:
|
if not snapmirror:
|
||||||
msg = _('Failed to get information about relationship between '
|
msg = _('Failed to get information about relationship between '
|
||||||
@ -3069,11 +3135,19 @@ class NetAppRestClient(object):
|
|||||||
'clone.is_flexclone': 'true',
|
'clone.is_flexclone': 'true',
|
||||||
'svm.name': self.connection.get_vserver(),
|
'svm.name': self.connection.get_vserver(),
|
||||||
}
|
}
|
||||||
if qos_policy_group is not None:
|
|
||||||
body['qos.policy.name'] = qos_policy_group
|
|
||||||
|
|
||||||
self.send_request('/storage/volumes', 'post', body=body)
|
self.send_request('/storage/volumes', 'post', body=body)
|
||||||
|
|
||||||
|
# NOTE(nahimsouza): QoS policy can not be set during the cloning
|
||||||
|
# process, so we need to make a separate request.
|
||||||
|
if qos_policy_group is not None:
|
||||||
|
volume = self._get_volume_by_args(vol_name=volume_name)
|
||||||
|
uuid = volume['uuid']
|
||||||
|
body = {
|
||||||
|
'qos.policy.name': qos_policy_group,
|
||||||
|
}
|
||||||
|
self.send_request(f'/storage/volumes/{uuid}', 'patch', body=body)
|
||||||
|
|
||||||
if split:
|
if split:
|
||||||
self.split_volume_clone(volume_name)
|
self.split_volume_clone(volume_name)
|
||||||
|
|
||||||
@ -3096,7 +3170,7 @@ class NetAppRestClient(object):
|
|||||||
source_volume=None, dest_volume=None):
|
source_volume=None, dest_volume=None):
|
||||||
"""Disables future transfers to a SnapMirror destination."""
|
"""Disables future transfers to a SnapMirror destination."""
|
||||||
|
|
||||||
snapmirror = self._get_snapmirrors(
|
snapmirror = self.get_snapmirrors(
|
||||||
source_path=source_path,
|
source_path=source_path,
|
||||||
dest_path=dest_path,
|
dest_path=dest_path,
|
||||||
source_vserver=source_vserver,
|
source_vserver=source_vserver,
|
||||||
@ -3126,7 +3200,13 @@ class NetAppRestClient(object):
|
|||||||
source_volume=None, dest_volume=None):
|
source_volume=None, dest_volume=None):
|
||||||
"""Breaks a data protection SnapMirror relationship."""
|
"""Breaks a data protection SnapMirror relationship."""
|
||||||
|
|
||||||
snapmirror = self._get_snapmirrors(
|
interval = 2
|
||||||
|
retries = (10 / interval)
|
||||||
|
|
||||||
|
@utils.retry(netapp_api.NaRetryableError, interval=interval,
|
||||||
|
retries=retries, backoff_rate=1)
|
||||||
|
def _waiter():
|
||||||
|
snapmirror = self.get_snapmirrors(
|
||||||
source_path=source_path,
|
source_path=source_path,
|
||||||
dest_path=dest_path,
|
dest_path=dest_path,
|
||||||
source_vserver=source_vserver,
|
source_vserver=source_vserver,
|
||||||
@ -3134,17 +3214,24 @@ class NetAppRestClient(object):
|
|||||||
dest_vserver=dest_vserver,
|
dest_vserver=dest_vserver,
|
||||||
dest_volume=dest_volume)
|
dest_volume=dest_volume)
|
||||||
|
|
||||||
if snapmirror:
|
snapmirror_state = snapmirror[0].get('transferring-state')
|
||||||
|
if snapmirror_state == 'success':
|
||||||
uuid = snapmirror[0]['uuid']
|
uuid = snapmirror[0]['uuid']
|
||||||
body = {'state': 'broken_off'}
|
body = {'state': 'broken_off'}
|
||||||
try:
|
|
||||||
self.send_request(f'/snapmirror/relationships/{uuid}', 'patch',
|
self.send_request(f'/snapmirror/relationships/{uuid}', 'patch',
|
||||||
body=body)
|
body=body)
|
||||||
except netapp_api.api.NaApiError as e:
|
return
|
||||||
transfer_in_progress = 'Another transfer is in progress'
|
else:
|
||||||
if not (e.code == netapp_api.EREST_BREAK_SNAPMIRROR_FAILED
|
message = 'Waiting for transfer state to be SUCCESS.'
|
||||||
and transfer_in_progress in e.message):
|
code = ''
|
||||||
raise
|
raise netapp_api.NaRetryableError(message=message, code=code)
|
||||||
|
|
||||||
|
try:
|
||||||
|
return _waiter()
|
||||||
|
except netapp_api.NaRetryableError:
|
||||||
|
msg = _("Transfer state did not reach the expected state. Retries "
|
||||||
|
"exhausted. Aborting.")
|
||||||
|
raise na_utils.NetAppDriverException(msg)
|
||||||
|
|
||||||
@na_utils.trace
|
@na_utils.trace
|
||||||
def resume_snapmirror_vol(self, source_vserver, source_volume,
|
def resume_snapmirror_vol(self, source_vserver, source_volume,
|
||||||
@ -3169,9 +3256,12 @@ class NetAppRestClient(object):
|
|||||||
source_vserver=None, dest_vserver=None,
|
source_vserver=None, dest_vserver=None,
|
||||||
source_volume=None, dest_volume=None):
|
source_volume=None, dest_volume=None):
|
||||||
"""Resume a SnapMirror relationship if it is quiesced."""
|
"""Resume a SnapMirror relationship if it is quiesced."""
|
||||||
response = self._get_snapmirrors(source_path, dest_path,
|
response = self.get_snapmirrors(source_path=source_path,
|
||||||
source_vserver, source_volume,
|
dest_path=dest_path,
|
||||||
dest_vserver, dest_volume)
|
source_vserver=source_vserver,
|
||||||
|
dest_vserver=dest_vserver,
|
||||||
|
source_volume=source_volume,
|
||||||
|
dest_volume=dest_volume)
|
||||||
|
|
||||||
if not response:
|
if not response:
|
||||||
# NOTE(nahimsouza): As ZAPI returns this error code, it was kept
|
# NOTE(nahimsouza): As ZAPI returns this error code, it was kept
|
||||||
@ -3247,9 +3337,12 @@ class NetAppRestClient(object):
|
|||||||
source_vserver=None, dest_vserver=None,
|
source_vserver=None, dest_vserver=None,
|
||||||
source_volume=None, dest_volume=None):
|
source_volume=None, dest_volume=None):
|
||||||
"""Update a snapmirror relationship asynchronously."""
|
"""Update a snapmirror relationship asynchronously."""
|
||||||
snapmirrors = self._get_snapmirrors(source_path, dest_path,
|
snapmirrors = self.get_snapmirrors(source_path=source_path,
|
||||||
source_vserver, source_volume,
|
dest_path=dest_path,
|
||||||
dest_vserver, dest_volume)
|
source_vserver=source_vserver,
|
||||||
|
dest_vserver=dest_vserver,
|
||||||
|
source_volume=source_volume,
|
||||||
|
dest_volume=dest_volume)
|
||||||
|
|
||||||
if not snapmirrors:
|
if not snapmirrors:
|
||||||
msg = _('Failed to get snapmirror relationship information')
|
msg = _('Failed to get snapmirror relationship information')
|
||||||
@ -3578,13 +3671,13 @@ class NetAppRestClient(object):
|
|||||||
# response is empty. Also, REST API does not have an equivalent to
|
# response is empty. Also, REST API does not have an equivalent to
|
||||||
# 'udp-max-xfer-size', so the default is always returned.
|
# 'udp-max-xfer-size', so the default is always returned.
|
||||||
nfs_info = {
|
nfs_info = {
|
||||||
'tcp-max-xfer-size': DEFAULT_TCP_MAX_XFER_SIZE,
|
'tcp-max-xfer-size': str(DEFAULT_TCP_MAX_XFER_SIZE),
|
||||||
'udp-max-xfer-size': DEFAULT_UDP_MAX_XFER_SIZE,
|
'udp-max-xfer-size': str(DEFAULT_UDP_MAX_XFER_SIZE),
|
||||||
}
|
}
|
||||||
records = response.get('records', [])
|
records = response.get('records', [])
|
||||||
if records:
|
if records:
|
||||||
nfs_info['tcp-max-xfer-size'] = (
|
nfs_info['tcp-max-xfer-size'] = (
|
||||||
records[0]['transport']['tcp_max_transfer_size'])
|
str(records[0]['transport']['tcp_max_transfer_size']))
|
||||||
|
|
||||||
return nfs_info
|
return nfs_info
|
||||||
|
|
||||||
@ -4495,26 +4588,27 @@ class NetAppRestClient(object):
|
|||||||
@na_utils.trace
|
@na_utils.trace
|
||||||
def _configure_nfs(self, nfs_config, svm_id):
|
def _configure_nfs(self, nfs_config, svm_id):
|
||||||
"""Sets the nfs configuraton"""
|
"""Sets the nfs configuraton"""
|
||||||
|
|
||||||
|
if ('udp-max-xfer-size' in nfs_config and
|
||||||
|
(nfs_config['udp-max-xfer-size']
|
||||||
|
!= str(DEFAULT_UDP_MAX_XFER_SIZE))):
|
||||||
|
|
||||||
|
msg = _('Failed to configure NFS. REST API does not support '
|
||||||
|
'setting udp-max-xfer-size default value %(default)s '
|
||||||
|
'is not equal to actual value %(actual)s')
|
||||||
|
msg_args = {
|
||||||
|
'default': DEFAULT_UDP_MAX_XFER_SIZE,
|
||||||
|
'actual': nfs_config['udp-max-xfer-size'],
|
||||||
|
}
|
||||||
|
raise exception.NetAppException(msg % msg_args)
|
||||||
|
|
||||||
|
nfs_config_value = int(nfs_config['tcp-max-xfer-size'])
|
||||||
body = {
|
body = {
|
||||||
'transport.tcp_max_transfer_size': nfs_config['tcp-max-xfer-size']
|
'transport.tcp_max_transfer_size': nfs_config_value
|
||||||
}
|
}
|
||||||
self.send_request(f'/protocols/nfs/services/{svm_id}', 'patch',
|
self.send_request(f'/protocols/nfs/services/{svm_id}', 'patch',
|
||||||
body=body)
|
body=body)
|
||||||
|
|
||||||
@na_utils.trace
|
|
||||||
def _get_svm_uuid(self):
|
|
||||||
# Get SVM UUID.
|
|
||||||
query = {
|
|
||||||
'name': self.vserver,
|
|
||||||
'fields': 'uuid'
|
|
||||||
}
|
|
||||||
res = self.send_request('/svm/svms', 'get', query=query)
|
|
||||||
if not res.get('records'):
|
|
||||||
msg = _('Vserver %s not found.') % self.vserver
|
|
||||||
raise exception.NetAppException(msg)
|
|
||||||
svm_id = res.get('records')[0]['uuid']
|
|
||||||
return svm_id
|
|
||||||
|
|
||||||
@na_utils.trace
|
@na_utils.trace
|
||||||
def create_network_interface(self, ip, netmask, node, port,
|
def create_network_interface(self, ip, netmask, node, port,
|
||||||
vserver_name, lif_name):
|
vserver_name, lif_name):
|
||||||
@ -4665,8 +4759,8 @@ class NetAppRestClient(object):
|
|||||||
query['svm.name'] = vserver
|
query['svm.name'] = vserver
|
||||||
|
|
||||||
nfs_info = {
|
nfs_info = {
|
||||||
'tcp-max-xfer-size': DEFAULT_TCP_MAX_XFER_SIZE,
|
'tcp-max-xfer-size': str(DEFAULT_TCP_MAX_XFER_SIZE),
|
||||||
'udp-max-xfer-size': DEFAULT_UDP_MAX_XFER_SIZE,
|
'udp-max-xfer-size': str(DEFAULT_UDP_MAX_XFER_SIZE)
|
||||||
}
|
}
|
||||||
|
|
||||||
response = self.send_request('/protocols/nfs/services/',
|
response = self.send_request('/protocols/nfs/services/',
|
||||||
@ -4675,7 +4769,7 @@ class NetAppRestClient(object):
|
|||||||
|
|
||||||
if records:
|
if records:
|
||||||
nfs_info['tcp-max-xfer-size'] = (
|
nfs_info['tcp-max-xfer-size'] = (
|
||||||
records[0]['transport']['tcp_max_transfer_size'])
|
str(records[0]['transport']['tcp_max_transfer_size']))
|
||||||
|
|
||||||
return nfs_info
|
return nfs_info
|
||||||
|
|
||||||
@ -4878,7 +4972,7 @@ class NetAppRestClient(object):
|
|||||||
if e.code == netapp_api.EREST_ENTRY_NOT_FOUND:
|
if e.code == netapp_api.EREST_ENTRY_NOT_FOUND:
|
||||||
LOG.debug('VLAN %(vlan)s on port %(port)s node %(node)s '
|
LOG.debug('VLAN %(vlan)s on port %(port)s node %(node)s '
|
||||||
'was not found')
|
'was not found')
|
||||||
if (e.code == netapp_api.EREST_INTERFACE_BOUND or
|
elif (e.code == netapp_api.EREST_INTERFACE_BOUND or
|
||||||
e.code == netapp_api.EREST_PORT_IN_USE):
|
e.code == netapp_api.EREST_PORT_IN_USE):
|
||||||
LOG.debug('VLAN %(vlan)s on port %(port)s node %(node)s '
|
LOG.debug('VLAN %(vlan)s on port %(port)s node %(node)s '
|
||||||
'still used by LIF and cannot be deleted.',
|
'still used by LIF and cannot be deleted.',
|
||||||
|
@ -53,6 +53,8 @@ EREST_INTERFACE_BOUND = '1376858'
|
|||||||
EREST_PORT_IN_USE = '1966189'
|
EREST_PORT_IN_USE = '1966189'
|
||||||
EREST_NFS_V4_0_ENABLED_MIGRATION_FAILURE = '13172940'
|
EREST_NFS_V4_0_ENABLED_MIGRATION_FAILURE = '13172940'
|
||||||
EREST_VSERVER_MIGRATION_TO_NON_AFF_CLUSTER = '13172984'
|
EREST_VSERVER_MIGRATION_TO_NON_AFF_CLUSTER = '13172984'
|
||||||
|
EREST_UNMOUNT_FAILED_LOCK = '917536'
|
||||||
|
EREST_CANNOT_MODITY_OFFLINE_VOLUME = '917533'
|
||||||
|
|
||||||
|
|
||||||
class NaRetryableError(api.NaApiError):
|
class NaRetryableError(api.NaApiError):
|
||||||
|
@ -2634,9 +2634,11 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||||||
# NOTE(dviroel): Don't try to resume or resync a SnapMirror that has
|
# NOTE(dviroel): Don't try to resume or resync a SnapMirror that has
|
||||||
# one of the in progress transfer states, because the storage will
|
# one of the in progress transfer states, because the storage will
|
||||||
# answer with an error.
|
# answer with an error.
|
||||||
in_progress_status = ['preparing', 'transferring', 'finalizing']
|
in_progress_status = ['preparing', 'transferring', 'finalizing',
|
||||||
|
'synchronizing']
|
||||||
if (snapmirror.get('mirror-state') != 'snapmirrored' and
|
if (snapmirror.get('mirror-state') != 'snapmirrored' and
|
||||||
snapmirror.get('relationship-status') in in_progress_status):
|
(snapmirror.get('relationship-status') in in_progress_status or
|
||||||
|
snapmirror.get('transferring-state') in in_progress_status)):
|
||||||
return constants.REPLICA_STATE_OUT_OF_SYNC
|
return constants.REPLICA_STATE_OUT_OF_SYNC
|
||||||
|
|
||||||
if snapmirror.get('mirror-state') != 'snapmirrored':
|
if snapmirror.get('mirror-state') != 'snapmirrored':
|
||||||
|
@ -85,7 +85,9 @@ DELETED_EXPORT_POLICIES = {
|
|||||||
}
|
}
|
||||||
QOS_POLICY_GROUP_NAME = 'fake_qos_policy_group_name'
|
QOS_POLICY_GROUP_NAME = 'fake_qos_policy_group_name'
|
||||||
QOS_MAX_THROUGHPUT = '5000B/s'
|
QOS_MAX_THROUGHPUT = '5000B/s'
|
||||||
|
QOS_MAX_THROUGHPUT_IOPS = '5000iops'
|
||||||
QOS_MAX_THROUGHPUT_NO_UNIT = 5000
|
QOS_MAX_THROUGHPUT_NO_UNIT = 5000
|
||||||
|
QOS_MAX_THROUGHPUT_IOPS_NO_UNIT = 5000
|
||||||
ADAPTIVE_QOS_POLICY_GROUP_NAME = 'fake_adaptive_qos_policy_group_name'
|
ADAPTIVE_QOS_POLICY_GROUP_NAME = 'fake_adaptive_qos_policy_group_name'
|
||||||
VSERVER_TYPE_DEFAULT = 'default'
|
VSERVER_TYPE_DEFAULT = 'default'
|
||||||
VSERVER_TYPE_DP_DEST = 'dp_destination'
|
VSERVER_TYPE_DP_DEST = 'dp_destination'
|
||||||
@ -1028,7 +1030,28 @@ NFS_LIFS = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
NFS_LIFS_REST = [
|
NFS_LIFS_REST = [
|
||||||
{'uuid': FAKE_UUID,
|
{
|
||||||
|
'uuid': 'fake_uuid_1',
|
||||||
|
'address': IP_ADDRESS,
|
||||||
|
'home-node': NODE_NAME,
|
||||||
|
'home-port': VLAN_PORT,
|
||||||
|
'interface-name': LIF_NAME,
|
||||||
|
'netmask': NETMASK,
|
||||||
|
'role': 'data',
|
||||||
|
'vserver': VSERVER_NAME,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'uuid': 'fake_uuid_2',
|
||||||
|
'address': IP_ADDRESS,
|
||||||
|
'home-node': NODE_NAME,
|
||||||
|
'home-port': VLAN_PORT,
|
||||||
|
'interface-name': LIF_NAME,
|
||||||
|
'netmask': NETMASK,
|
||||||
|
'role': 'data',
|
||||||
|
'vserver': VSERVER_NAME,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'uuid': 'fake_uuid_3',
|
||||||
'address': IP_ADDRESS,
|
'address': IP_ADDRESS,
|
||||||
'home-node': NODE_NAME,
|
'home-node': NODE_NAME,
|
||||||
'home-port': VLAN_PORT,
|
'home-port': VLAN_PORT,
|
||||||
@ -3690,7 +3713,8 @@ GENERIC_NETWORK_INTERFACES_GET_REPONSE = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"num_records": 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
GENERIC_EXPORT_POLICY_RESPONSE_AND_VOLUMES = {
|
GENERIC_EXPORT_POLICY_RESPONSE_AND_VOLUMES = {
|
||||||
@ -3940,6 +3964,9 @@ SNAPMIRROR_GET_ITER_RESPONSE_REST = {
|
|||||||
"transfer_schedule": {
|
"transfer_schedule": {
|
||||||
"name": "hourly",
|
"name": "hourly",
|
||||||
},
|
},
|
||||||
|
"transfer": {
|
||||||
|
"state": "success"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"num_records": 1,
|
"num_records": 1,
|
||||||
@ -3950,12 +3977,13 @@ REST_GET_SNAPMIRRORS_RESPONSE = [{
|
|||||||
'destination-vserver': SM_DEST_VSERVER,
|
'destination-vserver': SM_DEST_VSERVER,
|
||||||
'last-transfer-end-timestamp': 0,
|
'last-transfer-end-timestamp': 0,
|
||||||
'mirror-state': 'snapmirrored',
|
'mirror-state': 'snapmirrored',
|
||||||
'relationship-status': 'snapmirrored',
|
'relationship-status': 'idle',
|
||||||
'source-volume': SM_SOURCE_VOLUME,
|
'source-volume': SM_SOURCE_VOLUME,
|
||||||
'source-vserver': SM_SOURCE_VSERVER,
|
'source-vserver': SM_SOURCE_VSERVER,
|
||||||
'uuid': FAKE_UUID,
|
'uuid': FAKE_UUID,
|
||||||
'policy-type': 'async',
|
'policy-type': 'async',
|
||||||
'schedule': 'hourly'
|
'schedule': 'hourly',
|
||||||
|
'transferring-state': 'success'
|
||||||
}]
|
}]
|
||||||
|
|
||||||
FAKE_CIFS_RECORDS = {
|
FAKE_CIFS_RECORDS = {
|
||||||
@ -4622,7 +4650,8 @@ FAKE_AGGREGATES_RESPONSE = {
|
|||||||
{
|
{
|
||||||
"name": SHARE_AGGREGATE_NAME
|
"name": SHARE_AGGREGATE_NAME
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"name": VSERVER_NAME,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -4673,3 +4702,65 @@ REST_MGMT_INTERFACES = {
|
|||||||
],
|
],
|
||||||
"num_records": 2,
|
"num_records": 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FAKE_CIFS_LOCAL_USER = {
|
||||||
|
'records': [
|
||||||
|
{
|
||||||
|
'sid': 'S-1-5-21-256008430-3394229847-3930036330-1001'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
FAKE_SERVER_SWITCH_NAME = 'fake_ss_name'
|
||||||
|
FAKE_SUBTYPE = 'fake_subtype'
|
||||||
|
FAKE_DNS_CONFIG = {
|
||||||
|
'dns-state': 'true',
|
||||||
|
'domains': ['fake_domain'],
|
||||||
|
'dns-ips': ['fake_ip']
|
||||||
|
}
|
||||||
|
|
||||||
|
FAKE_VOLUME_MANAGE = {
|
||||||
|
'records': [
|
||||||
|
{
|
||||||
|
'name': VOLUME_NAMES[0],
|
||||||
|
'aggregates': [
|
||||||
|
{
|
||||||
|
'name': SHARE_AGGREGATE_NAME
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'nas': {
|
||||||
|
'path': VOLUME_JUNCTION_PATH
|
||||||
|
},
|
||||||
|
'style': 'flex',
|
||||||
|
'type': 'fake_type',
|
||||||
|
'svm': {
|
||||||
|
'name': VSERVER_NAME
|
||||||
|
},
|
||||||
|
'qos': {
|
||||||
|
'policy': {
|
||||||
|
'name': QOS_POLICY_GROUP_NAME
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'space': {
|
||||||
|
'size': SHARE_SIZE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'num_records': 1
|
||||||
|
}
|
||||||
|
|
||||||
|
FAKE_PORTS = [
|
||||||
|
{'speed': ''},
|
||||||
|
{'speed': '4'},
|
||||||
|
{'speed': 'auto'},
|
||||||
|
{'speed': 'undef'},
|
||||||
|
{'speed': 'fake_speed'}
|
||||||
|
]
|
||||||
|
|
||||||
|
FAKE_ROOT_AGGREGATES_RESPONSE = {
|
||||||
|
"records": [
|
||||||
|
{
|
||||||
|
"aggregate": SHARE_AGGREGATE_NAME
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
@ -3179,6 +3179,7 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
|||||||
'volume-type': 'rw',
|
'volume-type': 'rw',
|
||||||
'junction-path': '/%s' % fake.SHARE_NAME,
|
'junction-path': '/%s' % fake.SHARE_NAME,
|
||||||
'space-reserve': ('none' if thin_provisioned else 'volume'),
|
'space-reserve': ('none' if thin_provisioned else 'volume'),
|
||||||
|
'encrypt': 'false'
|
||||||
}
|
}
|
||||||
|
|
||||||
self.client.send_request.assert_called_once_with('volume-create',
|
self.client.send_request.assert_called_once_with('volume-create',
|
||||||
@ -3291,6 +3292,7 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
|||||||
expected_api_args = {
|
expected_api_args = {
|
||||||
'volume-type': volume_type,
|
'volume-type': volume_type,
|
||||||
'space-reserve': 'volume',
|
'space-reserve': 'volume',
|
||||||
|
'encrypt': 'false'
|
||||||
}
|
}
|
||||||
self.assertEqual(expected_api_args, result_api_args)
|
self.assertEqual(expected_api_args, result_api_args)
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user