baremetal: support for volume connectors API

adding volume connectors feature.

Change-Id: Id021456e4b52928bd6303a8d400a75de8d1cbf01
Story: #2007416
Task: #39036
Signed-off-by: subham rai <subham.k.rai@gmail.com>
This commit is contained in:
subham rai 2020-04-09 21:50:16 +05:30
parent 1a032b8c60
commit 0d691f78e1
10 changed files with 483 additions and 0 deletions

View File

@ -61,6 +61,14 @@ Allocation Operations
update_allocation, patch_allocation, delete_allocation,
wait_for_allocation
Volume Connector Operations
^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. autoclass:: openstack.baremetal.v1._proxy.Proxy
:noindex:
:members: volume_connectors, find_volume_connector, get_volume_connector,
create_volume_connector, update_volume_connector,
patch_volume_connector, delete_volume_connector
Utilities
---------

View File

@ -10,3 +10,4 @@ Baremetal Resources
v1/port
v1/port_group
v1/allocation
v1/volume_connector

View File

@ -0,0 +1,13 @@
openstack.baremetal.v1.volume_connector
=======================================
.. automodule:: openstack.baremetal.v1.volume_connector
The VolumeConnector Class
-------------------------
The ``VolumeConnector`` class inherits
from :class:`~openstack.resource.Resource`.
.. autoclass:: openstack.baremetal.v1.volume_connector.VolumeConnector
:members:

View File

