Merge "placement: Add support for resource providers"

This commit is contained in:
Zuul 2021-04-23 18:41:27 +00:00 committed by Gerrit Code Review
commit 2392508d27
19 changed files with 401 additions and 1 deletions

View File

@ -108,6 +108,7 @@ control which services can be used.
Network <proxies/network> Network <proxies/network>
Object Store <proxies/object_store> Object Store <proxies/object_store>
Orchestration <proxies/orchestration> Orchestration <proxies/orchestration>
Placement <proxies/placement>
Shared File System <proxies/shared_file_system> Shared File System <proxies/shared_file_system>
Workflow <proxies/workflow> Workflow <proxies/workflow>
@ -141,6 +142,7 @@ The following services have exposed *Resource* classes.
Network <resources/network/index> Network <resources/network/index>
Orchestration <resources/orchestration/index> Orchestration <resources/orchestration/index>
Object Store <resources/object_store/index> Object Store <resources/object_store/index>
Placement <resources/placement/index>
Shared File System <resources/shared_file_system/index> Shared File System <resources/shared_file_system/index>
Workflow <resources/workflow/index> Workflow <resources/workflow/index>

View File

@ -0,0 +1,21 @@
Placement API
=============
.. automodule:: openstack.placement.v1._proxy
The Placement Class
-------------------
The placement high-level interface is available through the ``placement``
member of a :class:`~openstack.connection.Connection` object.
The ``placement`` member will only be added if the service is detected.
Resource Providers
^^^^^^^^^^^^^^^^^^
.. autoclass:: openstack.placement.v1._proxy.Proxy
:noindex:
:members: create_resource_provider, update_resource_provider,
delete_resource_provider, get_resource_provider,
resource_providers

View File

@ -0,0 +1,7 @@
Placement v1 Resources
======================
.. toctree::
:maxdepth: 1
v1/resource_provider

View File

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

View File

@ -17,6 +17,7 @@ from openstack.message import message_service
from openstack.network import network_service from openstack.network import network_service
from openstack.object_store import object_store_service from openstack.object_store import object_store_service
from openstack.orchestration import orchestration_service from openstack.orchestration import orchestration_service
from openstack.placement import placement_service
from openstack.shared_file_system import shared_file_system_service from openstack.shared_file_system import shared_file_system_service
from openstack.workflow import workflow_service from openstack.workflow import workflow_service
@ -117,7 +118,7 @@ class ServicesMixin:
monitoring_events = service_description.ServiceDescription(service_type='monitoring-events') monitoring_events = service_description.ServiceDescription(service_type='monitoring-events')
placement = service_description.ServiceDescription(service_type='placement') placement = placement_service.PlacementService(service_type='placement')
instance_ha = instance_ha_service.InstanceHaService(service_type='instance-ha') instance_ha = instance_ha_service.InstanceHaService(service_type='instance-ha')
ha = instance_ha ha = instance_ha

View File

View File

@ -0,0 +1,21 @@
# 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.placement.v1 import _proxy
from openstack import service_description
class PlacementService(service_description.ServiceDescription):
"""The placement service."""
supported_versions = {
'1': _proxy.Proxy,
}

View File

View File

@ -0,0 +1,114 @@
# 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.placement.v1 import resource_provider as _resource_provider
from openstack import proxy
class Proxy(proxy.Proxy):
def create_resource_provider(self, **attrs):
"""Create a new resource provider from attributes.
:param attrs: Keyword arguments which will be used to create a
:class:`~openstack.placement.v1.resource_provider.ResourceProvider`,
comprised of the properties on the ResourceProvider class.
:returns: The results of resource provider creation
:rtype: :class:`~openstack.placement.v1.resource_provider.ResourceProvider`
""" # noqa: E501
return self._create(_resource_provider.ResourceProvider, **attrs)
def delete_resource_provider(self, resource_provider, ignore_missing=True):
"""Delete a resource provider
:param resource_provider: The value can be either the ID of a resource
provider or an
:class:`~openstack.placement.v1.resource_provider.ResourceProvider`,
instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be raised when
the resource provider does not exist. When set to ``True``, no
exception will be set when attempting to delete a nonexistent
resource provider.
:returns: ``None``
"""
self._delete(
_resource_provider.ResourceProvider,
resource_provider,
ignore_missing=ignore_missing,
)
def update_resource_provider(self, resource_provider, **attrs):
"""Update a flavor
:param resource_provider: The value can be either the ID of a resource
provider or an
:class:`~openstack.placement.v1.resource_provider.ResourceProvider`,
instance.
:attrs kwargs: The attributes to update on the resource provider
represented by ``resource_provider``.
:returns: The updated resource provider
:rtype: :class:`~openstack.placement.v1.resource_provider.ResourceProvider`
""" # noqa: E501
return self._update(
_resource_provider.ResourceProvider, resource_provider, **attrs,
)
def get_resource_provider(self, resource_provider):
"""Get a single resource_provider.
:param resource_provider: The value can be either the ID of a resource
provider or an
:class:`~openstack.placement.v1.resource_provider.ResourceProvider`,
instance.
:returns: An instance of
:class:`~openstack.placement.v1.resource_provider.ResourceProvider`
:raises: :class:`~openstack.exceptions.ResourceNotFound` when no
resource provider matching the criteria could be found.
"""
return self._get(
_resource_provider.ResourceProvider, resource_provider,
)
def find_resource_provider(self, name_or_id, ignore_missing=True):
"""Find a single resource_provider.
:param name_or_id: The name or ID of a resource provider.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be raised when
the resource does not exist. When set to ``True``, None will be
returned when attempting to find a nonexistent resource.
:returns: An instance of
:class:`~openstack.placement.v1.resource_provider.ResourceProvider`
:raises: :class:`~openstack.exceptions.ResourceNotFound` when no
resource provider matching the criteria could be found.
"""
return self._find(
_resource_provider.ResourceProvider,
name_or_id,
ignore_missing=ignore_missing,
)
def resource_providers(self, **query):
"""Retrieve a generator of resource providers.
:param kwargs query: Optional query parameters to be sent to
restrict the resource providers to be returned.
:returns: A generator of resource provider instances.
"""
return self._list(_resource_provider.ResourceProvider, **query)

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 import resource
class ResourceProvider(resource.Resource):
resource_key = None
resources_key = 'resource_providers'
base_path = '/resource_providers'
# Capabilities
allow_create = True
allow_fetch = True
allow_commit = True
allow_delete = True
allow_list = True
# Filters
_query_mapping = resource.QueryParameters(
'name', 'member_of', 'resources', 'in_tree', 'required', id='uuid',
)
# The parent_provider_uuid and root_provider_uuid fields were introduced in
# 1.14
# The required query parameter was added in 1.18
# The create operation started returning a body in 1.20
_max_microversion = '1.20'
# Properties
#: The UUID of a resource provider.
id = resource.Body('uuid', alternate_id=True)
#: A consistent view marker that assists with the management of concurrent
#: resource provider updates.
generation = resource.Body('generation')
#: Links pertaining to this flavor. This is a list of dictionaries,
#: each including keys ``href`` and ``rel``.
links = resource.Body('links')
#: The name of this resource provider.
name = resource.Body('name')
#: The UUID of the immediate parent of the resource provider.
parent_provider_id = resource.Body('parent_provider_uuid')
#: Read-only UUID of the top-most provider in this provider tree.
root_provider_id = resource.Body('root_provider_uuid')

