Volume Target support for Ironic on OpenStack SDK
This patch adds support for Ironic Volume Target API. Change-Id: Ic1e080cfc2c6439fddbb41bc6015abcb59291667 Story: #2008169 Task: #40924
This commit is contained in:
parent
256e25e321
commit
06db9e37fa
@ -69,6 +69,14 @@ Volume Connector Operations
|
||||
create_volume_connector, update_volume_connector,
|
||||
patch_volume_connector, delete_volume_connector
|
||||
|
||||
Volume Target Operations
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
.. autoclass:: openstack.baremetal.v1._proxy.Proxy
|
||||
:noindex:
|
||||
:members: volume_targets, find_volume_target, get_volume_target,
|
||||
create_volume_target, update_volume_target,
|
||||
patch_volume_target, delete_volume_target
|
||||
|
||||
Utilities
|
||||
---------
|
||||
|
||||
|
@ -11,3 +11,4 @@ Baremetal Resources
|
||||
v1/port_group
|
||||
v1/allocation
|
||||
v1/volume_connector
|
||||
v1/volume_target
|
||||
|
13
doc/source/user/resources/baremetal/v1/volume_target.rst
Normal file
13
doc/source/user/resources/baremetal/v1/volume_target.rst
Normal file
@ -0,0 +1,13 @@
|
||||
openstack.baremetal.v1.volume_target
|
||||
=======================================
|
||||
|
||||
.. automodule:: openstack.baremetal.v1.volume_target
|
||||
|
||||
The VolumeTarget Class
|
||||
-------------------------
|
||||
|
||||
The ``VolumeTarget`` class inherits
|
||||
from :class:`~openstack.resource.Resource`.
|
||||
|
||||
.. autoclass:: openstack.baremetal.v1.volume_target.VolumeTarget
|
||||
:members:
|
@ -18,6 +18,7 @@ from openstack.baremetal.v1 import node as _node
|
||||
from openstack.baremetal.v1 import port as _port
|
||||
from openstack.baremetal.v1 import port_group as _portgroup
|
||||
from openstack.baremetal.v1 import volume_connector as _volumeconnector
|
||||
from openstack.baremetal.v1 import volume_target as _volumetarget
|
||||
from openstack import exceptions
|
||||
from openstack import proxy
|
||||
from openstack import utils
|
||||
@ -231,7 +232,7 @@ class Proxy(proxy.Proxy):
|
||||
provided as the ``sort_key``.
|
||||
* ``sort_key``: Sorts the response by the this attribute value.
|
||||
Default is ``id``. You can specify multiple pairs of sort
|
||||
key and sort direction query parameters. If you omit the
|
||||
key and sort direction query pa rameters. If you omit the
|
||||
sort direction in a pair, the API uses the natural sorting
|
||||
direction of the server attribute that is provided as the
|
||||
``sort_key``.
|
||||
@ -1166,3 +1167,145 @@ class Proxy(proxy.Proxy):
|
||||
"""
|
||||
return self._delete(_volumeconnector.VolumeConnector,
|
||||
volume_connector, ignore_missing=ignore_missing)
|
||||
|
||||
def volume_targets(self, details=False, **query):
|
||||
"""Retrieve a generator of volume_target.
|
||||
|
||||
:param details: A boolean indicating whether the detailed information
|
||||
for every volume_target should be returned.
|
||||
:param dict query: Optional query parameters to be sent to restrict
|
||||
the volume_targets returned. Available parameters include:
|
||||
|
||||
* ``fields``: A list containing one or more fields to be returned
|
||||
in the response. This may lead to some performance gain
|
||||
because other fields of the resource are not refreshed.
|
||||
* ``limit``: Requests at most the specified number of
|
||||
volume_connector be returned from the query.
|
||||
* ``marker``: Specifies the ID of the last-seen volume_target.
|
||||
Use the ``limit`` parameter to make an initial limited request
|
||||
and use the ID of the last-seen volume_target from the
|
||||
response as the ``marker`` value in subsequent limited request.
|
||||
* ``node``:only return the ones associated with this specific node
|
||||
(name or UUID), or an empty set if not found.
|
||||
* ``sort_dir``:Sorts the response by the requested sort direction.
|
||||
A valid value is ``asc`` (ascending) or ``desc``
|
||||
(descending). Default is ``asc``. You can specify multiple
|
||||
pairs of sort key and sort direction query parameters. If
|
||||
you omit the sort direction in a pair, the API uses the
|
||||
natural sorting direction of the server attribute that is
|
||||
provided as the ``sort_key``.
|
||||
* ``sort_key``: Sorts the response by the this attribute value.
|
||||
Default is ``id``. You can specify multiple pairs of sort
|
||||
key and sort direction query parameters. If you omit the
|
||||
sort direction in a pair, the API uses the natural sorting
|
||||
direction of the server attribute that is provided as the
|
||||
``sort_key``.
|
||||
|
||||
:returns: A generator of volume_target instances.
|
||||
"""
|
||||
if details:
|
||||
query['detail'] = True
|
||||
return _volumetarget.VolumeTarget.list(self, **query)
|
||||
|
||||
def create_volume_target(self, **attrs):
|
||||
"""Create a new volume_target from attributes.
|
||||
|
||||
:param dict attrs: Keyword arguments that will be used to create a
|
||||
:class:
|
||||
`~openstack.baremetal.v1.volume_target.VolumeTarget`.
|
||||
|
||||
:returns: The results of volume_target creation.
|
||||
:rtype::class:
|
||||
`~openstack.baremetal.v1.volume_target.VolumeTarget`.
|
||||
"""
|
||||
return self._create(_volumetarget.VolumeTarget, **attrs)
|
||||
|
||||
def find_volume_target(self, vt_id, ignore_missing=True):
|
||||
"""Find a single volume target.
|
||||
|
||||
:param str vt_id: The ID of a volume target.
|
||||
|
||||
:param bool ignore_missing: When set to ``False``, an exception of
|
||||
:class:`~openstack.exceptions.ResourceNotFound` will be raised
|
||||
when the volume connector does not exist. When set to `True``,
|
||||
None will be returned when attempting to find a nonexistent
|
||||
volume target.
|
||||
:returns: One :class:
|
||||
`~openstack.baremetal.v1.volumetarget.VolumeTarget`
|
||||
object or None.
|
||||
"""
|
||||
return self._find(_volumetarget.VolumeTarget, vt_id,
|
||||
ignore_missing=ignore_missing)
|
||||
|
||||
def get_volume_target(self, volume_target, fields=None):
|
||||
"""Get a specific volume_target.
|
||||
|
||||
:param volume_target: The value can be the ID of a
|
||||
volume_target or a :class:
|
||||
`~openstack.baremetal.v1.volume_target.VolumeTarget
|
||||
instance.`
|
||||
:param fields: Limit the resource fields to fetch.`
|
||||
|
||||
:returns: One
|
||||
:class:
|
||||
`~openstack.baremetal.v1.volume_target.VolumeTarget`
|
||||
:raises: :class:`~openstack.exceptions.ResourceNotFound` when no
|
||||
volume_target matching the name or ID could be found.`
|
||||
"""
|
||||
return self._get_with_fields(_volumetarget.VolumeTarget,
|
||||
volume_target,
|
||||
fields=fields)
|
||||
|
||||
def update_volume_target(self, volume_target, **attrs):
|
||||
"""Update a volume_target.
|
||||
|
||||
:param volume_target:Either the ID of a volume_target
|
||||
or an instance of
|
||||
:class:`~openstack.baremetal.v1.volume_target.VolumeTarget.`
|
||||
:param dict attrs: The attributes to update on the
|
||||
volume_target represented by the ``volume_target`` parameter.`
|
||||
|
||||
:returns: The updated volume_target.
|
||||
:rtype::class:
|
||||
`~openstack.baremetal.v1.volume_target.VolumeTarget.`
|
||||
"""
|
||||
return self._update(_volumetarget.VolumeTarget,
|
||||
volume_target, **attrs)
|
||||
|
||||
def patch_volume_target(self, volume_target, patch):
|
||||
"""Apply a JSON patch to the volume_target.
|
||||
|
||||
:param volume_target: The value can be the ID of a
|
||||
volume_target or a :class:
|
||||
`~openstack.baremetal.v1.volume_target.VolumeTarget`
|
||||
instance.
|
||||
:param patch: JSON patch to apply.
|
||||
|
||||
:returns: The updated volume_target.
|
||||
:rtype::class:
|
||||
`~openstack.baremetal.v1.volume_target.VolumeTarget.`
|
||||
"""
|
||||
return self._get_resource(_volumetarget.VolumeTarget,
|
||||
volume_target).patch(self, patch)
|
||||
|
||||
def delete_volume_target(self, volume_target,
|
||||
ignore_missing=True):
|
||||
"""Delete an volume_target.
|
||||
|
||||
:param volume_target: The value can be either the ID of a
|
||||
volume_target.VolumeTarget or a
|
||||
:class:
|
||||
`~openstack.baremetal.v1.volume_target.VolumeTarget`
|
||||
instance.
|
||||
:param bool ignore_missing: When set to ``False``, an exception
|
||||
:class:`~openstack.exceptions.ResourceNotFound` will be raised
|
||||
when the volume_target could not be found.
|
||||
When set to ``True``, no exception will be raised when
|
||||
attempting to delete a non-existent volume_target.
|
||||
|
||||
:returns: The instance of the volume_target which was deleted.
|
||||
:rtype::class:
|
||||
`~openstack.baremetal.v1.volume_target.VolumeTarget`.
|
||||
"""
|
||||
return self._delete(_volumetarget.VolumeTarget,
|
||||
volume_target, ignore_missing=ignore_missing)
|
||||
|
60
openstack/baremetal/v1/volume_target.py
Normal file
60
openstack/baremetal/v1/volume_target.py
Normal file
@ -0,0 +1,60 @@
|
||||
# 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 openstack.baremetal.v1 import _common
|
||||
from openstack import resource
|
||||
|
||||
|
||||
class VolumeTarget(_common.ListMixin, resource.Resource):
|
||||
|
||||
resources_key = 'targets'
|
||||
base_path = '/volume/targets'
|
||||
|
||||
# capabilities
|
||||
allow_create = True
|
||||
allow_fetch = True
|
||||
allow_commit = True
|
||||
allow_delete = True
|
||||
allow_list = True
|
||||
allow_patch = True
|
||||
commit_method = 'PATCH'
|
||||
commit_jsonpatch = True
|
||||
|
||||
_query_mapping = resource.QueryParameters(
|
||||
'node', 'detail',
|
||||
fields={'type': _common.fields_type},
|
||||
)
|
||||
|
||||
# Volume Targets is available since 1.32
|
||||
_max_microversion = '1.32'
|
||||
|
||||
#: The boot index of the Volume target. “0” indicates that this volume is
|
||||
# used as a boot volume.
|
||||
boot_index = resource.Body('boot_index')
|
||||
#: Timestamp at which the port was created.
|
||||
created_at = resource.Body('created_at')
|
||||
#: A set of one or more arbitrary metadata key and value pairs.
|
||||
extra = resource.Body('extra')
|
||||
#: A list of relative links. Includes the self and bookmark links.
|
||||
links = resource.Body('links', type=list)
|
||||
#: The UUID of the Node this resource belongs to.
|
||||
node_id = resource.Body('node_uuid')
|
||||
#: A set of physical information of the volume.
|
||||
properties = resource.Body('properties')
|
||||
#: Timestamp at which the port was last updated.
|
||||
updated_at = resource.Body('updated_at')
|
||||
#: The UUID of the resource.
|
||||
id = resource.Body('uuid', alternate_id=True)
|
||||
#: The identifier of the volume.
|
||||
volume_id = resource.Body('volume_id')
|
||||
#: The type of Volume target.
|
||||
volume_type = resource.Body('volume_type')
|
@ -73,3 +73,14 @@ class BaseBaremetalTest(base.BaseFunctionalTest):
|
||||
self.conn.baremetal.delete_volume_connector(volume_connector.id,
|
||||
ignore_missing=True))
|
||||
return volume_connector
|
||||
|
||||
def create_volume_target(self, node_id=None, **kwargs):
|
||||
node_id = node_id or self.node_id
|
||||
volume_target = self.conn.baremetal.create_volume_target(
|
||||
node_uuid=node_id, **kwargs)
|
||||
|
||||
self.addCleanup(
|
||||
lambda:
|
||||
self.conn.baremetal.delete_volume_target(volume_target.id,
|
||||
ignore_missing=True))
|
||||
return volume_target
|
||||
|
@ -0,0 +1,179 @@
|
||||
# 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 openstack import exceptions
|
||||
from openstack.tests.functional.baremetal import base
|
||||
|
||||
|
||||
class TestBareMetalVolumetarget(base.BaseBaremetalTest):
|
||||
|
||||
min_microversion = '1.32'
|
||||
|
||||
def setUp(self):
|
||||
super(TestBareMetalVolumetarget, self).setUp()
|
||||
self.node = self.create_node(provision_state='enroll')
|
||||
|
||||
def test_volume_target_create_get_delete(self):
|
||||
self.conn.baremetal.set_node_provision_state(
|
||||
self.node, 'manage', wait=True)
|
||||
self.conn.baremetal.set_node_power_state(self.node, 'power off')
|
||||
volume_target = self.create_volume_target(
|
||||
boot_index=0,
|
||||
volume_id='04452bed-5367-4202-8bf5-de4335ac56d2',
|
||||
volume_type='iscsi')
|
||||
|
||||
loaded = self.conn.baremetal.get_volume_target(
|
||||
volume_target.id)
|
||||
self.assertEqual(loaded.id, volume_target.id)
|
||||
self.assertIsNotNone(loaded.node_id)
|
||||
|
||||
with_fields = self.conn.baremetal.get_volume_target(
|
||||
volume_target.id, fields=['uuid', 'extra'])
|
||||
self.assertEqual(volume_target.id, with_fields.id)
|
||||
self.assertIsNone(with_fields.node_id)
|
||||
|
||||
self.conn.baremetal.delete_volume_target(volume_target,
|
||||
ignore_missing=False)
|
||||
self.assertRaises(exceptions.ResourceNotFound,
|
||||
self.conn.baremetal.get_volume_target,
|
||||
volume_target.id)
|
||||
|
||||
def test_volume_target_list(self):
|
||||
node2 = self.create_node(name='test-node')
|
||||
self.conn.baremetal.set_node_provision_state(
|
||||
node2, 'manage', wait=True)
|
||||
self.conn.baremetal.set_node_power_state(node2, 'power off')
|
||||
self.conn.baremetal.set_node_provision_state(
|
||||
self.node, 'manage', wait=True)
|
||||
self.conn.baremetal.set_node_power_state(self.node, 'power off')
|
||||
vt1 = self.create_volume_target(
|
||||
boot_index=0,
|
||||
volume_id='bd4d008c-7d31-463d-abf9-6c23d9d55f7f',
|
||||
node_id=node2.id,
|
||||
volume_type='iscsi')
|
||||
vt2 = self.create_volume_target(
|
||||
boot_index=0,
|
||||
volume_id='04452bed-5367-4202-8bf5-de4335ac57c2',
|
||||
node_id=self.node.id,
|
||||
volume_type='iscsi')
|
||||
|
||||
vts = self.conn.baremetal.volume_targets(
|
||||
node=self.node.id)
|
||||
self.assertEqual([v.id for v in vts], [vt2.id])
|
||||
|
||||
vts = self.conn.baremetal.volume_targets(node=node2.id)
|
||||
self.assertEqual([v.id for v in vts], [vt1.id])
|
||||
|
||||
vts = self.conn.baremetal.volume_targets(node='test-node')
|
||||
self.assertEqual([v.id for v in vts], [vt1.id])
|
||||
|
||||
vts_with_details = self.conn.baremetal.volume_targets(details=True)
|
||||
for i in vts_with_details:
|
||||
self.assertIsNotNone(i.id)
|
||||
self.assertIsNotNone(i.volume_type)
|
||||
|
||||
vts_with_fields = self.conn.baremetal.volume_targets(
|
||||
fields=['uuid', 'node_uuid'])
|
||||
for i in vts_with_fields:
|
||||
self.assertIsNotNone(i.id)
|
||||
self.assertIsNone(i.volume_type)
|
||||
self.assertIsNotNone(i.node_id)
|
||||
|
||||
def test_volume_target_list_update_delete(self):
|
||||
self.conn.baremetal.set_node_provision_state(
|
||||
self.node, 'manage', wait=True)
|
||||
self.conn.baremetal.set_node_power_state(self.node, 'power off')
|
||||
self.create_volume_target(
|
||||
boot_index=0,
|
||||
volume_id='04452bed-5367-4202-8bf5-de4335ac57h3',
|
||||
node_id=self.node.id,
|
||||
volume_type='iscsi',
|
||||
extra={'foo': 'bar'})
|
||||
volume_target = next(self.conn.baremetal.volume_targets(
|
||||
details=True,
|
||||
node=self.node.id))
|
||||
self.assertEqual(volume_target.extra, {'foo': 'bar'})
|
||||
|
||||
# This test checks that resources returned from listing are usable
|
||||
self.conn.baremetal.update_volume_target(volume_target,
|
||||
extra={'foo': 42})
|
||||
self.conn.baremetal.delete_volume_target(volume_target,
|
||||
ignore_missing=False)
|
||||
|
||||
def test_volume_target_update(self):
|
||||
self.conn.baremetal.set_node_provision_state(
|
||||
self.node, 'manage', wait=True)
|
||||
self.conn.baremetal.set_node_power_state(self.node, 'power off')
|
||||
volume_target = self.create_volume_target(
|
||||
boot_index=0,
|
||||
volume_id='04452bed-5367-4202-8bf5-de4335ac53h7',
|
||||
node_id=self.node.id,
|
||||
volume_type='isci')
|
||||
volume_target.extra = {'answer': 42}
|
||||
|
||||
volume_target = self.conn.baremetal.update_volume_target(
|
||||
volume_target)
|
||||
self.assertEqual({'answer': 42}, volume_target.extra)
|
||||
|
||||
volume_target = self.conn.baremetal.get_volume_target(
|
||||
volume_target.id)
|
||||
self.assertEqual({'answer': 42}, volume_target.extra)
|
||||
|
||||
def test_volume_target_patch(self):
|
||||
vol_targ_id = '04452bed-5367-4202-9cg6-de4335ac53h7'
|
||||
self.conn.baremetal.set_node_provision_state(
|
||||
self.node, 'manage', wait=True)
|
||||
self.conn.baremetal.set_node_power_state(self.node, 'power off')
|
||||
volume_target = self.create_volume_target(
|
||||
boot_index=0,
|
||||
volume_id=vol_targ_id,
|
||||
node_id=self.node.id,
|
||||
volume_type='isci')
|
||||
|
||||
volume_target = self.conn.baremetal.patch_volume_target(
|
||||
volume_target, dict(path='/extra/answer', op='add', value=42))
|
||||
self.assertEqual({'answer': 42}, volume_target.extra)
|
||||
self.assertEqual(vol_targ_id,
|
||||
volume_target.volume_id)
|
||||
|
||||
volume_target = self.conn.baremetal.get_volume_target(
|
||||
volume_target.id)
|
||||
self.assertEqual({'answer': 42}, volume_target.extra)
|
||||
|
||||
def test_volume_target_negative_non_existing(self):
|
||||
uuid = "5c9dcd04-2073-49bc-9618-99ae634d8971"
|
||||
self.assertRaises(exceptions.ResourceNotFound,
|
||||
self.conn.baremetal.get_volume_target, uuid)
|
||||
self.assertRaises(exceptions.ResourceNotFound,
|
||||
self.conn.baremetal.find_volume_target, uuid,
|
||||
ignore_missing=False)
|
||||
self.assertRaises(exceptions.ResourceNotFound,
|
||||
self.conn.baremetal.delete_volume_target, uuid,
|
||||
ignore_missing=False)
|
||||
self.assertIsNone(self.conn.baremetal.find_volume_target(uuid))
|
||||
self.assertIsNone(self.conn.baremetal.delete_volume_target(uuid))
|
||||
|
||||
def test_volume_target_fields(self):
|
||||
self.create_node()
|
||||
self.conn.baremetal.set_node_provision_state(
|
||||
self.node, 'manage', wait=True)
|
||||
self.conn.baremetal.set_node_power_state(self.node, 'power off')
|
||||
self.create_volume_target(
|
||||
boot_index=0,
|
||||
volume_id='04452bed-5367-4202-8bf5-99ae634d8971',
|
||||
node_id=self.node.id,
|
||||
volume_type='iscsi')
|
||||
result = self.conn.baremetal.volume_targets(
|
||||
fields=['uuid', 'node_id'])
|
||||
for item in result:
|
||||
self.assertIsNotNone(item.id)
|
@ -20,6 +20,7 @@ from openstack.baremetal.v1 import node
|
||||
from openstack.baremetal.v1 import port
|
||||
from openstack.baremetal.v1 import port_group
|
||||
from openstack.baremetal.v1 import volume_connector
|
||||
from openstack.baremetal.v1 import volume_target
|
||||
from openstack import exceptions
|
||||
from openstack.tests.unit import base
|
||||
from openstack.tests.unit import test_proxy_base
|
||||
@ -205,6 +206,42 @@ class TestBaremetalProxy(test_proxy_base.TestProxyBase):
|
||||
volume_connector.VolumeConnector,
|
||||
True)
|
||||
|
||||
@mock.patch.object(volume_target.VolumeTarget, 'list')
|
||||
def test_volume_target_detailed(self, mock_list):
|
||||
result = self.proxy.volume_targets(details=True, query=1)
|
||||
self.assertIs(result, mock_list.return_value)
|
||||
mock_list.assert_called_once_with(self.proxy, detail=True, query=1)
|
||||
|
||||
@mock.patch.object(volume_target.VolumeTarget, 'list')
|
||||
def test_volume_target_not_detailed(self, mock_list):
|
||||
result = self.proxy.volume_targets(query=1)
|
||||
self.assertIs(result, mock_list.return_value)
|
||||
mock_list.assert_called_once_with(self.proxy, query=1)
|
||||
|
||||
def test_create_volume_target(self):
|
||||
self.verify_create(self.proxy.create_volume_target,
|
||||
volume_target.VolumeTarget)
|
||||
|
||||
def test_find_volume_target(self):
|
||||
self.verify_find(self.proxy.find_volume_target,
|
||||
volume_target.VolumeTarget)
|
||||
|
||||
def test_get_volume_target(self):
|
||||
self.verify_get(self.proxy.get_volume_target,
|
||||
volume_target.VolumeTarget,
|
||||
mock_method=_MOCK_METHOD,
|
||||
expected_kwargs={'fields': None})
|
||||
|
||||
def test_delete_volume_target(self):
|
||||
self.verify_delete(self.proxy.delete_volume_target,
|
||||
volume_target.VolumeTarget,
|
||||
False)
|
||||
|
||||
def test_delete_volume_target_ignore(self):
|
||||
self.verify_delete(self.proxy.delete_volume_target,
|
||||
volume_target.VolumeTarget,
|
||||
True)
|
||||
|
||||
@mock.patch.object(node.Node, 'fetch', autospec=True)
|
||||
def test__get_with_fields_none(self, mock_fetch):
|
||||
result = self.proxy._get_with_fields(node.Node, 'value')
|
||||
|
65
openstack/tests/unit/baremetal/v1/test_volume_target.py
Normal file
65
openstack/tests/unit/baremetal/v1/test_volume_target.py
Normal file
@ -0,0 +1,65 @@
|
||||
# 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 openstack.tests.unit import base
|
||||
|
||||
from openstack.baremetal.v1 import volume_target
|
||||
|
||||
FAKE = {
|
||||
"boot_index": 0,
|
||||
"created_at": "2016-08-18T22:28:48.643434+11:11",
|
||||
"extra": {},
|
||||
"links": [
|
||||
{
|
||||
"href": "http://127.0.0.1:6385/v1/volume/targets/<ID>",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://127.0.0.1:6385/volume/targets/<ID>",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"node_uuid": "6d85703a-565d-469a-96ce-30b6de53079d",
|
||||
"properties": {},
|
||||
"updated_at": None,
|
||||
"uuid": "bd4d008c-7d31-463d-abf9-6c23d9d55f7f",
|
||||
"volume_id": "04452bed-5367-4202-8bf5-de4335ac56d2",
|
||||
"volume_type": "iscsi"
|
||||
}
|
||||
|
||||
|
||||
class TestVolumeTarget(base.TestCase):
|
||||
|
||||
def test_basic(self):
|
||||
sot = volume_target.VolumeTarget()
|
||||
self.assertIsNone(sot.resource_key)
|
||||
self.assertEqual('targets', sot.resources_key)
|
||||
self.assertEqual('/volume/targets', sot.base_path)
|
||||
self.assertTrue(sot.allow_create)
|
||||
self.assertTrue(sot.allow_fetch)
|
||||
self.assertTrue(sot.allow_commit)
|
||||
self.assertTrue(sot.allow_delete)
|
||||
self.assertTrue(sot.allow_list)
|
||||
self.assertEqual('PATCH', sot.commit_method)
|
||||
|
||||
def test_instantiate(self):
|
||||
sot = volume_target.VolumeTarget(**FAKE)
|
||||
self.assertEqual(FAKE['boot_index'], sot.boot_index)
|
||||
self.assertEqual(FAKE['created_at'], sot.created_at)
|
||||
self.assertEqual(FAKE['extra'], sot.extra)
|
||||
self.assertEqual(FAKE['links'], sot.links)
|
||||
self.assertEqual(FAKE['node_uuid'], sot.node_id)
|
||||
self.assertEqual(FAKE['properties'], sot.properties)
|
||||
self.assertEqual(FAKE['updated_at'], sot.updated_at)
|
||||
self.assertEqual(FAKE['uuid'], sot.id)
|
||||
self.assertEqual(FAKE['volume_id'], sot.volume_id)
|
||||
self.assertEqual(FAKE['volume_type'], sot.volume_type)
|
@ -0,0 +1,4 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Support for Ironic Volume Target API.
|
Loading…
Reference in New Issue
Block a user