From a3a5c2f2f022ba0d6b5b60329dc7a9d4511822a2 Mon Sep 17 00:00:00 2001 From: Brian Curtin Date: Mon, 13 Jul 2015 14:24:33 -0500 Subject: [PATCH] Split account/container metadata to own resources The account data being handled within the Container resource makes for some oddity within that resource as well as from the proxy. They share some commonality that is now in a base class, but their properties are now properly separated. Change-Id: Id81b8a878424498777edea2a985894cc93f7b225 Closes-Bug: 1462641 --- openstack/object_store/v1/_base.py | 39 ++++++++++++++ openstack/object_store/v1/_proxy.py | 17 +++--- openstack/object_store/v1/account.py | 38 +++++++++++++ openstack/object_store/v1/container.py | 48 ++--------------- .../unit/object_store/v1/test_account.py | 54 +++++++++++++++++++ .../unit/object_store/v1/test_container.py | 24 --------- .../tests/unit/object_store/v1/test_proxy.py | 3 +- 7 files changed, 147 insertions(+), 76 deletions(-) create mode 100644 openstack/object_store/v1/_base.py create mode 100644 openstack/object_store/v1/account.py create mode 100644 openstack/tests/unit/object_store/v1/test_account.py diff --git a/openstack/object_store/v1/_base.py b/openstack/object_store/v1/_base.py new file mode 100644 index 00000000..9459929d --- /dev/null +++ b/openstack/object_store/v1/_base.py @@ -0,0 +1,39 @@ +# 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.object_store import object_store_service +from openstack import resource + + +class BaseResource(resource.Resource): + service = object_store_service.ObjectStoreService() + + @classmethod + def update_by_id(cls, session, resource_id, attrs, path_args=None): + """Update a Resource with the given attributes. + + :param session: The session to use for making this request. + :type session: :class:`~openstack.session.Session` + :param resource_id: This resource's identifier, if needed by + the request. The default is ``None``. + :param dict attrs: The attributes to be sent in the body + of the request. + :param dict path_args: This parameter is sent by the base + class but is ignored for this method. + + :return: A ``dict`` representing the response headers. + """ + url = cls._get_url(None, resource_id) + headers = attrs.get(resource.HEADERS, dict()) + return session.post(url, service=cls.service, accept=None, + headers=headers).headers diff --git a/openstack/object_store/v1/_proxy.py b/openstack/object_store/v1/_proxy.py index 008545ea..95eea45b 100644 --- a/openstack/object_store/v1/_proxy.py +++ b/openstack/object_store/v1/_proxy.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. +from openstack.object_store.v1 import account as _account from openstack.object_store.v1 import container as _container from openstack.object_store.v1 import obj as _obj from openstack import proxy @@ -21,22 +22,22 @@ class Proxy(proxy.BaseProxy): """Get metatdata for this account :rtype: - :class:`~openstack.object_store.v1.container.Container` + :class:`~openstack.object_store.v1.account.Account` """ - return self._head(_container.Container) + return self._head(_account.Account) - def set_account_metadata(self, container): + def set_account_metadata(self, account): """Set metatdata for this account. - :param container: Account metadata specified on a - :class:`~openstack.object_store.v1.container.Container` object + :param account: Account metadata specified on a + :class:`~openstack.object_store.v1.account.Account` object to be sent to the server. - :type container: - :class:`~openstack.object_store.v1.container.Container` + :type account: + :class:`~openstack.object_store.v1.account.Account` :rtype: ``None`` """ - container.update(self.session) + account.update(self.session) def containers(self, **query): """Obtain Container objects for this account. diff --git a/openstack/object_store/v1/account.py b/openstack/object_store/v1/account.py new file mode 100644 index 00000000..d6a16852 --- /dev/null +++ b/openstack/object_store/v1/account.py @@ -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.object_store.v1 import _base +from openstack import resource + + +class Account(_base.BaseResource): + base_path = "/" + + allow_retrieve = True + allow_update = True + allow_head = True + + #: The total number of bytes that are stored in Object Storage for + #: the account. + account_bytes_used = resource.header("x-account-bytes-used", type=int) + #: The number of containers. + account_container_count = resource.header("x-account-container-count", + type=int) + #: The number of objects in the account. + account_object_count = resource.header("x-account-object-count", type=int) + #: The secret key value for temporary URLs. If not set, + #: this header is not returned by this operation. + meta_temp_url_key = resource.header("x-account-meta-temp-url-key") + #: A second secret key value for temporary URLs. If not set, + #: this header is not returned by this operation. + meta_temp_url_key_2 = resource.header("x-account-meta-temp-url-key-2") diff --git a/openstack/object_store/v1/container.py b/openstack/object_store/v1/container.py index aa730853..3e431016 100644 --- a/openstack/object_store/v1/container.py +++ b/openstack/object_store/v1/container.py @@ -11,13 +11,12 @@ # License for the specific language governing permissions and limitations # under the License. -from openstack.object_store import object_store_service +from openstack.object_store.v1 import _base from openstack import resource -class Container(resource.Resource): +class Container(_base.BaseResource): base_path = "/" - service = object_store_service.ObjectStoreService() id_attribute = "name" allow_create = True @@ -27,22 +26,6 @@ class Container(resource.Resource): allow_list = True allow_head = True - # Account data (when id=None) - #: The total number of bytes that are stored in Object Storage for - #: the account. - account_bytes_used = resource.header("x-account-bytes-used", type=int) - #: The number of containers. - account_container_count = resource.header("x-account-container-count", - type=int) - #: The number of objects in the account. - account_object_count = resource.header("x-account-object-count", type=int) - #: The secret key value for temporary URLs. If not set, - #: this header is not returned by this operation. - meta_temp_url_key = resource.header("x-account-meta-temp-url-key") - #: A second secret key value for temporary URLs. If not set, - #: this header is not returned by this operation. - meta_temp_url_key_2 = resource.header("x-account-meta-temp-url-key-2") - # Container body data (when id=None) #: The name of the container. name = resource.prop("name") @@ -97,29 +80,9 @@ class Container(resource.Resource): #: has a copy of the object before any data is sent. if_none_match = resource.header("if-none-match") - @classmethod - def update_by_id(cls, session, resource_id, attrs, path_args=None): - """Update a Container with the given attributes. - - :param session: The session to use for making this request. - :type session: :class:`~openstack.session.Session` - :param resource_id: This resource's identifier, if needed by - the request. The default is ``None``. - :param dict attrs: The attributes to be sent in the body - of the request. - :param dict path_args: This parameter is sent by the base - class but is ignored for this method. - - :return: A ``dict`` representing the response headers. - """ - url = cls._get_url(None, resource_id) - headers = attrs.get(resource.HEADERS, dict()) - return session.post(url, service=cls.service, accept=None, - headers=headers).headers - @classmethod def create_by_id(cls, session, attrs, resource_id=None): - """Create a Container from its attributes. + """Create a Resource from its attributes. :param session: The session to use for making this request. :type session: :class:`~openstack.session.Session` @@ -136,13 +99,12 @@ class Container(resource.Resource): headers=headers).headers def create(self, session): - """Create a Container from this instance. + """Create a Resource from this instance. :param session: The session to use for making this request. :type session: :class:`~openstack.session.Session` - :return: This :class:`~openstack.object_store.v1.container.Container` - instance. + :return: This instance. """ resp = self.create_by_id(session, self._attrs, self.id) self.set_headers(resp) diff --git a/openstack/tests/unit/object_store/v1/test_account.py b/openstack/tests/unit/object_store/v1/test_account.py new file mode 100644 index 00000000..41adc86c --- /dev/null +++ b/openstack/tests/unit/object_store/v1/test_account.py @@ -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. + +import testtools + +from openstack.object_store.v1 import account + + +CONTAINER_NAME = "mycontainer" + +ACCOUNT_EXAMPLE = { + 'content-length': '0', + 'accept-ranges': 'bytes', + 'date': 'Sat, 05 Jul 2014 19:17:40 GMT', + 'x-account-bytes-used': '12345', + 'x-account-container-count': '678', + 'content-type': 'text/plain; charset=utf-8', + 'x-account-object-count': '98765' +} + + +class TestAccount(testtools.TestCase): + + def test_basic(self): + sot = account.Account.new(**ACCOUNT_EXAMPLE) + self.assertIsNone(sot.resources_key) + self.assertIsNone(sot.id) + self.assertEqual('/', sot.base_path) + self.assertEqual('object-store', sot.service.service_type) + self.assertTrue(sot.allow_update) + self.assertTrue(sot.allow_head) + self.assertTrue(sot.allow_retrieve) + self.assertFalse(sot.allow_delete) + self.assertFalse(sot.allow_list) + self.assertFalse(sot.allow_create) + + def test_make_it(self): + sot = account.Account.new(**{'headers': ACCOUNT_EXAMPLE}) + self.assertIsNone(sot.id) + self.assertEqual(int(ACCOUNT_EXAMPLE['x-account-bytes-used']), + sot.account_bytes_used) + self.assertEqual(int(ACCOUNT_EXAMPLE['x-account-container-count']), + sot.account_container_count) + self.assertEqual(int(ACCOUNT_EXAMPLE['x-account-object-count']), + sot.account_object_count) diff --git a/openstack/tests/unit/object_store/v1/test_container.py b/openstack/tests/unit/object_store/v1/test_container.py index ff666c94..bd60072e 100644 --- a/openstack/tests/unit/object_store/v1/test_container.py +++ b/openstack/tests/unit/object_store/v1/test_container.py @@ -18,17 +18,6 @@ from openstack.object_store.v1 import container CONTAINER_NAME = "mycontainer" -ACCOUNT_EXAMPLE = { - 'content-length': '0', - 'accept-ranges': 'bytes', - 'id': 'tx4272aa0d6e1e4f8f971f8-0053b84f54', - 'date': 'Sat, 05 Jul 2014 19:17:40 GMT', - 'x-account-bytes-used': '12345', - 'x-account-container-count': '678', - 'content-type': 'text/plain; charset=utf-8', - 'x-account-object-count': '98765' -} - CONT_EXAMPLE = { "count": 999, "bytes": 12345, @@ -64,19 +53,6 @@ LIST_EXAMPLE = [ ] -class TestAccount(testtools.TestCase): - - def test_make_it(self): - sot = container.Container.new(**{'headers': ACCOUNT_EXAMPLE}) - self.assertIsNone(sot.id) - self.assertEqual(int(ACCOUNT_EXAMPLE['x-account-bytes-used']), - sot.account_bytes_used) - self.assertEqual(int(ACCOUNT_EXAMPLE['x-account-container-count']), - sot.account_container_count) - self.assertEqual(int(ACCOUNT_EXAMPLE['x-account-object-count']), - sot.account_object_count) - - class TestContainer(testtools.TestCase): def setUp(self): diff --git a/openstack/tests/unit/object_store/v1/test_proxy.py b/openstack/tests/unit/object_store/v1/test_proxy.py index 7ba82988..aa38a47e 100644 --- a/openstack/tests/unit/object_store/v1/test_proxy.py +++ b/openstack/tests/unit/object_store/v1/test_proxy.py @@ -14,6 +14,7 @@ import mock import six from openstack.object_store.v1 import _proxy +from openstack.object_store.v1 import account from openstack.object_store.v1 import container from openstack.object_store.v1 import obj from openstack import session @@ -30,7 +31,7 @@ class TestObjectStoreProxy(test_proxy_base.TestProxyBase): self.proxy = _proxy.Proxy(self.session) def test_account_metadata_get(self): - self.verify_head(self.proxy.get_account_metadata, container.Container) + self.verify_head(self.proxy.get_account_metadata, account.Account) def test_container_metadata_get(self): self.verify_head(self.proxy.get_container_metadata,