image: Add metadef resource type operations
- Add resource for Metadata definition resource types Glance v2 API(https://docs.openstack.org/api-ref/image/v2/metadefs-index.html#metadata-definition-resource-types) - Change method names and adjust spacing - Resolve merge conflict Change-Id: I8ac7d15e69cb5cb017fe93e38736b8dbee9ae2f8
This commit is contained in:
@@ -66,6 +66,16 @@ Metadef Namespace Operations
|
||||
:members: create_metadef_namespace, delete_metadef_namespace,
|
||||
get_metadef_namespace, metadef_namespaces, update_metadef_namespace
|
||||
|
||||
|
||||
Metadef Resource Type Operations
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. autoclass:: openstack.image.v2._proxy.Proxy
|
||||
:noindex:
|
||||
:members: metadef_resource_types, metadef_resource_type_associations,
|
||||
create_metadef_resource_type_association,
|
||||
delete_metadef_resource_type_association
|
||||
|
||||
Helpers
|
||||
^^^^^^^
|
||||
|
||||
|
@@ -18,6 +18,7 @@ Image v2 Resources
|
||||
v2/image
|
||||
v2/member
|
||||
v2/metadef_namespace
|
||||
v2/metadef_resource_type
|
||||
v2/metadef_schema
|
||||
v2/task
|
||||
v2/service_info
|
||||
|
24
doc/source/user/resources/image/v2/metadef_resource_type.rst
Normal file
24
doc/source/user/resources/image/v2/metadef_resource_type.rst
Normal file
@@ -0,0 +1,24 @@
|
||||
openstack.image.v2.metadef_resource_type
|
||||
========================================
|
||||
|
||||
.. automodule:: openstack.image.v2.metadef_resource_type
|
||||
|
||||
The MetadefResourceType Class
|
||||
-----------------------------
|
||||
|
||||
The ``MetadefResourceType`` class inherits
|
||||
from :class:`~openstack.resource.Resource`.
|
||||
|
||||
.. autoclass:: openstack.image.v2.metadef_resource_type.MetadefResourceType
|
||||
:members:
|
||||
|
||||
|
||||
The MetadefResourceTypeAssociation Class
|
||||
----------------------------------------
|
||||
|
||||
The ``MetadefResourceTypeAssociation`` class inherits
|
||||
from :class:`~openstack.resource.Resource`.
|
||||
|
||||
.. autoclass::
|
||||
openstack.image.v2.metadef_resource_type.MetadefResourceTypeAssociation
|
||||
:members:
|
@@ -18,6 +18,7 @@ from openstack.image import _base_proxy
|
||||
from openstack.image.v2 import image as _image
|
||||
from openstack.image.v2 import member as _member
|
||||
from openstack.image.v2 import metadef_namespace as _metadef_namespace
|
||||
from openstack.image.v2 import metadef_resource_type as _metadef_resource_type
|
||||
from openstack.image.v2 import metadef_schema as _metadef_schema
|
||||
from openstack.image.v2 import schema as _schema
|
||||
from openstack.image.v2 import service_info as _si
|
||||
@@ -765,6 +766,86 @@ class Proxy(_base_proxy.BaseImageProxy):
|
||||
**attrs,
|
||||
)
|
||||
|
||||
# ====== METADEF RESOURCE TYPES ======
|
||||
def metadef_resource_types(self, **query):
|
||||
"""Return a generator of metadef resource types
|
||||
|
||||
:return: A generator object of metadef resource types
|
||||
:rtype:
|
||||
:class:`~openstack.image.v2.metadef_resource_type.MetadefResourceType`
|
||||
:raises: :class:`~openstack.exceptions.ResourceNotFound`
|
||||
when no resource can be found.
|
||||
"""
|
||||
return self._list(_metadef_resource_type.MetadefResourceType, **query)
|
||||
|
||||
# ====== METADEF RESOURCE TYPES ASSOCIATION======
|
||||
def create_metadef_resource_type_association(self,
|
||||
metadef_namespace,
|
||||
**attrs):
|
||||
"""Creates a resource type association between a namespace
|
||||
and the resource type specified in the body of the request.
|
||||
|
||||
:param dict attrs: Keyword arguments which will be used to create a
|
||||
:class:`~openstack.image.v2.metadef_resource_type.MetadefResourceTypeAssociation`
|
||||
comprised of the properties on the
|
||||
MetadefResourceTypeAssociation class.
|
||||
|
||||
:returns: The results of metadef resource type association creation
|
||||
:rtype:
|
||||
:class:`~openstack.image.v2.metadef_resource_type.MetadefResourceTypeAssociation`
|
||||
"""
|
||||
namespace_name = resource.Resource._get_id(metadef_namespace)
|
||||
return self._create(
|
||||
_metadef_resource_type.MetadefResourceTypeAssociation,
|
||||
namespace_name=namespace_name,
|
||||
**attrs)
|
||||
|
||||
def delete_metadef_resource_type_association(self,
|
||||
metadef_resource_type,
|
||||
metadef_namespace,
|
||||
ignore_missing=True):
|
||||
"""Removes a resource type association in a namespace.
|
||||
|
||||
:param metadef_resource_type: The value can be either the name of
|
||||
a metadef resource type association or an
|
||||
:class:`~openstack.image.v2.metadef_resource_type.MetadefResourceTypeAssociation`
|
||||
instance.
|
||||
:param metadef_namespace: The value can be either the name of metadef
|
||||
namespace or an
|
||||
:class:`~openstack.image.v2.metadef_namespace.MetadefNamespace`
|
||||
instance
|
||||
:param bool ignore_missing: When set to ``False``,
|
||||
:class:`~openstack.exceptions.ResourceNotFound` will be raised when
|
||||
the metadef resource type association does not exist.
|
||||
:returns: ``None``
|
||||
"""
|
||||
namespace_name = resource.Resource._get_id(metadef_namespace)
|
||||
self._delete(
|
||||
_metadef_resource_type.MetadefResourceTypeAssociation,
|
||||
metadef_resource_type,
|
||||
namespace_name=namespace_name,
|
||||
ignore_missing=ignore_missing,
|
||||
)
|
||||
|
||||
def metadef_resource_type_associations(self, metadef_namespace, **query):
|
||||
"""Return a generator of metadef resource type associations
|
||||
|
||||
:param metadef_namespace: The value can be either the name of metadef
|
||||
namespace or an
|
||||
:class:`~openstack.image.v2.metadef_namespace.MetadefNamespace`
|
||||
instance
|
||||
:return: A generator object of metadef resource type associations
|
||||
:rtype:
|
||||
:class:`~openstack.image.v2.metadef_resource_type.MetadefResourceTypeAssociation`
|
||||
:raises: :class:`~openstack.exceptions.ResourceNotFound`
|
||||
when no resource can be found.
|
||||
"""
|
||||
namespace_name = resource.Resource._get_id(metadef_namespace)
|
||||
return self._list(
|
||||
_metadef_resource_type.MetadefResourceTypeAssociation,
|
||||
namespace_name=namespace_name,
|
||||
**query)
|
||||
|
||||
# ====== SCHEMAS ======
|
||||
def get_images_schema(self):
|
||||
"""Get images schema
|
||||
|
56
openstack/image/v2/metadef_resource_type.py
Normal file
56
openstack/image/v2/metadef_resource_type.py
Normal 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 MetadefResourceType(resource.Resource):
|
||||
resources_key = 'resource_types'
|
||||
base_path = '/metadefs/resource_types'
|
||||
|
||||
# capabilities
|
||||
allow_list = True
|
||||
|
||||
#: The name of metadata definition resource type
|
||||
name = resource.Body('name', alternate_id=True)
|
||||
#: The date and time when the resource type was created.
|
||||
created_at = resource.Body('created_at')
|
||||
#: The date and time when the resource type was updated.
|
||||
updated_at = resource.Body('updated_at')
|
||||
|
||||
|
||||
class MetadefResourceTypeAssociation(resource.Resource):
|
||||
resources_key = 'resource_type_associations'
|
||||
base_path = '/metadefs/namespaces/%(namespace_name)s/resource_types'
|
||||
|
||||
# capabilities
|
||||
allow_create = True
|
||||
allow_delete = True
|
||||
allow_list = True
|
||||
|
||||
#: The name of the namespace whose details you want to see.
|
||||
namespace_name = resource.URI('namespace_name')
|
||||
#: The name of metadata definition resource type
|
||||
name = resource.Body('name', alternate_id=True)
|
||||
#: The date and time when the resource type was created.
|
||||
created_at = resource.Body('created_at')
|
||||
#: The date and time when the resource type was updated.
|
||||
updated_at = resource.Body('updated_at')
|
||||
#: Prefix for any properties in the namespace that you want to apply
|
||||
#: to the resource type. If you specify a prefix, you must append
|
||||
#: a prefix separator, such as the colon (:) character.
|
||||
prefix = resource.Body('prefix')
|
||||
#: Some resource types allow more than one key and value pair
|
||||
#: for each instance. For example, the Image service allows
|
||||
#: both user and image metadata on volumes. The properties_target parameter
|
||||
#: enables a namespace target to remove the ambiguity
|
||||
properties_target = resource.Body('properties_target')
|
@@ -0,0 +1,79 @@
|
||||
# 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.image.v2 import metadef_namespace as _metadef_namespace
|
||||
from openstack.image.v2 import metadef_resource_type as _metadef_resource_type
|
||||
from openstack.tests.functional.image.v2 import base
|
||||
|
||||
|
||||
class TestMetadefResourceType(base.BaseImageTest):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
# there's a limit on namespace length
|
||||
namespace = self.getUniqueString().split('.')[-1]
|
||||
self.metadef_namespace = self.conn.image.create_metadef_namespace(
|
||||
namespace=namespace,
|
||||
)
|
||||
self.assertIsInstance(
|
||||
self.metadef_namespace,
|
||||
_metadef_namespace.MetadefNamespace,
|
||||
)
|
||||
self.assertEqual(namespace, self.metadef_namespace.namespace)
|
||||
|
||||
resource_type_name = 'test-resource-type'
|
||||
resource_type = {'name': resource_type_name}
|
||||
self.metadef_resource_type = \
|
||||
self.conn.image.create_metadef_resource_type_association(
|
||||
metadef_namespace=namespace,
|
||||
**resource_type
|
||||
)
|
||||
self.assertIsInstance(
|
||||
self.metadef_resource_type,
|
||||
_metadef_resource_type.MetadefResourceTypeAssociation
|
||||
)
|
||||
self.assertEqual(resource_type_name, self.metadef_resource_type.name)
|
||||
|
||||
def tearDown(self):
|
||||
# we do this in tearDown rather than via 'addCleanup' since we want to
|
||||
# wait for the deletion of the resource to ensure it completes
|
||||
self.conn.image.delete_metadef_namespace(self.metadef_namespace)
|
||||
self.conn.image.wait_for_delete(self.metadef_namespace)
|
||||
|
||||
super().tearDown()
|
||||
|
||||
def test_metadef_resource_types(self):
|
||||
# list resource type associations
|
||||
associations = list(self.conn.image.metadef_resource_type_associations(
|
||||
metadef_namespace=self.metadef_namespace))
|
||||
|
||||
self.assertIn(
|
||||
self.metadef_resource_type.name,
|
||||
{a.name for a in associations}
|
||||
)
|
||||
|
||||
# (no find_metadef_resource_type_association method)
|
||||
|
||||
# list resource types
|
||||
resource_types = list(self.conn.image.metadef_resource_types())
|
||||
|
||||
self.assertIn(
|
||||
self.metadef_resource_type.name,
|
||||
{t.name for t in resource_types}
|
||||
)
|
||||
|
||||
# delete
|
||||
self.conn.image.delete_metadef_resource_type_association(
|
||||
self.metadef_resource_type,
|
||||
metadef_namespace=self.metadef_namespace
|
||||
)
|
38
openstack/tests/unit/image/v2/test_metadef_resource_type.py
Normal file
38
openstack/tests/unit/image/v2/test_metadef_resource_type.py
Normal file
@@ -0,0 +1,38 @@
|
||||
# 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.image.v2 import metadef_resource_type
|
||||
from openstack.tests.unit import base
|
||||
|
||||
|
||||
EXAMPLE = {
|
||||
"name": "OS::Nova::Aggregate",
|
||||
"created_at": "2022-07-09T04:10:37Z"
|
||||
}
|
||||
|
||||
|
||||
class TestMetadefResourceType(base.TestCase):
|
||||
def test_basic(self):
|
||||
sot = metadef_resource_type.MetadefResourceType()
|
||||
self.assertIsNone(sot.resource_key)
|
||||
self.assertEqual('resource_types', sot.resources_key)
|
||||
self.assertEqual('/metadefs/resource_types', sot.base_path)
|
||||
self.assertFalse(sot.allow_create)
|
||||
self.assertFalse(sot.allow_fetch)
|
||||
self.assertFalse(sot.allow_commit)
|
||||
self.assertFalse(sot.allow_delete)
|
||||
self.assertTrue(sot.allow_list)
|
||||
|
||||
def test_make_it(self):
|
||||
sot = metadef_resource_type.MetadefResourceType(**EXAMPLE)
|
||||
self.assertEqual(EXAMPLE['name'], sot.name)
|
||||
self.assertEqual(EXAMPLE['created_at'], sot.created_at)
|
@@ -0,0 +1,44 @@
|
||||
# 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.image.v2 import metadef_resource_type
|
||||
from openstack.tests.unit import base
|
||||
|
||||
|
||||
EXAMPLE = {
|
||||
"name": "OS::Cinder::Volume",
|
||||
"prefix": "CIM_PASD_",
|
||||
"properties_target": "image",
|
||||
"created_at": "2022-07-09T04:10:38Z"
|
||||
}
|
||||
|
||||
|
||||
class TestMetadefResourceTypeAssociation(base.TestCase):
|
||||
def test_basic(self):
|
||||
sot = metadef_resource_type.MetadefResourceTypeAssociation()
|
||||
self.assertIsNone(sot.resource_key)
|
||||
self.assertEqual('resource_type_associations', sot.resources_key)
|
||||
self.assertEqual(
|
||||
'/metadefs/namespaces/%(namespace_name)s/resource_types',
|
||||
sot.base_path)
|
||||
self.assertTrue(sot.allow_create)
|
||||
self.assertFalse(sot.allow_fetch)
|
||||
self.assertFalse(sot.allow_commit)
|
||||
self.assertTrue(sot.allow_delete)
|
||||
self.assertTrue(sot.allow_list)
|
||||
|
||||
def test_make_it(self):
|
||||
sot = metadef_resource_type.MetadefResourceTypeAssociation(**EXAMPLE)
|
||||
self.assertEqual(EXAMPLE['name'], sot.name)
|
||||
self.assertEqual(EXAMPLE['created_at'], sot.created_at)
|
||||
self.assertEqual(EXAMPLE['prefix'], sot.prefix)
|
||||
self.assertEqual(EXAMPLE['properties_target'], sot.properties_target)
|
@@ -20,6 +20,7 @@ from openstack.image.v2 import _proxy
|
||||
from openstack.image.v2 import image as _image
|
||||
from openstack.image.v2 import member as _member
|
||||
from openstack.image.v2 import metadef_namespace as _metadef_namespace
|
||||
from openstack.image.v2 import metadef_resource_type as _metadef_resource_type
|
||||
from openstack.image.v2 import metadef_schema as _metadef_schema
|
||||
from openstack.image.v2 import schema as _schema
|
||||
from openstack.image.v2 import service_info as _service_info
|
||||
@@ -533,6 +534,50 @@ class TestMetadefNamespace(TestImageProxy):
|
||||
)
|
||||
|
||||
|
||||
class TestMetadefResourceType(TestImageProxy):
|
||||
def test_metadef_resource_types(self):
|
||||
self.verify_list(
|
||||
self.proxy.metadef_resource_types,
|
||||
_metadef_resource_type.MetadefResourceType
|
||||
)
|
||||
|
||||
|
||||
class TestMetadefResourceTypeAssociation(TestImageProxy):
|
||||
def test_create_metadef_resource_type_association(self):
|
||||
self.verify_create(
|
||||
self.proxy.create_metadef_resource_type_association,
|
||||
_metadef_resource_type.MetadefResourceTypeAssociation,
|
||||
method_kwargs={'metadef_namespace': 'namespace_name'},
|
||||
expected_kwargs={'namespace_name': 'namespace_name'}
|
||||
)
|
||||
|
||||
def test_delete_metadef_resource_type_association(self):
|
||||
self.verify_delete(
|
||||
self.proxy.delete_metadef_resource_type_association,
|
||||
_metadef_resource_type.MetadefResourceTypeAssociation,
|
||||
False,
|
||||
method_kwargs={'metadef_namespace': 'namespace_name'},
|
||||
expected_kwargs={'namespace_name': 'namespace_name'}
|
||||
)
|
||||
|
||||
def test_delete_metadef_resource_type_association_ignore(self):
|
||||
self.verify_delete(
|
||||
self.proxy.delete_metadef_resource_type_association,
|
||||
_metadef_resource_type.MetadefResourceTypeAssociation,
|
||||
True,
|
||||
method_kwargs={'metadef_namespace': 'namespace_name'},
|
||||
expected_kwargs={'namespace_name': 'namespace_name'}
|
||||
)
|
||||
|
||||
def test_metadef_resource_type_associations(self):
|
||||
self.verify_list(
|
||||
self.proxy.metadef_resource_type_associations,
|
||||
_metadef_resource_type.MetadefResourceTypeAssociation,
|
||||
method_kwargs={'metadef_namespace': 'namespace_name'},
|
||||
expected_kwargs={'namespace_name': 'namespace_name'}
|
||||
)
|
||||
|
||||
|
||||
class TestSchema(TestImageProxy):
|
||||
def test_images_schema_get(self):
|
||||
self._verify(
|
||||
|
Reference in New Issue
Block a user