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:
EunYoung Kim
2022-10-15 20:34:52 +09:00
parent 8f0e751b4e
commit c52f2decd3
9 changed files with 378 additions and 0 deletions

View File

@@ -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
^^^^^^^

View File

@@ -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

View 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:

View File

@@ -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

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 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')

View File

@@ -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
)

View 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)

View File

@@ -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)

View File

@@ -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(