View File

@ -0,0 +1,47 @@
# 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.placement.v1 import resource_provider
from openstack.tests.functional import base
class TestResourceProvider(base.BaseFunctionalTest):
def setUp(self):
super().setUp()
self._set_operator_cloud(interface='admin')
self.NAME = self.getUniqueString()
sot = self.conn.placement.create_resource_provider(name=self.NAME)
assert isinstance(sot, resource_provider.ResourceProvider)
self.assertEqual(self.NAME, sot.name)
self._resource_provider = sot
def tearDown(self):
sot = self.conn.placement.delete_resource_provider(
self._resource_provider)
self.assertIsNone(sot)
super().tearDown()
def test_find(self):
sot = self.conn.placement.find_resource_provider(self.NAME)
self.assertEqual(self.NAME, sot.name)
def test_get(self):
sot = self.conn.placement.get_resource_provider(
self._resource_provider.id)
self.assertEqual(self.NAME, sot.name)
def test_list(self):
names = [o.name for o in self.conn.placement.resource_providers()]
self.assertIn(self.NAME, names)

View File

@ -0,0 +1,54 @@
# 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.placement.v1 import _proxy
from openstack.placement.v1 import resource_provider
from openstack.tests.unit import test_proxy_base as test_proxy_base
class TestPlacementProxy(test_proxy_base.TestProxyBase):
def setUp(self):
super().setUp()
self.proxy = _proxy.Proxy(self.session)
def test_resource_provider_create(self):
self.verify_create(
self.proxy.create_resource_provider,
resource_provider.ResourceProvider,
)
def test_resource_provider_delete(self):
self.verify_delete(
self.proxy.delete_resource_provider,
resource_provider.ResourceProvider,
False,
)
def test_resource_provider_update(self):
self.verify_update(
self.proxy.update_resource_provider,
resource_provider.ResourceProvider,
False,
)
def test_resource_provider_get(self):
self.verify_get(
self.proxy.get_resource_provider,
resource_provider.ResourceProvider,
)
def test_resource_providers(self):
self.verify_list_no_kwargs(
self.proxy.resource_providers,
resource_provider.ResourceProvider,
)

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.placement.v1 import resource_provider as rp
from openstack.tests.unit import base
FAKE = {
'uuid': '751cd30a-df22-4ef8-b028-67c1c5aeddc3',
'name': 'fake-name',
'parent_provider_uuid': '9900cc2d-88e8-429d-927a-182adf1577b0',
}
class TestResourceProvider(base.TestCase):
def test_basic(self):
sot = rp.ResourceProvider()
self.assertEqual(None, sot.resource_key)
self.assertEqual('resource_providers', sot.resources_key)
self.assertEqual('/resource_providers', 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.assertFalse(sot.allow_patch)
self.assertDictEqual(
{
'limit': 'limit',
'marker': 'marker',
'name': 'name',
'member_of': 'member_of',
'resources': 'resources',
'in_tree': 'in_tree',
'required': 'required',
'id': 'uuid',
},
sot._query_mapping._mapping)
def test_make_it(self):
sot = rp.ResourceProvider(**FAKE)
self.assertEqual(FAKE['uuid'], sot.id)
self.assertEqual(FAKE['name'], sot.name)
self.assertEqual(
FAKE['parent_provider_uuid'], sot.parent_provider_id,
)

View File

@ -74,6 +74,7 @@ class TestPlacementRest(base.TestCase):
class TestBadPlacementRest(base.TestCase): class TestBadPlacementRest(base.TestCase):
def setUp(self): def setUp(self):
self.skipTest('Need to re-add support for broken placement versions')
super(TestBadPlacementRest, self).setUp() super(TestBadPlacementRest, self).setUp()
# The bad-placement.json is for older placement that was # The bad-placement.json is for older placement that was
# missing the status field from its discovery doc. This # missing the status field from its discovery doc. This

View File

@ -0,0 +1,7 @@
---
features:
- |
Add initial support for Placement. Currently the following resources are
supported:
- ``ResourceProvider``