Merge "Add functional API tests for volume connector and volume target"
This commit is contained in:
commit
09627c8436
@ -50,6 +50,16 @@ class BaremetalClient(base.BaremetalClient):
|
||||
"""List all existing port groups."""
|
||||
return self._list_request('portgroups', **kwargs)
|
||||
|
||||
@base.handle_errors
|
||||
def list_volume_connectors(self, **kwargs):
|
||||
"""List all existing volume connectors."""
|
||||
return self._list_request('volume/connectors', **kwargs)
|
||||
|
||||
@base.handle_errors
|
||||
def list_volume_targets(self, **kwargs):
|
||||
"""List all existing volume targets."""
|
||||
return self._list_request('volume/targets', **kwargs)
|
||||
|
||||
@base.handle_errors
|
||||
def list_node_ports(self, uuid):
|
||||
"""List all ports associated with the node."""
|
||||
@ -123,6 +133,24 @@ class BaremetalClient(base.BaremetalClient):
|
||||
"""
|
||||
return self._show_request('portgroups', portgroup_ident)
|
||||
|
||||
@base.handle_errors
|
||||
def show_volume_connector(self, volume_connector_ident):
|
||||
"""Gets a specific volume connector.
|
||||
|
||||
:param volume_connector_ident: UUID of the volume connector.
|
||||
:return: Serialized volume connector as a dictionary.
|
||||
"""
|
||||
return self._show_request('volume/connectors', volume_connector_ident)
|
||||
|
||||
@base.handle_errors
|
||||
def show_volume_target(self, volume_target_ident):
|
||||
"""Gets a specific volume target.
|
||||
|
||||
:param volume_target_ident: UUID of the volume target.
|
||||
:return: Serialized volume target as a dictionary.
|
||||
"""
|
||||
return self._show_request('volume/targets', volume_target_ident)
|
||||
|
||||
@base.handle_errors
|
||||
def show_port_by_address(self, address):
|
||||
"""Gets a specific port by address.
|
||||
@ -238,6 +266,52 @@ class BaremetalClient(base.BaremetalClient):
|
||||
|
||||
return self._create_request('portgroups', portgroup)
|
||||
|
||||
@base.handle_errors
|
||||
def create_volume_connector(self, node_uuid, **kwargs):
|
||||
"""Create a volume connector with the specified parameters.
|
||||
|
||||
:param node_uuid: The UUID of the node which owns the volume connector.
|
||||
:param kwargs:
|
||||
type: type of the volume connector.
|
||||
connector_id: connector_id of the volume connector.
|
||||
uuid: UUID of the volume connector. Optional.
|
||||
extra: meta data of the volume connector; a dictionary. Optional.
|
||||
:return: A tuple with the server response and the created volume
|
||||
connector.
|
||||
"""
|
||||
volume_connector = {'node_uuid': node_uuid}
|
||||
|
||||
for arg in ('type', 'connector_id', 'uuid', 'extra'):
|
||||
if arg in kwargs:
|
||||
volume_connector[arg] = kwargs[arg]
|
||||
|
||||
return self._create_request('volume/connectors', volume_connector)
|
||||
|
||||
@base.handle_errors
|
||||
def create_volume_target(self, node_uuid, **kwargs):
|
||||
"""Create a volume target with the specified parameters.
|
||||
|
||||
:param node_uuid: The UUID of the node which owns the volume target.
|
||||
:param kwargs:
|
||||
volume_type: type of the volume target.
|
||||
volume_id: volume_id of the volume target.
|
||||
boot_index: boot index of the volume target.
|
||||
uuid: UUID of the volume target. Optional.
|
||||
extra: meta data of the volume target; a dictionary. Optional.
|
||||
properties: properties related to the type of the volume target;
|
||||
a dictionary. Optional.
|
||||
:return: A tuple with the server response and the created volume
|
||||
target.
|
||||
"""
|
||||
volume_target = {'node_uuid': node_uuid}
|
||||
|
||||
for arg in ('volume_type', 'volume_id', 'boot_index', 'uuid', 'extra',
|
||||
'properties'):
|
||||
if arg in kwargs:
|
||||
volume_target[arg] = kwargs[arg]
|
||||
|
||||
return self._create_request('volume/targets', volume_target)
|
||||
|
||||
@base.handle_errors
|
||||
def delete_node(self, uuid):
|
||||
"""Deletes a node having the specified UUID.
|
||||
@ -277,6 +351,25 @@ class BaremetalClient(base.BaremetalClient):
|
||||
"""
|
||||
return self._delete_request('portgroups', portgroup_ident)
|
||||
|
||||
@base.handle_errors
|
||||
def delete_volume_connector(self, volume_connector_ident):
|
||||
"""Deletes a volume connector having the specified UUID.
|
||||
|
||||
:param volume_connector_ident: UUID of the volume connector.
|
||||
:return: A tuple with the server response and the response body.
|
||||
"""
|
||||
return self._delete_request('volume/connectors',
|
||||
volume_connector_ident)
|
||||
|
||||
@base.handle_errors
|
||||
def delete_volume_target(self, volume_target_ident):
|
||||
"""Deletes a volume target having the specified UUID.
|
||||
|
||||
:param volume_target_ident: UUID of the volume target.
|
||||
:return: A tuple with the server response and the response body.
|
||||
"""
|
||||
return self._delete_request('volume/targets', volume_target_ident)
|
||||
|
||||
@base.handle_errors
|
||||
def update_node(self, uuid, patch=None, **kwargs):
|
||||
"""Update the specified node.
|
||||
@ -326,6 +419,32 @@ class BaremetalClient(base.BaremetalClient):
|
||||
|
||||
return self._patch_request('ports', uuid, patch)
|
||||
|
||||
@base.handle_errors
|
||||
def update_volume_connector(self, uuid, patch):
|
||||
"""Update the specified volume connector.
|
||||
|
||||
:param uuid: The unique identifier of the volume connector.
|
||||
:param patch: List of dicts representing json patches. Each dict
|
||||
has keys 'path', 'op' and 'value'; to update a field.
|
||||
:return: A tuple with the server response and the updated volume
|
||||
connector.
|
||||
"""
|
||||
|
||||
return self._patch_request('volume/connectors', uuid, patch)
|
||||
|
||||
@base.handle_errors
|
||||
def update_volume_target(self, uuid, patch):
|
||||
"""Update the specified volume target.
|
||||
|
||||
:param uuid: The unique identifier of the volume target.
|
||||
:param patch: List of dicts representing json patches. Each dict
|
||||
has keys 'path', 'op' and 'value'; to update a field.
|
||||
:return: A tuple with the server response and the updated volume
|
||||
target.
|
||||
"""
|
||||
|
||||
return self._patch_request('volume/targets', uuid, patch)
|
||||
|
||||
@base.handle_errors
|
||||
def set_node_power_state(self, node_uuid, state):
|
||||
"""Set power state of the specified node.
|
||||
|
@ -33,7 +33,8 @@ SUPPORTED_DRIVERS = ['fake']
|
||||
|
||||
# NOTE(jroll): resources must be deleted in a specific order, this list
|
||||
# defines the resource types to clean up, and the correct order.
|
||||
RESOURCE_TYPES = ['port', 'node', 'chassis', 'portgroup']
|
||||
RESOURCE_TYPES = ['port', 'portgroup', 'volume_connector', 'volume_target',
|
||||
'node', 'chassis']
|
||||
|
||||
|
||||
def creates(resource):
|
||||
@ -221,6 +222,34 @@ class BaseBaremetalTest(api_version_utils.BaseMicroversionTest,
|
||||
|
||||
return resp, body
|
||||
|
||||
@classmethod
|
||||
@creates('volume_connector')
|
||||
def create_volume_connector(cls, node_uuid, **kwargs):
|
||||
"""Wrapper utility for creating test volume connector.
|
||||
|
||||
:param node_uuid: The unique identifier of the node.
|
||||
:return: A tuple with the server response and the created volume
|
||||
connector.
|
||||
"""
|
||||
resp, body = cls.client.create_volume_connector(node_uuid=node_uuid,
|
||||
**kwargs)
|
||||
|
||||
return resp, body
|
||||
|
||||
@classmethod
|
||||
@creates('volume_target')
|
||||
def create_volume_target(cls, node_uuid, **kwargs):
|
||||
"""Wrapper utility for creating test volume target.
|
||||
|
||||
:param node_uuid: The unique identifier of the node.
|
||||
:return: A tuple with the server response and the created volume
|
||||
target.
|
||||
"""
|
||||
resp, body = cls.client.create_volume_target(node_uuid=node_uuid,
|
||||
**kwargs)
|
||||
|
||||
return resp, body
|
||||
|
||||
@classmethod
|
||||
def delete_chassis(cls, chassis_id):
|
||||
"""Deletes a chassis having the specified UUID.
|
||||
@ -283,6 +312,35 @@ class BaseBaremetalTest(api_version_utils.BaseMicroversionTest,
|
||||
|
||||
return resp
|
||||
|
||||
@classmethod
|
||||
def delete_volume_connector(cls, volume_connector_id):
|
||||
"""Deletes a volume connector having the specified UUID.
|
||||
|
||||
:param volume_connector_id: The UUID of the volume connector.
|
||||
:return: Server response.
|
||||
"""
|
||||
resp, body = cls.client.delete_volume_connector(volume_connector_id)
|
||||
|
||||
if volume_connector_id in cls.created_objects['volume_connector']:
|
||||
cls.created_objects['volume_connector'].remove(
|
||||
volume_connector_id)
|
||||
|
||||
return resp
|
||||
|
||||
@classmethod
|
||||
def delete_volume_target(cls, volume_target_id):
|
||||
"""Deletes a volume target having the specified UUID.
|
||||
|
||||
:param volume_target_id: The UUID of the volume target.
|
||||
:return: Server response.
|
||||
"""
|
||||
resp, body = cls.client.delete_volume_target(volume_target_id)
|
||||
|
||||
if volume_target_id in cls.created_objects['volume_target']:
|
||||
cls.created_objects['volume_target'].remove(volume_target_id)
|
||||
|
||||
return resp
|
||||
|
||||
def validate_self_link(self, resource, uuid, link):
|
||||
"""Check whether the given self link formatted correctly."""
|
||||
expected_link = "{base}/{pref}/{res}/{uuid}".format(
|
||||
|
227
ironic_tempest_plugin/tests/api/admin/test_volume_connector.py
Normal file
227
ironic_tempest_plugin/tests/api/admin/test_volume_connector.py
Normal file
@ -0,0 +1,227 @@
|
||||
# Copyright 2017 FUJITSU LIMITED
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
from tempest.lib.common.utils import data_utils
|
||||
from tempest.lib import decorators
|
||||
from tempest.lib import exceptions as lib_exc
|
||||
|
||||
from ironic_tempest_plugin.tests.api.admin import api_microversion_fixture
|
||||
from ironic_tempest_plugin.tests.api.admin import base
|
||||
|
||||
|
||||
class TestVolumeConnector(base.BaseBaremetalTest):
|
||||
"""Basic test cases for volume connector."""
|
||||
|
||||
min_microversion = '1.32'
|
||||
extra = {'key1': 'value1', 'key2': 'value2'}
|
||||
|
||||
def setUp(self):
|
||||
super(TestVolumeConnector, self).setUp()
|
||||
self.useFixture(
|
||||
api_microversion_fixture.APIMicroversionFixture(
|
||||
self.min_microversion))
|
||||
_, self.chassis = self.create_chassis()
|
||||
_, self.node = self.create_node(self.chassis['uuid'])
|
||||
_, self.volume_connector = self.create_volume_connector(
|
||||
self.node['uuid'], type='iqn',
|
||||
connector_id=data_utils.rand_name('connector_id'),
|
||||
extra=self.extra)
|
||||
|
||||
@decorators.attr(type=['negative'])
|
||||
@decorators.idempotent_id('3c3cbf45-488a-4386-a811-bf0aa2589c58')
|
||||
def test_create_volume_connector_error(self):
|
||||
"""Create a volume connector.
|
||||
|
||||
Fail when creating a volume connector with same connector_id
|
||||
& type as an existing volume connector.
|
||||
"""
|
||||
regex_str = (r'.*A volume connector .*already exists')
|
||||
|
||||
self.assertRaisesRegex(
|
||||
lib_exc.Conflict, regex_str,
|
||||
self.create_volume_connector,
|
||||
self.node['uuid'],
|
||||
type=self.volume_connector['type'],
|
||||
connector_id=self.volume_connector['connector_id'])
|
||||
|
||||
@decorators.idempotent_id('5795f816-0789-42e6-bb9c-91b4876ad13f')
|
||||
def test_delete_volume_connector(self):
|
||||
"""Delete a volume connector."""
|
||||
# Powering off the Node before deleting a volume connector.
|
||||
self.client.set_node_power_state(self.node['uuid'], 'power off')
|
||||
|
||||
self.delete_volume_connector(self.volume_connector['uuid'])
|
||||
self.assertRaises(lib_exc.NotFound, self.client.show_volume_connector,
|
||||
self.volume_connector['uuid'])
|
||||
|
||||
@decorators.attr(type=['negative'])
|
||||
@decorators.idempotent_id('ccbda5e6-52b7-400c-94d7-25eec1d590f0')
|
||||
def test_delete_volume_connector_error(self):
|
||||
"""Delete a volume connector
|
||||
|
||||
Fail when deleting a volume connector on node
|
||||
with powered on state.
|
||||
"""
|
||||
|
||||
# Powering on the Node before deleting a volume connector.
|
||||
self.client.set_node_power_state(self.node['uuid'], 'power on')
|
||||
|
||||
regex_str = (r'.*The requested action \\\\"volume connector '
|
||||
r'deletion\\\\" can not be performed on node*')
|
||||
|
||||
self.assertRaisesRegex(lib_exc.BadRequest,
|
||||
regex_str,
|
||||
self.delete_volume_connector,
|
||||
self.volume_connector['uuid'])
|
||||
|
||||
@decorators.idempotent_id('6e4f50b7-0f4f-41c2-971e-d751abcac4e0')
|
||||
def test_show_volume_connector(self):
|
||||
"""Show a specified volume connector."""
|
||||
_, volume_connector = self.client.show_volume_connector(
|
||||
self.volume_connector['uuid'])
|
||||
self._assertExpected(self.volume_connector, volume_connector)
|
||||
|
||||
@decorators.idempotent_id('a4725778-e164-4ee5-96a0-66119a35f783')
|
||||
def test_list_volume_connectors(self):
|
||||
"""List volume connectors."""
|
||||
_, body = self.client.list_volume_connectors()
|
||||
self.assertIn(self.volume_connector['uuid'],
|
||||
[i['uuid'] for i in body['connectors']])
|
||||
self.assertIn(self.volume_connector['type'],
|
||||
[i['type'] for i in body['connectors']])
|
||||
self.assertIn(self.volume_connector['connector_id'],
|
||||
[i['connector_id'] for i in body['connectors']])
|
||||
|
||||
@decorators.idempotent_id('1d0459ad-01c0-46db-b930-7301bc2a3c98')
|
||||
def test_list_with_limit(self):
|
||||
"""List volume connectors with limit."""
|
||||
_, body = self.client.list_volume_connectors(limit=3)
|
||||
|
||||
next_marker = body['connectors'][-1]['uuid']
|
||||
self.assertIn(next_marker, body['next'])
|
||||
|
||||
@decorators.idempotent_id('3c6f8354-e9bd-4f21-aae2-6deb96b04be7')
|
||||
def test_update_volume_connector_replace(self):
|
||||
"""Update a volume connector with new connector id."""
|
||||
new_connector_id = data_utils.rand_name('connector_id')
|
||||
|
||||
patch = [{'path': '/connector_id',
|
||||
'op': 'replace',
|
||||
'value': new_connector_id}]
|
||||
|
||||
# Powering off the Node before updating a volume connector.
|
||||
self.client.set_node_power_state(self.node['uuid'], 'power off')
|
||||
|
||||
self.client.update_volume_connector(
|
||||
self.volume_connector['uuid'], patch)
|
||||
|
||||
_, body = self.client.show_volume_connector(
|
||||
self.volume_connector['uuid'])
|
||||
self.assertEqual(new_connector_id, body['connector_id'])
|
||||
|
||||
@decorators.attr(type=['negative'])
|
||||
@decorators.idempotent_id('5af8dc7a-9965-4787-8184-e60aeaf30957')
|
||||
def test_update_volume_connector_replace_error(self):
|
||||
"""Updating a volume connector.
|
||||
|
||||
Fail when updating a volume connector on node
|
||||
with power on state.
|
||||
"""
|
||||
|
||||
new_connector_id = data_utils.rand_name('connector_id')
|
||||
|
||||
patch = [{'path': '/connector_id',
|
||||
'op': 'replace',
|
||||
'value': new_connector_id}]
|
||||
|
||||
# Powering on the Node before updating a volume connector.
|
||||
self.client.set_node_power_state(self.node['uuid'], 'power on')
|
||||
|
||||
regex_str = (r'.*The requested action \\\\"volume connector '
|
||||
r'update\\\\" can not be performed on node*')
|
||||
self.assertRaisesRegex(lib_exc.BadRequest,
|
||||
regex_str,
|
||||
self.client.update_volume_connector,
|
||||
self.volume_connector['uuid'],
|
||||
patch)
|
||||
|
||||
@decorators.idempotent_id('b95c75eb-4048-482e-99ff-fe1d32538383')
|
||||
def test_update_volume_connector_remove_item(self):
|
||||
"""Update a volume connector by removing one item from collection."""
|
||||
new_extra = {'key1': 'value1'}
|
||||
_, body = self.client.show_volume_connector(
|
||||
self.volume_connector['uuid'])
|
||||
connector_id = body['connector_id']
|
||||
connector_type = body['type']
|
||||
|
||||
# Powering off the Node before updating a volume connector.
|
||||
self.client.set_node_power_state(self.node['uuid'], 'power off')
|
||||
|
||||
# Removing one item from the collection
|
||||
self.client.update_volume_connector(self.volume_connector['uuid'],
|
||||
[{'path': '/extra/key2',
|
||||
'op': 'remove'}])
|
||||
_, body = self.client.show_volume_connector(
|
||||
self.volume_connector['uuid'])
|
||||
self.assertEqual(new_extra, body['extra'])
|
||||
|
||||
# Assert nothing else was changed
|
||||
self.assertEqual(connector_id, body['connector_id'])
|
||||
self.assertEqual(connector_type, body['type'])
|
||||
|
||||
@decorators.idempotent_id('8de03acd-532a-476f-8bc9-0e8b23bfe609')
|
||||
def test_update_volume_connector_remove_collection(self):
|
||||
"""Update a volume connector by removing collection."""
|
||||
_, body = self.client.show_volume_connector(
|
||||
self.volume_connector['uuid'])
|
||||
connector_id = body['connector_id']
|
||||
connector_type = body['type']
|
||||
|
||||
# Powering off the Node before updating a volume connector.
|
||||
self.client.set_node_power_state(self.node['uuid'], 'power off')
|
||||
|
||||
# Removing the collection
|
||||
self.client.update_volume_connector(self.volume_connector['uuid'],
|
||||
[{'path': '/extra',
|
||||
'op': 'remove'}])
|
||||
_, body = self.client.show_volume_connector(
|
||||
self.volume_connector['uuid'])
|
||||
self.assertEqual({}, body['extra'])
|
||||
|
||||
# Assert nothing else was changed
|
||||
self.assertEqual(connector_id, body['connector_id'])
|
||||
self.assertEqual(connector_type, body['type'])
|
||||
|
||||
@decorators.idempotent_id('bfb0ca6b-086d-4663-9b25-e0eaf42da55b')
|
||||
def test_update_volume_connector_add(self):
|
||||
"""Update a volume connector by adding one item to collection."""
|
||||
new_extra = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
|
||||
|
||||
patch = [{'path': '/extra/key3',
|
||||
'op': 'add',
|
||||
'value': new_extra['key3']},
|
||||
{'path': '/extra/key3',
|
||||
'op': 'add',
|
||||
'value': new_extra['key3']}]
|
||||
|
||||
# Powering off the Node before updating a volume connector.
|
||||
self.client.set_node_power_state(self.node['uuid'], 'power off')
|
||||
|
||||
self.client.update_volume_connector(
|
||||
self.volume_connector['uuid'], patch)
|
||||
|
||||
_, body = self.client.show_volume_connector(
|
||||
self.volume_connector['uuid'])
|
||||
self.assertEqual(new_extra, body['extra'])
|
210
ironic_tempest_plugin/tests/api/admin/test_volume_target.py
Normal file
210
ironic_tempest_plugin/tests/api/admin/test_volume_target.py
Normal file
@ -0,0 +1,210 @@
|
||||
# Copyright 2017 FUJITSU LIMITED
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
from tempest.lib.common.utils import data_utils
|
||||
from tempest.lib import decorators
|
||||
from tempest.lib import exceptions as lib_exc
|
||||
|
||||
from ironic_tempest_plugin.tests.api.admin import api_microversion_fixture
|
||||
from ironic_tempest_plugin.tests.api.admin import base
|
||||
|
||||
|
||||
class TestVolumeTarget(base.BaseBaremetalTest):
|
||||
"""Basic test cases for volume target."""
|
||||
|
||||
min_microversion = '1.32'
|
||||
extra = {'key1': 'value1', 'key2': 'value2'}
|
||||
|
||||
def setUp(self):
|
||||
super(TestVolumeTarget, self).setUp()
|
||||
self.useFixture(
|
||||
api_microversion_fixture.APIMicroversionFixture(
|
||||
self.min_microversion))
|
||||
_, self.chassis = self.create_chassis()
|
||||
_, self.node = self.create_node(self.chassis['uuid'])
|
||||
_, self.volume_target = self.create_volume_target(
|
||||
self.node['uuid'], volume_type=data_utils.rand_name('volume_type'),
|
||||
volume_id=data_utils.rand_name('volume_id'),
|
||||
boot_index=10,
|
||||
extra=self.extra)
|
||||
|
||||
@decorators.attr(type=['negative'])
|
||||
@decorators.idempotent_id('da5c27d4-68cc-499f-b8ab-3048b87d3bca')
|
||||
def test_create_volume_target_error(self):
|
||||
"""Create a volume target.
|
||||
|
||||
Fail when creating a volume target with same boot index as the
|
||||
existing volume target.
|
||||
"""
|
||||
regex_str = (r'.*A volume target .*already exists')
|
||||
|
||||
self.assertRaisesRegex(
|
||||
lib_exc.Conflict, regex_str,
|
||||
self.create_volume_target,
|
||||
self.node['uuid'],
|
||||
volume_type=data_utils.rand_name('volume_type'),
|
||||
volume_id=data_utils.rand_name('volume_id'),
|
||||
boot_index=self.volume_target['boot_index'])
|
||||
|
||||
@decorators.idempotent_id('ea3a9b2e-8971-4830-9274-abaf0239f1ce')
|
||||
def test_delete_volume_target(self):
|
||||
"""Delete a volume target."""
|
||||
# Powering off the Node before deleting a volume target.
|
||||
self.client.set_node_power_state(self.node['uuid'], 'power off')
|
||||
|
||||
self.delete_volume_target(self.volume_target['uuid'])
|
||||
self.assertRaises(lib_exc.NotFound, self.client.show_volume_target,
|
||||
self.volume_target['uuid'])
|
||||
|
||||
@decorators.attr(type=['negative'])
|
||||
@decorators.idempotent_id('532a06bc-a9b2-44b0-828a-c53279c87cb2')
|
||||
def test_delete_volume_target_error(self):
|
||||
"""Fail when deleting a volume target on node with power on state."""
|
||||
# Powering on the Node before deleting a volume target.
|
||||
self.client.set_node_power_state(self.node['uuid'], 'power on')
|
||||
|
||||
regex_str = (r'.*The requested action \\\\"volume target '
|
||||
r'deletion\\\\" can not be performed on node*')
|
||||
|
||||
self.assertRaisesRegex(lib_exc.BadRequest,
|
||||
regex_str,
|
||||
self.delete_volume_target,
|
||||
self.volume_target['uuid'])
|
||||
|
||||
@decorators.idempotent_id('a2598388-8f61-4b7e-944f-f37e4f60e1e2')
|
||||
def test_show_volume_target(self):
|
||||
"""Show a specified volume target."""
|
||||
_, volume_target = self.client.show_volume_target(
|
||||
self.volume_target['uuid'])
|
||||
self._assertExpected(self.volume_target, volume_target)
|
||||
|
||||
@decorators.idempotent_id('ae99a986-d93c-4324-9cdc-41d89e3a659f')
|
||||
def test_list_volume_targets(self):
|
||||
"""List volume targets."""
|
||||
_, body = self.client.list_volume_targets()
|
||||
self.assertIn(self.volume_target['uuid'],
|
||||
[i['uuid'] for i in body['targets']])
|
||||
self.assertIn(self.volume_target['volume_type'],
|
||||
[i['volume_type'] for i in body['targets']])
|
||||
self.assertIn(self.volume_target['volume_id'],
|
||||
[i['volume_id'] for i in body['targets']])
|
||||
|
||||
@decorators.idempotent_id('9da25447-0370-4b33-9c1f-d4503f5950ae')
|
||||
def test_list_with_limit(self):
|
||||
"""List volume targets with limit."""
|
||||
_, body = self.client.list_volume_targets(limit=3)
|
||||
|
||||
next_marker = body['targets'][-1]['uuid']
|
||||
self.assertIn(next_marker, body['next'])
|
||||
|
||||
@decorators.idempotent_id('8559cd08-feae-4f1a-a0ad-5bad8ea12b76')
|
||||
def test_update_volume_target_replace(self):
|
||||
"""Update a volume target by replacing volume id."""
|
||||
new_volume_id = data_utils.rand_name('volume_id')
|
||||
|
||||
patch = [{'path': '/volume_id',
|
||||
'op': 'replace',
|
||||
'value': new_volume_id}]
|
||||
|
||||
# Powering off the Node before updating a volume target.
|
||||
self.client.set_node_power_state(self.node['uuid'], 'power off')
|
||||
|
||||
self.client.update_volume_target(self.volume_target['uuid'], patch)
|
||||
|
||||
_, body = self.client.show_volume_target(self.volume_target['uuid'])
|
||||
self.assertEqual(new_volume_id, body['volume_id'])
|
||||
|
||||
@decorators.attr(type=['negative'])
|
||||
@decorators.idempotent_id('fd5266d3-4f3c-4dce-9c87-bfdea2b756c7')
|
||||
def test_update_volume_target_replace_error(self):
|
||||
"""Fail when updating a volume target on node with power on state."""
|
||||
new_volume_id = data_utils.rand_name('volume_id')
|
||||
|
||||
patch = [{'path': '/volume_id',
|
||||
'op': 'replace',
|
||||
'value': new_volume_id}]
|
||||
|
||||
# Powering on the Node before updating a volume target.
|
||||
self.client.set_node_power_state(self.node['uuid'], 'power on')
|
||||
|
||||
regex_str = (r'.*The requested action \\\\"volume target '
|
||||
r'update\\\\" can not be performed on node*')
|
||||
|
||||
self.assertRaisesRegex(lib_exc.BadRequest,
|
||||
regex_str,
|
||||
self.client.update_volume_target,
|
||||
self.volume_target['uuid'],
|
||||
patch)
|
||||
|
||||
@decorators.idempotent_id('1c13a4ee-1a49-4739-8c19-77960fbd1af8')
|
||||
def test_update_volume_target_remove_item(self):
|
||||
"""Update a volume target by removing one item from the collection."""
|
||||
new_extra = {'key1': 'value1'}
|
||||
_, body = self.client.show_volume_target(self.volume_target['uuid'])
|
||||
volume_id = body['volume_id']
|
||||
volume_type = body['volume_type']
|
||||
|
||||
# Powering off the Node before updating a volume target.
|
||||
self.client.set_node_power_state(self.node['uuid'], 'power off')
|
||||
|
||||
# Removing one item from the collection
|
||||
self.client.update_volume_target(self.volume_target['uuid'],
|
||||
[{'path': '/extra/key2',
|
||||
'op': 'remove'}])
|
||||
|
||||
_, body = self.client.show_volume_target(self.volume_target['uuid'])
|
||||
self.assertEqual(new_extra, body['extra'])
|
||||
|
||||
# Assert nothing else was changed
|
||||
self.assertEqual(volume_id, body['volume_id'])
|
||||
self.assertEqual(volume_type, body['volume_type'])
|
||||
|
||||
@decorators.idempotent_id('6784ddb0-9144-41ea-b8a0-f888ad5c5b62')
|
||||
def test_update_volume_target_remove_collection(self):
|
||||
"""Update a volume target by removing the collection."""
|
||||
_, body = self.client.show_volume_target(self.volume_target['uuid'])
|
||||
volume_id = body['volume_id']
|
||||
volume_type = body['volume_type']
|
||||
|
||||
# Powering off the Node before updating a volume target.
|
||||
self.client.set_node_power_state(self.node['uuid'], 'power off')
|
||||
|
||||
# Removing the collection
|
||||
self.client.update_volume_target(self.volume_target['uuid'],
|
||||
[{'path': '/extra',
|
||||
'op': 'remove'}])
|
||||
_, body = self.client.show_volume_target(self.volume_target['uuid'])
|
||||
self.assertEqual({}, body['extra'])
|
||||
|
||||
# Assert nothing else was changed
|
||||
self.assertEqual(volume_id, body['volume_id'])
|
||||
self.assertEqual(volume_type, body['volume_type'])
|
||||
|
||||
@decorators.idempotent_id('9629715d-57ba-423b-b985-232674cc3a25')
|
||||
def test_update_volume_target_add(self):
|
||||
"""Update a volume target by adding to the collection."""
|
||||
new_extra = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
|
||||
|
||||
patch = [{'path': '/extra/key3',
|
||||
'op': 'add',
|
||||
'value': new_extra['key3']}]
|
||||
|
||||
# Powering off the Node before updating a volume target.
|
||||
self.client.set_node_power_state(self.node['uuid'], 'power off')
|
||||
|
||||
self.client.update_volume_target(self.volume_target['uuid'], patch)
|
||||
|
||||
_, body = self.client.show_volume_target(self.volume_target['uuid'])
|
||||
self.assertEqual(new_extra, body['extra'])
|
Loading…
Reference in New Issue
Block a user