@ -17,6 +17,7 @@ from openstack.baremetal.v1 import driver as _driver
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 import exceptions
from openstack import proxy
from openstack import utils
@ -1003,3 +1004,145 @@ class Proxy(proxy.Proxy):
"""
res = self._get_resource(_node.Node, node)
return res.set_traits(self, traits)
def volume_connectors(self, details=False, **query):
"""Retrieve a generator of volume_connector.
:param details: A boolean indicating whether the detailed information
for every volume_connector should be returned.
:param dict query: Optional query parameters to be sent to restrict
the volume_connectors 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_connector.
Use the ``limit`` parameter to make an initial limited request
and use the ID of the last-seen volume_connector 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_connector instances.
"""
if details:
query['detail'] = True
return _volumeconnector.VolumeConnector.list(self, **query)
def create_volume_connector(self, **attrs):
"""Create a new volume_connector from attributes.
:param dict attrs: Keyword arguments that will be used to create a
:class:
`~openstack.baremetal.v1.volume_connector.VolumeConnector`.
:returns: The results of volume_connector creation.
:rtype::class:
`~openstack.baremetal.v1.volume_connector.VolumeConnector`.
"""
return self._create(_volumeconnector.VolumeConnector, **attrs)
def find_volume_connector(self, vc_id, ignore_missing=True):
"""Find a single volume connector.
:param str vc_id: The ID of a volume connector.
: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 connector.
:returns: One :class:
`~openstack.baremetal.v1.volumeconnector.VolumeConnector`
object or None.
"""
return self._find(_volumeconnector.VolumeConnector, vc_id,
ignore_missing=ignore_missing)
def get_volume_connector(self, volume_connector, fields=None):
"""Get a specific volume_connector.
:param volume_connector: The value can be the ID of a
volume_connector or a :class:
`~openstack.baremetal.v1.volume_connector.VolumeConnector
instance.`
:param fields: Limit the resource fields to fetch.`
:returns: One
:class:
`~openstack.baremetal.v1.volume_connector.VolumeConnector`
:raises: :class:`~openstack.exceptions.ResourceNotFound` when no
volume_connector matching the name or ID could be found.`
"""
return self._get_with_fields(_volumeconnector.VolumeConnector,
volume_connector,
fields=fields)
def update_volume_connector(self, volume_connector, **attrs):
"""Update a volume_connector.
:param volume_connector:Either the ID of a volume_connector
or an instance of
:class:`~openstack.baremetal.v1.volume_connector.VolumeConnector.`
:param dict attrs: The attributes to update on the
volume_connector represented by the ``volume_connector`` parameter.`
:returns: The updated volume_connector.
:rtype::class:
`~openstack.baremetal.v1.volume_connector.VolumeConnector.`
"""
return self._update(_volumeconnector.VolumeConnector,
volume_connector, **attrs)
def patch_volume_connector(self, volume_connector, patch):
"""Apply a JSON patch to the volume_connector.
:param volume_connector: The value can be the ID of a
volume_connector or a :class:
`~openstack.baremetal.v1.volume_connector.VolumeConnector`
instance.
:param patch: JSON patch to apply.
:returns: The updated volume_connector.
:rtype::class:
`~openstack.baremetal.v1.volume_connector.VolumeConnector.`
"""
return self._get_resource(_volumeconnector.VolumeConnector,
volume_connector).patch(self, patch)
def delete_volume_connector(self, volume_connector,
ignore_missing=True):
"""Delete an volume_connector.
:param volume_connector: The value can be either the ID of a
volume_connector.VolumeConnector or a
:class:
`~openstack.baremetal.v1.volume_connector.VolumeConnector`
instance.
:param bool ignore_missing: When set to ``False``, an exception
:class:`~openstack.exceptions.ResourceNotFound` will be raised
when the volume_connector could not be found.
When set to ``True``, no exception will be raised when
attempting to delete a non-existent volume_connector.
:returns: The instance of the volume_connector which was deleted.
:rtype::class:
`~openstack.baremetal.v1.volume_connector.VolumeConnector`.
"""
return self._delete(_volumeconnector.VolumeConnector,
volume_connector, ignore_missing=ignore_missing)

View File

@ -0,0 +1,56 @@
# 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 VolumeConnector(_common.ListMixin, resource.Resource):
resources_key = 'connectors'
base_path = '/volume/connectors'
# 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 Connectors is available since 1.32
_max_microversion = '1.32'
#: The identifier of Volume connector and this field depends on the "type"
# of the volume_connector
connector_id = resource.Body('connector_id')
#: 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, including the self and bookmark links.
links = resource.Body('links', type=list)
#: The UUID of node this port belongs to
node_id = resource.Body('node_uuid')
#: The types of Volume connector
type = resource.Body('type')
#: Timestamp at which the port was last updated.
updated_at = resource.Body('updated_at')
#: The UUID of the port
id = resource.Body('uuid', alternate_id=True)

View File

@ -62,3 +62,14 @@ class BaseBaremetalTest(base.BaseFunctionalTest):
lambda: self.conn.baremetal.delete_port_group(port_group.id,
ignore_missing=True))
return port_group
def create_volume_connector(self, node_id=None, **kwargs):
node_id = node_id or self.node_id
volume_connector = self.conn.baremetal.create_volume_connector(
node_uuid=node_id, **kwargs)
self.addCleanup(
lambda:
self.conn.baremetal.delete_volume_connector(volume_connector.id,
ignore_missing=True))
return volume_connector

View File

@ -0,0 +1,161 @@
# 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 TestBareMetalVolumeconnector(base.BaseBaremetalTest):
min_microversion = '1.32'
def setUp(self):
super(TestBareMetalVolumeconnector, self).setUp()
self.node = self.create_node(provision_state='enroll')
def test_volume_connector_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_connector = self.create_volume_connector(
connector_id='iqn.2017-07.org.openstack:01:d9a51732c3f',
type='iqn')
loaded = self.conn.baremetal.get_volume_connector(
volume_connector.id)
self.assertEqual(loaded.id, volume_connector.id)
self.assertIsNotNone(loaded.node_id)
with_fields = self.conn.baremetal.get_volume_connector(
volume_connector.id, fields=['uuid', 'extra'])
self.assertEqual(volume_connector.id, with_fields.id)
self.assertIsNone(with_fields.node_id)
self.conn.baremetal.delete_volume_connector(volume_connector,
ignore_missing=False)
self.assertRaises(exceptions.ResourceNotFound,
self.conn.baremetal.get_volume_connector,
volume_connector.id)
def test_volume_connector_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')
vc1 = self.create_volume_connector(
connector_id='iqn.2018-07.org.openstack:01:d9a514g2c32',
node_id=node2.id,
type='iqn')
vc2 = self.create_volume_connector(
connector_id='iqn.2017-07.org.openstack:01:d9a51732c4g',
node_id=self.node.id,
type='iqn')
vcs = self.conn.baremetal.volume_connectors(
node=self.node.id)
self.assertEqual([v.id for v in vcs], [vc2.id])
vcs = self.conn.baremetal.volume_connectors(node=node2.id)
self.assertEqual([v.id for v in vcs], [vc1.id])
vcs = self.conn.baremetal.volume_connectors(node='test-node')
self.assertEqual([v.id for v in vcs], [vc1.id])
def test_volume_connector_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_connector(
connector_id='iqn.2020-07.org.openstack:02:d9451472ce2',
node_id=self.node.id,
type='iqn',
extra={'foo': 'bar'})
volume_connector = next(self.conn.baremetal.volume_connectors(
details=True,
node=self.node.id))
self.assertEqual(volume_connector.extra, {'foo': 'bar'})
# This test checks that resources returned from listing are usable
self.conn.baremetal.update_volume_connector(volume_connector,
extra={'foo': 42})
self.conn.baremetal.delete_volume_connector(volume_connector,
ignore_missing=False)
def test_volume_connector_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_connector = self.create_volume_connector(
connector_id='iqn.2019-07.org.openstack:03:de45b472c40',
node_id=self.node.id,
type='iqn')
volume_connector.extra = {'answer': 42}
volume_connector = self.conn.baremetal.update_volume_connector(
volume_connector)
self.assertEqual({'answer': 42}, volume_connector.extra)
volume_connector = self.conn.baremetal.get_volume_connector(
volume_connector.id)
self.assertEqual({'answer': 42}, volume_connector.extra)
def test_volume_connector_patch(self):
vol_conn_id = 'iqn.2020-07.org.openstack:04:de45b472c40'
self.conn.baremetal.set_node_provision_state(
self.node, 'manage', wait=True)
self.conn.baremetal.set_node_power_state(self.node, 'power off')
volume_connector = self.create_volume_connector(
connector_id=vol_conn_id,
node_id=self.node.id,
type='iqn')
volume_connector = self.conn.baremetal.patch_volume_connector(
volume_connector, dict(path='/extra/answer', op='add', value=42))
self.assertEqual({'answer': 42}, volume_connector.extra)
self.assertEqual(vol_conn_id,
volume_connector.connector_id)
volume_connector = self.conn.baremetal.get_volume_connector(
volume_connector.id)
self.assertEqual({'answer': 42}, volume_connector.extra)
def test_volume_connector_negative_non_existing(self):
uuid = "5c9dcd04-2073-49bc-9618-99ae634d8971"
self.assertRaises(exceptions.ResourceNotFound,
self.conn.baremetal.get_volume_connector, uuid)
self.assertRaises(exceptions.ResourceNotFound,
self.conn.baremetal.find_volume_connector, uuid,
ignore_missing=False)
self.assertRaises(exceptions.ResourceNotFound,
self.conn.baremetal.delete_volume_connector, uuid,
ignore_missing=False)
self.assertIsNone(self.conn.baremetal.find_volume_connector(uuid))
self.assertIsNone(self.conn.baremetal.delete_volume_connector(uuid))
def test_volume_connector_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_connector(
connector_id='iqn.2018-08.org.openstack:04:de45f37c48',
node_id=self.node.id,
type='iqn')
result = self.conn.baremetal.volume_connectors(
fields=['uuid', 'node_id'])
for item in result:
self.assertIsNotNone(item.id)
self.assertIsNone(item.connector_id)

View File

@ -19,6 +19,7 @@ from openstack.baremetal.v1 import driver
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 import exceptions
from openstack.tests.unit import base
from openstack.tests.unit import test_proxy_base
@ -180,6 +181,30 @@ class TestBaremetalProxy(test_proxy_base.TestProxyBase):
self.verify_delete(self.proxy.delete_allocation, allocation.Allocation,
True)
def test_create_volume_connector(self):
self.verify_create(self.proxy.create_volume_connector,
volume_connector.VolumeConnector)
def test_find_volume_connector(self):
self.verify_find(self.proxy.find_volume_connector,
volume_connector.VolumeConnector)
def test_get_volume_connector(self):
self.verify_get(self.proxy.get_volume_connector,
volume_connector.VolumeConnector,
mock_method=_MOCK_METHOD,
expected_kwargs={'fields': None})
def test_delete_volume_connector(self):
self.verify_delete(self.proxy.delete_volume_connector,
volume_connector.VolumeConnector,
False)
def test_delete_volume_connector_ignore(self):
self.verify_delete(self.proxy.delete_volume_connector,
volume_connector.VolumeConnector,
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')

View File

@ -0,0 +1,61 @@
# 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_connector
FAKE = {
"connector_id": "iqn.2017-07.org.openstack:01:d9a51732c3f",
"created_at": "2016-08-18T22:28:48.643434+11:11",
"extra": {},
"links": [
{
"href": "http://127.0.0.1:6385/v1/volume/connector/<ID>",
"rel": "self"
},
{
"href": "http://127.0.0.1:6385/volume/connector/<ID>",
"rel": "bookmark"
}
],
"node_uuid": "6d85703a-565d-469a-96ce-30b6de53079d",
"type": "iqn",
"updated_at": None,
"uuid": "9bf93e01-d728-47a3-ad4b-5e66a835037c"
}
class TestVolumeconnector(base.TestCase):
def test_basic(self):
sot = volume_connector.VolumeConnector()
self.assertIsNone(sot.resource_key)
self.assertEqual('connectors', sot.resources_key)
self.assertEqual('/volume/connectors', 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_connector.VolumeConnector(**FAKE)
self.assertEqual(FAKE['connector_id'], sot.connector_id)
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['type'], sot.type)
self.assertEqual(FAKE['updated_at'], sot.updated_at)
self.assertEqual(FAKE['uuid'], sot.id)

View File

@ -0,0 +1,4 @@
---
features:
- |
Adds support for the baremetal volume connector API.