From 4b8a9ceb2097745a1bd97a4ef52c02ad2acb832b Mon Sep 17 00:00:00 2001 From: Snow Kim Date: Tue, 13 Sep 2022 00:11:03 +0900 Subject: [PATCH] image: Add metadef schema resource to v2 api * Add resource for (Glance) Metadata Definition Schema API (https://docs.openstack.org/api-ref/image/v2/metadefs-index.html?expanded=#metadata-definition-schemas) * Adjust names to avoid abbreviations * Adjust grouping * Add tests * Add docs and release note * Trim underlines in docs * Resolve merge conflict * Seperate functional test to another file * Rename test class name correctly Change-Id: If2dfbca5ffbd425e4183b310af9534411318a395 --- doc/source/user/proxies/image_v2.rst | 9 +- doc/source/user/resources/image/index.rst | 1 + .../resources/image/v2/metadef_schema.rst | 13 ++ openstack/image/v2/_proxy.py | 101 +++++++++++++ openstack/image/v2/metadef_schema.py | 29 ++++ .../image/v2/test_metadef_schema.py | 67 +++++++++ .../unit/image/v2/test_metadef_schema.py | 141 ++++++++++++++++++ openstack/tests/unit/image/v2/test_proxy.py | 93 ++++++++++++ ...image-metadef-schema-b463825481bdf954.yaml | 3 + 9 files changed, 455 insertions(+), 2 deletions(-) create mode 100644 doc/source/user/resources/image/v2/metadef_schema.rst create mode 100644 openstack/image/v2/metadef_schema.py create mode 100644 openstack/tests/functional/image/v2/test_metadef_schema.py create mode 100644 openstack/tests/unit/image/v2/test_metadef_schema.py create mode 100644 releasenotes/notes/add-image-metadef-schema-b463825481bdf954.yaml diff --git a/doc/source/user/proxies/image_v2.rst b/doc/source/user/proxies/image_v2.rst index cbd6feea2..941f803a2 100644 --- a/doc/source/user/proxies/image_v2.rst +++ b/doc/source/user/proxies/image_v2.rst @@ -43,7 +43,12 @@ Schema Operations .. autoclass:: openstack.image.v2._proxy.Proxy :noindex: :members: get_images_schema, get_image_schema, get_members_schema, - get_member_schema, get_tasks_schema, get_task_schema + get_member_schema, get_tasks_schema, get_task_schema, + get_metadef_namespace_schema, get_metadef_namespaces_schema, + get_metadef_resource_type_schema, get_metadef_resource_types_schema, + get_metadef_object_schema, get_metadef_objects_schema, + get_metadef_property_schema, get_metadef_properties_schema, + get_metadef_tag_schema, get_metadef_tags_schema Service Info Discovery Operations ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -54,7 +59,7 @@ Service Info Discovery Operations Metadef Namespace Operations -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: openstack.image.v2._proxy.Proxy :noindex: diff --git a/doc/source/user/resources/image/index.rst b/doc/source/user/resources/image/index.rst index 986f3018e..660312278 100644 --- a/doc/source/user/resources/image/index.rst +++ b/doc/source/user/resources/image/index.rst @@ -18,5 +18,6 @@ Image v2 Resources v2/image v2/member v2/metadef_namespace + v2/metadef_schema v2/task v2/service_info diff --git a/doc/source/user/resources/image/v2/metadef_schema.rst b/doc/source/user/resources/image/v2/metadef_schema.rst new file mode 100644 index 000000000..8332ee48d --- /dev/null +++ b/doc/source/user/resources/image/v2/metadef_schema.rst @@ -0,0 +1,13 @@ +openstack.image.v2.metadef_schema +================================= + +.. automodule:: openstack.image.v2.metadef_schema + +The MetadefSchema Class +----------------------- + +The ``MetadefSchema`` class inherits +from :class:`~openstack.resource.Resource`. + +.. autoclass:: openstack.image.v2.metadef_schema.MetadefSchema + :members: diff --git a/openstack/image/v2/_proxy.py b/openstack/image/v2/_proxy.py index c747d1a17..b819c8ae3 100644 --- a/openstack/image/v2/_proxy.py +++ b/openstack/image/v2/_proxy.py @@ -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_schema as _metadef_schema from openstack.image.v2 import schema as _schema from openstack.image.v2 import service_info as _si from openstack.image.v2 import task as _task @@ -817,6 +818,106 @@ class Proxy(_base_proxy.BaseImageProxy): return self._get(_schema.Schema, requires_id=False, base_path='/schemas/task') + def get_metadef_namespace_schema(self): + """Get metadata definition namespace schema + + :returns: One :class:`~openstack.image.v2.metadef_schema.MetadefSchema` + :raises: :class:`~openstack.exceptions.ResourceNotFound` + when no resource can be found. + """ + return self._get(_metadef_schema.MetadefSchema, requires_id=False, + base_path='/schemas/metadefs/namespace') + + def get_metadef_namespaces_schema(self): + """Get metadata definition namespaces schema + + :returns: One :class:`~openstack.image.v2.metadef_schema.MetadefSchema` + :raises: :class:`~openstack.exceptions.ResourceNotFound` + when no resource can be found. + """ + return self._get(_metadef_schema.MetadefSchema, requires_id=False, + base_path='/schemas/metadefs/namespaces') + + def get_metadef_resource_type_schema(self): + """Get metadata definition resource type association schema + + :returns: One :class:`~openstack.image.v2.metadef_schema.MetadefSchema` + :raises: :class:`~openstack.exceptions.ResourceNotFound` + when no resource can be found. + """ + return self._get(_metadef_schema.MetadefSchema, requires_id=False, + base_path='/schemas/metadefs/resource_type') + + def get_metadef_resource_types_schema(self): + """Get metadata definition resource type associations schema + + :returns: One :class:`~openstack.image.v2.metadef_schema.MetadefSchema` + :raises: :class:`~openstack.exceptions.ResourceNotFound` + when no resource can be found. + """ + return self._get(_metadef_schema.MetadefSchema, requires_id=False, + base_path='/schemas/metadefs/resource_types') + + def get_metadef_object_schema(self): + """Get metadata definition object schema + + :returns: One :class:`~openstack.image.v2.metadef_schema.MetadefSchema` + :raises: :class:`~openstack.exceptions.ResourceNotFound` + when no resource can be found. + """ + return self._get(_metadef_schema.MetadefSchema, requires_id=False, + base_path='/schemas/metadefs/object') + + def get_metadef_objects_schema(self): + """Get metadata definition objects schema + + :returns: One :class:`~openstack.image.v2.metadef_schema.MetadefSchema` + :raises: :class:`~openstack.exceptions.ResourceNotFound` + when no resource can be found. + """ + return self._get(_metadef_schema.MetadefSchema, requires_id=False, + base_path='/schemas/metadefs/objects') + + def get_metadef_property_schema(self): + """Get metadata definition property schema + + :returns: One :class:`~openstack.image.v2.metadef_schema.MetadefSchema` + :raises: :class:`~openstack.exceptions.ResourceNotFound` + when no resource can be found. + """ + return self._get(_metadef_schema.MetadefSchema, requires_id=False, + base_path='/schemas/metadefs/property') + + def get_metadef_properties_schema(self): + """Get metadata definition properties schema + + :returns: One :class:`~openstack.image.v2.metadef_schema.MetadefSchema` + :raises: :class:`~openstack.exceptions.ResourceNotFound` + when no resource can be found. + """ + return self._get(_metadef_schema.MetadefSchema, requires_id=False, + base_path='/schemas/metadefs/properties') + + def get_metadef_tag_schema(self): + """Get metadata definition tag schema + + :returns: One :class:`~openstack.image.v2.metadef_schema.MetadefSchema` + :raises: :class:`~openstack.exceptions.ResourceNotFound` + when no resource can be found. + """ + return self._get(_metadef_schema.MetadefSchema, requires_id=False, + base_path='/schemas/metadefs/tag') + + def get_metadef_tags_schema(self): + """Get metadata definition tags schema + + :returns: One :class:`~openstack.image.v2.metadef_schema.MetadefSchema` + :raises: :class:`~openstack.exceptions.ResourceNotFound` + when no resource can be found. + """ + return self._get(_metadef_schema.MetadefSchema, requires_id=False, + base_path='/schemas/metadefs/tags') + # ====== TASKS ====== def tasks(self, **query): """Return a generator of tasks diff --git a/openstack/image/v2/metadef_schema.py b/openstack/image/v2/metadef_schema.py new file mode 100644 index 000000000..b5e4fee68 --- /dev/null +++ b/openstack/image/v2/metadef_schema.py @@ -0,0 +1,29 @@ +# 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 MetadefSchema(resource.Resource): + base_path = '/schemas/metadefs' + + # capabilities + allow_fetch = True + + #: A boolean value that indicates allows users to add custom properties. + additional_properties = resource.Body('additionalProperties', type=bool) + #: A set of definitions. + definitions = resource.Body('definitions', type=dict) + #: A list of required resources. + required = resource.Body('required', type=list) + #: Schema properties. + properties = resource.Body('properties', type=dict) diff --git a/openstack/tests/functional/image/v2/test_metadef_schema.py b/openstack/tests/functional/image/v2/test_metadef_schema.py new file mode 100644 index 000000000..ae5fe3384 --- /dev/null +++ b/openstack/tests/functional/image/v2/test_metadef_schema.py @@ -0,0 +1,67 @@ +# 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_schema as _metadef_schema +from openstack.tests.functional.image.v2 import base + + +class TestMetadefSchema(base.BaseImageTest): + + def test_get_metadef_namespace_schema(self): + metadef_schema = self.conn.image.get_metadef_namespace_schema() + self.assertIsNotNone(metadef_schema) + self.assertIsInstance(metadef_schema, _metadef_schema.MetadefSchema) + + def test_get_metadef_namespaces_schema(self): + metadef_schema = self.conn.image.get_metadef_namespaces_schema() + self.assertIsNotNone(metadef_schema) + self.assertIsInstance(metadef_schema, _metadef_schema.MetadefSchema) + + def test_get_metadef_resource_type_schema(self): + metadef_schema = self.conn.image.get_metadef_resource_type_schema() + self.assertIsNotNone(metadef_schema) + self.assertIsInstance(metadef_schema, _metadef_schema.MetadefSchema) + + def test_get_metadef_resource_types_schema(self): + metadef_schema = self.conn.image.get_metadef_resource_types_schema() + self.assertIsNotNone(metadef_schema) + self.assertIsInstance(metadef_schema, _metadef_schema.MetadefSchema) + + def test_get_metadef_object_schema(self): + metadef_schema = self.conn.image.get_metadef_object_schema() + self.assertIsNotNone(metadef_schema) + self.assertIsInstance(metadef_schema, _metadef_schema.MetadefSchema) + + def test_get_metadef_objects_schema(self): + metadef_schema = self.conn.image.get_metadef_objects_schema() + self.assertIsNotNone(metadef_schema) + self.assertIsInstance(metadef_schema, _metadef_schema.MetadefSchema) + + def test_get_metadef_property_schema(self): + metadef_schema = self.conn.image.get_metadef_property_schema() + self.assertIsNotNone(metadef_schema) + self.assertIsInstance(metadef_schema, _metadef_schema.MetadefSchema) + + def test_get_metadef_properties_schema(self): + metadef_schema = self.conn.image.get_metadef_properties_schema() + self.assertIsNotNone(metadef_schema) + self.assertIsInstance(metadef_schema, _metadef_schema.MetadefSchema) + + def test_get_metadef_tag_schema(self): + metadef_schema = self.conn.image.get_metadef_tag_schema() + self.assertIsNotNone(metadef_schema) + self.assertIsInstance(metadef_schema, _metadef_schema.MetadefSchema) + + def test_get_metadef_tags_schema(self): + metadef_schema = self.conn.image.get_metadef_tags_schema() + self.assertIsNotNone(metadef_schema) + self.assertIsInstance(metadef_schema, _metadef_schema.MetadefSchema) diff --git a/openstack/tests/unit/image/v2/test_metadef_schema.py b/openstack/tests/unit/image/v2/test_metadef_schema.py new file mode 100644 index 000000000..e26d89823 --- /dev/null +++ b/openstack/tests/unit/image/v2/test_metadef_schema.py @@ -0,0 +1,141 @@ +# 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_schema +from openstack.tests.unit import base + + +IDENTIFIER = 'IDENTIFIER' +EXAMPLE = { + 'name': 'namespace', + 'properties': { + 'namespace': { + 'type': 'string', + 'description': 'The unique namespace text.', + 'maxLength': 80 + }, + 'visibility': { + 'type': 'string', + 'description': 'Scope of namespace accessibility.', + 'enum': [ + 'public', + 'private' + ] + }, + 'created_at': { + 'type': 'string', + 'readOnly': True, + 'description': 'Date and time of namespace creation', + 'format': 'date-time' + }, + 'resource_type_associations': { + 'type': 'array', + 'items': { + 'type': 'object', + 'properties': { + 'name': { + 'type': 'string' + }, + 'prefix': { + 'type': 'string' + }, + 'properties_target': { + 'type': 'string' + } + } + } + }, + 'properties': { + '$ref': '#/definitions/property' + }, + 'objects': { + 'type': 'array', + 'items': { + 'type': 'object', + 'properties': { + 'name': { + 'type': 'string' + }, + 'description': { + 'type': 'string' + }, + 'required': { + '$ref': '#/definitions/stringArray' + }, + 'properties': { + '$ref': '#/definitions/property' + } + } + } + }, + 'tags': { + 'type': 'array', + 'items': { + 'type': 'object', + 'properties': { + 'name': { + 'type': 'string' + } + } + } + } + }, + 'additionalProperties': False, + 'definitions': { + 'positiveInteger': { + 'type': 'integer', + 'minimum': 0 + }, + 'positiveIntegerDefault0': { + 'allOf': [ + { + '$ref': '#/definitions/positiveInteger' + }, + { + 'default': 0 + } + ] + }, + 'stringArray': { + 'type': 'array', + 'items': { + 'type': 'string' + }, + 'uniqueItems': True + } + }, + 'required': [ + 'namespace' + ] +} + + +class TestMetadefSchema(base.TestCase): + def test_basic(self): + sot = metadef_schema.MetadefSchema() + self.assertIsNone(sot.resource_key) + self.assertIsNone(sot.resources_key) + self.assertEqual('/schemas/metadefs', sot.base_path) + self.assertFalse(sot.allow_create) + self.assertTrue(sot.allow_fetch) + self.assertFalse(sot.allow_commit) + self.assertFalse(sot.allow_delete) + self.assertFalse(sot.allow_list) + + def test_make_it(self): + sot = metadef_schema.MetadefSchema(**EXAMPLE) + self.assertEqual(EXAMPLE['name'], sot.name) + self.assertEqual(EXAMPLE['properties'], sot.properties) + self.assertEqual(EXAMPLE['additionalProperties'], + sot.additional_properties) + self.assertEqual(EXAMPLE['definitions'], sot.definitions) + self.assertEqual(EXAMPLE['required'], sot.required) diff --git a/openstack/tests/unit/image/v2/test_proxy.py b/openstack/tests/unit/image/v2/test_proxy.py index f4e568a59..6aeaa1fe7 100644 --- a/openstack/tests/unit/image/v2/test_proxy.py +++ b/openstack/tests/unit/image/v2/test_proxy.py @@ -20,6 +20,7 @@ from openstack.image.v2 import _proxy from openstack.image.v2 import image from openstack.image.v2 import member from openstack.image.v2 import metadef_namespace +from openstack.image.v2 import metadef_schema from openstack.image.v2 import schema from openstack.image.v2 import service_info as si from openstack.image.v2 import task @@ -598,3 +599,95 @@ class TestMisc(TestImageProxy): method_kwargs={}, expected_args=[si.Import], expected_kwargs={'require_id': False}) + + +class TestMetadefSchema(TestImageProxy): + def test_metadef_namespace_schema_get(self): + self._verify( + "openstack.proxy.Proxy._get", + self.proxy.get_metadef_namespace_schema, + expected_args=[metadef_schema.MetadefSchema], + expected_kwargs={ + 'base_path': '/schemas/metadefs/namespace', + 'requires_id': False}) + + def test_metadef_namespaces_schema_get(self): + self._verify( + "openstack.proxy.Proxy._get", + self.proxy.get_metadef_namespaces_schema, + expected_args=[metadef_schema.MetadefSchema], + expected_kwargs={ + 'base_path': '/schemas/metadefs/namespaces', + 'requires_id': False}) + + def test_metadef_resource_type_schema_get(self): + self._verify( + "openstack.proxy.Proxy._get", + self.proxy.get_metadef_resource_type_schema, + expected_args=[metadef_schema.MetadefSchema], + expected_kwargs={ + 'base_path': '/schemas/metadefs/resource_type', + 'requires_id': False}) + + def test_metadef_resource_types_schema_get(self): + self._verify( + "openstack.proxy.Proxy._get", + self.proxy.get_metadef_resource_types_schema, + expected_args=[metadef_schema.MetadefSchema], + expected_kwargs={ + 'base_path': '/schemas/metadefs/resource_types', + 'requires_id': False}) + + def test_metadef_object_schema_get(self): + self._verify( + "openstack.proxy.Proxy._get", + self.proxy.get_metadef_object_schema, + expected_args=[metadef_schema.MetadefSchema], + expected_kwargs={ + 'base_path': '/schemas/metadefs/object', + 'requires_id': False}) + + def test_metadef_objects_schema_get(self): + self._verify( + "openstack.proxy.Proxy._get", + self.proxy.get_metadef_objects_schema, + expected_args=[metadef_schema.MetadefSchema], + expected_kwargs={ + 'base_path': '/schemas/metadefs/objects', + 'requires_id': False}) + + def test_metadef_property_schema_get(self): + self._verify( + "openstack.proxy.Proxy._get", + self.proxy.get_metadef_property_schema, + expected_args=[metadef_schema.MetadefSchema], + expected_kwargs={ + 'base_path': '/schemas/metadefs/property', + 'requires_id': False}) + + def test_metadef_properties_schema_get(self): + self._verify( + "openstack.proxy.Proxy._get", + self.proxy.get_metadef_properties_schema, + expected_args=[metadef_schema.MetadefSchema], + expected_kwargs={ + 'base_path': '/schemas/metadefs/properties', + 'requires_id': False}) + + def test_metadef_tag_schema_get(self): + self._verify( + "openstack.proxy.Proxy._get", + self.proxy.get_metadef_tag_schema, + expected_args=[metadef_schema.MetadefSchema], + expected_kwargs={ + 'base_path': '/schemas/metadefs/tag', + 'requires_id': False}) + + def test_metadef_tags_schema_get(self): + self._verify( + "openstack.proxy.Proxy._get", + self.proxy.get_metadef_tags_schema, + expected_args=[metadef_schema.MetadefSchema], + expected_kwargs={ + 'base_path': '/schemas/metadefs/tags', + 'requires_id': False}) diff --git a/releasenotes/notes/add-image-metadef-schema-b463825481bdf954.yaml b/releasenotes/notes/add-image-metadef-schema-b463825481bdf954.yaml new file mode 100644 index 000000000..f02975932 --- /dev/null +++ b/releasenotes/notes/add-image-metadef-schema-b463825481bdf954.yaml @@ -0,0 +1,3 @@ +--- +features: + - Add support for metadata definition schema resource in image service. \ No newline at end of file