From 7ec745d7b2bf83962d39f9757d167c5c554106ae Mon Sep 17 00:00:00 2001 From: NaoShark <49853899+NaoShark@users.noreply.github.com> Date: Wed, 7 Jul 2021 10:43:36 +0900 Subject: [PATCH] Delete database and object functions (#83) * Delete database and object sub-command * Delete related files --- ecl/database/__init__.py | 0 ecl/database/database_service.py | 24 -- ecl/database/exceptions.py | 13 - ecl/database/v1/__init__.py | 0 ecl/database/v1/_proxy.py | 332 ------------------ ecl/database/v1/database.py | 48 --- ecl/database/v1/datastore.py | 39 -- ecl/database/v1/flavor.py | 53 --- ecl/database/v1/instance.py | 141 -------- ecl/database/v1/user.py | 71 ---- ecl/database/version.py | 55 --- ecl/object_store/__init__.py | 0 ecl/object_store/object_store_service.py | 24 -- ecl/object_store/v1/__init__.py | 0 ecl/object_store/v1/_base.py | 86 ----- ecl/object_store/v1/_proxy.py | 323 ----------------- ecl/object_store/v1/account.py | 42 --- ecl/object_store/v1/container.py | 165 --------- ecl/object_store/v1/obj.py | 234 ------------ ecl/profile.py | 10 +- ecl/tests/functional/object_store/__init__.py | 0 .../functional/object_store/v1/__init__.py | 0 .../object_store/v1/test_account.py | 79 ----- .../object_store/v1/test_container.py | 134 ------- .../functional/object_store/v1/test_obj.py | 154 -------- .../functional/telemetry/v2/test_meter.py | 32 -- ecl/tests/unit/object_store/__init__.py | 0 .../object_store/test_object_store_service.py | 28 -- ecl/tests/unit/object_store/v1/__init__.py | 0 .../unit/object_store/v1/test_account.py | 56 --- .../unit/object_store/v1/test_container.py | 171 --------- ecl/tests/unit/object_store/v1/test_obj.py | 137 -------- ecl/tests/unit/object_store/v1/test_proxy.py | 277 --------------- 33 files changed, 1 insertion(+), 2727 deletions(-) delete mode 100755 ecl/database/__init__.py delete mode 100755 ecl/database/database_service.py delete mode 100755 ecl/database/exceptions.py delete mode 100755 ecl/database/v1/__init__.py delete mode 100755 ecl/database/v1/_proxy.py delete mode 100755 ecl/database/v1/database.py delete mode 100644 ecl/database/v1/datastore.py delete mode 100755 ecl/database/v1/flavor.py delete mode 100755 ecl/database/v1/instance.py delete mode 100755 ecl/database/v1/user.py delete mode 100755 ecl/database/version.py delete mode 100755 ecl/object_store/__init__.py delete mode 100755 ecl/object_store/object_store_service.py delete mode 100755 ecl/object_store/v1/__init__.py delete mode 100755 ecl/object_store/v1/_base.py delete mode 100755 ecl/object_store/v1/_proxy.py delete mode 100755 ecl/object_store/v1/account.py delete mode 100755 ecl/object_store/v1/container.py delete mode 100755 ecl/object_store/v1/obj.py delete mode 100755 ecl/tests/functional/object_store/__init__.py delete mode 100755 ecl/tests/functional/object_store/v1/__init__.py delete mode 100755 ecl/tests/functional/object_store/v1/test_account.py delete mode 100755 ecl/tests/functional/object_store/v1/test_container.py delete mode 100755 ecl/tests/functional/object_store/v1/test_obj.py delete mode 100755 ecl/tests/functional/telemetry/v2/test_meter.py delete mode 100755 ecl/tests/unit/object_store/__init__.py delete mode 100755 ecl/tests/unit/object_store/test_object_store_service.py delete mode 100755 ecl/tests/unit/object_store/v1/__init__.py delete mode 100755 ecl/tests/unit/object_store/v1/test_account.py delete mode 100755 ecl/tests/unit/object_store/v1/test_container.py delete mode 100755 ecl/tests/unit/object_store/v1/test_obj.py delete mode 100755 ecl/tests/unit/object_store/v1/test_proxy.py diff --git a/ecl/database/__init__.py b/ecl/database/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/ecl/database/database_service.py b/ecl/database/database_service.py deleted file mode 100755 index 3818dd1..0000000 --- a/ecl/database/database_service.py +++ /dev/null @@ -1,24 +0,0 @@ -# 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 ecl import service_filter - - -class DatabaseService(service_filter.ServiceFilter): - """Database(Trove) service""" - - valid_versions = [service_filter.ValidVersion('v1')] - - def __init__(self, version=None): - """Create a Database(Trove) service""" - super(DatabaseService, self).__init__(service_type='rdb', - version=version) diff --git a/ecl/database/exceptions.py b/ecl/database/exceptions.py deleted file mode 100755 index 78d6906..0000000 --- a/ecl/database/exceptions.py +++ /dev/null @@ -1,13 +0,0 @@ -""" -Exception definitions for RDatabase. -""" -import json -from ecl import exceptions - - -class HttpException(exceptions.HttpException): - pass - - -class NotFoundException(HttpException): - pass diff --git a/ecl/database/v1/__init__.py b/ecl/database/v1/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/ecl/database/v1/_proxy.py b/ecl/database/v1/_proxy.py deleted file mode 100755 index 8c353ff..0000000 --- a/ecl/database/v1/_proxy.py +++ /dev/null @@ -1,332 +0,0 @@ -# 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 ecl.database.v1 import instance as _instance -from ecl.database.v1 import user as _user -from ecl.database.v1 import database as _database -from ecl.database.v1 import flavor as _flavor -from ecl.database.v1 import datastore as _datastore - -from ecl import proxy2 -from ecl import resource2 - - -class Proxy(proxy2.BaseProxy): - - def instances(self, **query): - """Retrieve a list of instances - - :param kwargs \*\*query: Optional query parameters to be sent to limit - the instances being returned. - :returns: A list of database instances. - """ - instance = _instance.Instance - return list(self._list(instance, paginated=False, **query)) - - def create_instance(self, - name, - flavor_id, - volume, - datastore, - nics, - databases=None, - users=None, - availability_zone=None, - backup_window=None, - backup_retention_period=None, - restore_point=None, - maintenance_window=None, - **attrs): - """Create a new instance from attributes - - :param string name: Name of instance - :param string flavor_id: Flavor ID of server - :param dict volue: Volume configuration dict which has volume_size inside - :param databases: Database definition - list to initialize database on creating instance - :param users: List of users to connect to defined databases - :param dict datastore: Datastore name and version of instance - :param dict nics: Network difinition of instance - :param availability_zone: Availability zone for instance - :param backup_window: Backup window time range - :param backup_retention_period: Number of the day to retain backup - :param maintenance_window: Maintenance window time range by - the day of the week and from/to time - :param kwargs attrs: Keyword arguments which will be used to create - a :class:`~ecl.datagase.v1.instance.Instance`, - comprised of the properties on the Instance class. - - :returns: The results of instance creation - :rtype: :class:`~ecl.compute.v1.instance.Instance` - """ - attrs.update({"name": name}) - attrs.update({"flavorRef": flavor_id}) - attrs.update({"volume": volume}) - attrs.update({"datastore": datastore}) - attrs.update({"nics": nics}) - - if databases: - attrs.update({"databases": databases}) - if users: - attrs.update({"users": users}) - if availability_zone: - attrs.update({"availability_zone": availability_zone}) - if backup_window: - attrs.update({"backup_window": backup_window}) - if backup_retention_period or backup_retention_period == 0: - attrs.update({"backup_retention_period": backup_retention_period}) - if restore_point: - attrs.update({"restorePoint": restore_point}) - if maintenance_window: - attrs.update({"maintenance_window": maintenance_window}) - - return self._create(_instance.Instance, **attrs) - - def delete_instance(self, instance, ignore_missing=False): - """Delete a instance - - :param instance: The value can be either the ID of a server or a - :class:`~ecl.database.v1.instance.Instance` instance. - :param bool ignore_missing: When set to ``False`` - :class:`~ecl.exceptions.ResourceNotFound` will be - raised when the server does not exist. - When set to ``True``, no exception will be set when - attempting to delete a nonexistent instance - :param bool force: When set to ``True``, the instance deletion will be - forced immediatly. - - :returns: ``None`` - """ - self._delete(_instance.Instance, instance, ignore_missing=ignore_missing) - - def find_instance(self, name_or_id, ignore_missing=False): - """Find a single instance - - :param name_or_id: The name or ID of a server. - :param bool ignore_missing: When set to ``False`` - :class:`~ecl.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: One :class:`~ecl.database.v1.instance.Instance` or None - """ - return self._find(_instance.Instance, name_or_id, - ignore_missing=ignore_missing) - - def get_instance(self, instance): - """Get a single instance - - :param instance: The value can be the ID of a instance or a - :class:`~ecl.database.v1.instance.Instance` instance. - - :returns: One :class:`~ecl.database.v1.instance.Instance` - :raises: :class:`~ecl.exceptions.ResourceNotFound` - when no resource can be found. - """ - return self._get(_instance.Instance, instance) - - def wait_for_server(self, instance, status='ACTIVE', failures=['ERROR'], - interval=2, wait=120): - return resource2.wait_for_status(self.session, instance, status, - failures, interval, wait) - - # def find_flavor(self, name_or_id, ignore_missing=False): - # """Find a single flavor - - # :param name_or_id: The name or ID of a flavor. - # :param bool ignore_missing: When set to ``False`` - # :class:`~ecl.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: One :class:`~ecl.database.v1.flavor.Flavor` or None - # """ - # return self._find(_flavor.Flavor, name_or_id, - # ignore_missing=ignore_missing) - - # def get_flavor(self, flavor): - # """Get a single flavor - - # :param flavor: The value can be the ID of a flavor or a - # :class:`~ecl.database.v1.flavor.Flavor` instance. - - # :returns: One :class:`~ecl.database.v1.flavor.Flavor` - # :raises: :class:`~ecl.exceptions.ResourceNotFound` - # when no resource can be found. - # """ - # return self._get(_flavor.Flavor, flavor) - - def flavors(self): - """Return a list of flavors - :returns: A list of flavor objects - """ - return list(self._list(_flavor.Flavor, paginated=False)) - - def datastores(self): - """Return a list of datastores - :returns: A list of datastore objects - """ - return list(self._list(_datastore.Datastore, paginated=False)) - - def users(self, instance_id, **query): - """Retrieve a list of users assciated with instance - - :param instance_id: Instance id to find users - :param kwargs \*\*query: Optional query parameters to be sent to limit - the instances being returned. Available parameters include: - :returns: A list of database instances. - """ - user = _user.User - return list(self._list(user, paginated=False, instance_id=instance_id, **query)) - - def create_user(self, instance_id, name, password, databases=None): - """Create a new user from attributes - - :param string instance_id: ID of instance to assciate creating user - :param string name: Name of user - :param string password: Password of user - :param databases: Database list of user to grant - - :returns: ``None`` - """ - attrs = {"name": name, - "password": password} - if databases: - attrs.update({"databases": databases}) - user = _user.User() - return user.create(self.session, instance_id, **attrs) - - def delete_user(self, instance_id, user, ignore_missing=False): - """Delete a user - - :param instance_id: The value can be either the ID of a server or a - :class:`~ecl.database.v1.instance.Instance` instance. - :param string user: Name of user. - :param bool ignore_missing: When set to ``False`` - :class:`~ecl.exceptions.ResourceNotFound` will be - raised when the resource does not exist. - When set to ``True``, no exception will be set when - attempting to delete a nonexistent user - - :returns: ``None`` - """ - self._delete(_user.User, user, instance_id=instance_id, - ignore_missing=ignore_missing) - - def find_user(self, instance_id, name_or_id, ignore_missing=False): - """Find a single user - - :param name_or_id: The name or ID of a user. - :param bool ignore_missing: When set to ``False`` - :class:`~ecl.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: One :class:`~ecl.database.v1.user.User` or None - """ - return self._find(_user.User, name_or_id, - instance_id=instance_id, - ignore_missing=ignore_missing) - - def get_user(self, instance_id, user): - """Show a user - - :param instance_id: The value can be either the ID of a server or a - :class:`~ecl.database.v1.instance.Instance` instance. - :param string user: Name of user. - :returns: One user. - :rtype: :class:`~ecl.compute.v1.user.User` - """ - return self._get(_user.User, user, instance_id=instance_id) - - def grant_user(self, instance_id, user_name, databases): - """Grants database access privilege to user in DB Instance. - - :param instance_id: The value can be either the ID of a server or a - :class:`~ecl.database.v1.instance.Instance` instance. - :param string user: Name of user. - :param array databases: Database names to grant access privilege. - :returns: ``None`` - """ - user = _user.User() - return user.grant(self.session, instance_id, user_name, databases) - - def revoke_user(self, instance_id, user_name, database): - """Revoke the access privilege of user from database in DB Instance. - - :param instance_id: The value can be either the ID of a server or a - :class:`~ecl.database.v1.instance.Instance` instance. - :param string user: Name of user. - :param string database: Database name to revoke access privilege. - :returns: ``None`` - """ - user = _user.User() - return user.revoke(self.session, instance_id, user_name, database) - - def databases(self, instance_id, **query): - """Retrieve a list of databases assciated with instance - - :param instance_id: Instance id to find databases - :param kwargs \*\*query: Optional query parameters to be sent to limit - the instances being returned. Available parameters include: - :returns: A list of database instances. - """ - database = _database.Database - return list(self._list(database, paginated=False, - instance_id=instance_id, **query)) - - def create_database(self, instance_id, name, charset=None, collate=None): - """Create a new database from attributes - - :param string instance_id: ID of instance to assciate creating database - :param string name: Name of database - - :returns: ``None`` - """ - attrs = {"name": name} - if charset: - attrs.update({"character_set": charset}) - if collate: - attrs.update({"collate": collate}) - database = _database.Database() - return database.create(self.session, instance_id, **attrs) - - def delete_database(self, instance_id, database, ignore_missing=False): - """Delete a database - - :param instance_id: The value can be either the ID of a server or a - :class:`~ecl.database.v1.instance.Instance` instance. - :param bool ignore_missing: When set to ``False`` - :class:`~ecl.exceptions.ResourceNotFound` will be - raised when the resource does not exist. - When set to ``True``, no exception will be set when - attempting to delete a nonexistent database - - :returns: ``None`` - """ - self._delete(_database.Database, database, instance_id=instance_id, - ignore_missing=ignore_missing) - - def find_database(self, instance_id, name_or_id, ignore_missing=False): - """Find a single database - - :param name_or_id: The name or ID of a database. - :param bool ignore_missing: When set to ``False`` - :class:`~ecl.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: One :class:`~ecl.database.v1.database.Database` or None - """ - return self._find(_database.Database, name_or_id, - instance_id=instance_id, - ignore_missing=ignore_missing) diff --git a/ecl/database/v1/database.py b/ecl/database/v1/database.py deleted file mode 100755 index 026ff68..0000000 --- a/ecl/database/v1/database.py +++ /dev/null @@ -1,48 +0,0 @@ -# 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 ecl.database import database_service -from ecl import resource2 -from ecl import exceptions - - -class Database(resource2.Resource): - resource_key = "database" - resources_key = "databases" - base_path = '/instances/%(instance_id)s/databases' - service = database_service.DatabaseService() - - # Capabilities - allow_create = True - allow_delete = True - allow_list = True - - allow_update = False - allow_get = False - - # Properties - #: Name of Database. - name = resource2.Body('name', alternate_id=True) - #: Character set of Database. - character_set = resource2.Body('character_set') - #: Collate of Database. - collate = resource2.Body('collate') - #: ID of instance associated with this database - instance_id = resource2.URI('instance_id') - - def create(self, session, instance_id, **attrs): - base = self.base_path % {"instance_id": instance_id} - body = {"databases": [attrs]} - resp = session.post(base, endpoint_filter=self.service, json=body, - headers={"Accept": "application/json"}) - self._translate_response(resp, has_body=False) - return self diff --git a/ecl/database/v1/datastore.py b/ecl/database/v1/datastore.py deleted file mode 100644 index 852eb58..0000000 --- a/ecl/database/v1/datastore.py +++ /dev/null @@ -1,39 +0,0 @@ -# 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 ecl.database import database_service -from ecl import resource2 - - -class Datastore(resource2.Resource): - resource_key = None - resources_key = 'datastores' - base_path = '/datastores' - service = database_service.DatabaseService() - - # capabilities - allow_list = True - - _query_mapping = resource2.QueryParameters() - - # Properties - #: The ID of this datastore - id = resource2.Body('id') - #: The name of this datastore. - name = resource2.Body('name') - #: Size of the disk this datastore offers. *Type: int* - default_version = resource2.Body('default_version') - #: The amount of RAM (in MB) this datastore offers. *Type: int* - versions = resource2.Body('versions') - #: Links pertaining to this datastore. This is a list of dictionaries, - #: each including keys ``href`` and ``rel``. - links = resource2.Body('links') diff --git a/ecl/database/v1/flavor.py b/ecl/database/v1/flavor.py deleted file mode 100755 index c46b5f4..0000000 --- a/ecl/database/v1/flavor.py +++ /dev/null @@ -1,53 +0,0 @@ -# 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 ecl.database import database_service -from ecl import resource2 - - -class Flavor(resource2.Resource): - resource_key = 'flavor' - resources_key = 'flavors' - base_path = '/flavors' - service = database_service.DatabaseService() - - # capabilities - allow_get = True - allow_list = True - - _query_mapping = resource2.QueryParameters() - - # Properties - #: Links pertaining to this flavor. This is a list of dictionaries, - #: each including keys ``href`` and ``rel``. - links = resource2.Body('links') - #: The name of this flavor. - name = resource2.Body('name') - #: Size of the disk this flavor offers. *Type: int* - disk = resource2.Body('disk', type=int) - #: ``True`` if this is a publicly visible flavor. ``False`` if this is - #: a private image. *Type: bool* - is_public = resource2.Body('os-flavor-access:is_public', type=bool) - #: The amount of RAM (in MB) this flavor offers. *Type: int* - ram = resource2.Body('ram', type=int) - #: The number of virtual CPUs this flavor offers. *Type: int* - vcpus = resource2.Body('vcpus', type=int) - #: Size of the swap partitions. - swap = resource2.Body('swap') - #: Size of the ephemeral data disk attached to this server. *Type: int* - ephemeral = resource2.Body('ephemeral', type=int) - #: ``True`` if this flavor is disabled, ``False`` if not. *Type: bool* - is_disabled = resource2.Body('OS-FLV-DISABLED:disabled', type=bool) - #: The bandwidth scaling factor this flavor receives on the network. - rxtx_factor = resource2.Body('rxtx_factor', type=float) - #: ID - str_id = resource2.Body('str_id', alternate_id=True) diff --git a/ecl/database/v1/instance.py b/ecl/database/v1/instance.py deleted file mode 100755 index be8d57d..0000000 --- a/ecl/database/v1/instance.py +++ /dev/null @@ -1,141 +0,0 @@ -# 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 ecl.database import database_service - -from ecl import exceptions -from ecl import resource2 -from ecl import utils - - -class Instance(resource2.Resource): - resource_key = 'instance' - resources_key = 'instances' - base_path = '/instances' - service = database_service.DatabaseService() - - # capabilities - allow_create = True - allow_get = True - allow_delete = True - allow_list = True - - allow_update = False - - _query_mapping = resource2.QueryParameters() - - #: ID of the server - id = resource2.Body('id') - - #: Timestamp of when the instance was created. - created_at = resource2.Body('created') - - #: The datastore property returned as instence property. - datastore = resource2.Body('datastore', type=dict) - - #: The flavor property returned from instance. - flavor = resource2.Body('flavor', type=dict) - - #: The flavor reference, as a ID or full URL, - #: in case create instane. - flavor_id = resource2.Body('flavorRef') - - #: An ID representing the host of this instance. - hostname = resource2.Body('hostname') - - #: A list of dictionaries holding links relevant to this instance. - links = resource2.Body('links', type=list) - - #: Name of the instance - name = resource2.Body('name') - - #: Region of the instance - region = resource2.Body('region') - - #: The state this instance is in. - status = resource2.Body('status') - - #: Timestamp of when this instance was last updated. - updated_at = resource2.Body('updated') - - #: The volume property returned from instance. - volume = resource2.Body('volume', type=dict) - - #: A nic definition object. Required parameter when there are multiple - #: networks defined for the tenant. - nics = resource2.Body('nics', type=dict) - - #: Databases list of instance. - databases = resource2.Body('databases', type=list) - - #: Users list of instance. - users = resource2.Body('users', type=list) - - #: Backup window of instance. - backup_window = resource2.Body('backup_window') - - #: Maintenance window of instance. - maintenance_window = resource2.Body('maintenance_window') - - #: Backup retension period of this instance. - backup_retention_period = resource2.Body('backup_retention_period', - type=int) - - #: Restore Point - restore_point = resource2.Body('restorePoint', type=dict) - - #: Restoreable Time - restorable_time = resource2.Body('restorable_time') - - #: Endpoints - endpoints = resource2.Body('endpoints', type=list) - - #: Availability Zone - availability_zone = resource2.Body('availability_zone') - - @classmethod - def find(cls, session, name_or_id, ignore_missing=False, **params): - """Find a resource by its name or id. - - :param session: The session to use for making this request. - :type session: :class:`~ecl.session.Session` - :param name_or_id: This resource's identifier, if needed by - the request. The default is ``None``. - :param bool ignore_missing: When set to ``False`` - :class:`~ecl.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. - :param dict params: Any additional parameters to be passed into - underlying methods, such as to - :meth:`~ecl.resource2.Resource.existing` - in order to pass on URI parameters. - - :return: The :class:`Resource` object matching the given name or id - or None if nothing matches. - :raises: :class:`ecl.exceptions.DuplicateResource` if more - than one resource is found for this request. - :raises: :class:`ecl.exceptions.ResourceNotFound` if nothing - is found and ignore_missing is ``False``. - """ - # Try to short-circuit by looking directly for a matching ID. - - data = cls.list(session, **params) - - result = cls._get_one_match(name_or_id, data) - if result is not None: - return result - - if ignore_missing: - return None - raise exceptions.ResourceNotFound( - "No %s found for %s" % (cls.__name__, name_or_id)) diff --git a/ecl/database/v1/user.py b/ecl/database/v1/user.py deleted file mode 100755 index d1a8f23..0000000 --- a/ecl/database/v1/user.py +++ /dev/null @@ -1,71 +0,0 @@ -# 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 ecl.database import database_service -from ecl import resource2 -from ecl import exceptions - - -class User(resource2.Resource): - resource_key = "user" - resources_key = "users" - base_path = '/instances/%(instance_id)s/users' - service = database_service.DatabaseService() - - # _query_mapping = resource2.QueryParameters() - - # Capabilities - allow_create = True - allow_delete = True - allow_list = True - allow_update = True - allow_get = True - - # Properties - #: User's name of Database instance. - name = resource2.Body('name', alternate_id=True) - - #: Allowed access host of user. - host = resource2.Body('host') - - #: Relevant database of this user. - databases = resource2.Body('databases', type=list) - - #: User's password of Database instance. - #: This parameter is only used in instance creation. - password = resource2.Body('password') - - #: ID of instance associated with this user - instance_id = resource2.URI('instance_id') - - def create(self, session, instance_id, **attrs): - base = self.base_path % {"instance_id": instance_id} - body = {"users": [attrs]} - resp = session.post(base, endpoint_filter=self.service, json=body, - headers={"Accept": "application/json"}) - self._translate_response(resp, has_body=False) - return self - - def grant(self, session, instance_id, user, databases): - base = self.base_path % {"instance_id": instance_id} - uri = "%s/%s/databases" % (base, user) - resp = session.put(uri, endpoint_filter=self.service, - json={"databases": databases}) - self._translate_response(resp, has_body=False) - return self - - def revoke(self, session, instance_id, user, database): - base = self.base_path % {"instance_id": instance_id} - uri = uri = "%s/%s/databases/%s" % (base, user, database) - resp = session.delete(uri, endpoint_filter=self.service) - self._translate_response(resp, has_body=False) - return self diff --git a/ecl/database/version.py b/ecl/database/version.py deleted file mode 100755 index 4ce2c51..0000000 --- a/ecl/database/version.py +++ /dev/null @@ -1,55 +0,0 @@ -# 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 ecl.database import database_service -from ecl import resource2 - - -class Version(resource2.Resource): - resource_key = 'version' - resources_key = 'versions' - base_path = '' - service = database_service.DatabaseService( - version=database_service.DatabaseService.UNVERSIONED - ) - - # capabilities - allow_list = True - allow_get = True - - # Properties - #: Version identifier included in API URL. - id = resource2.Body('id') - #: List of API endpoint link. - links = resource2.Body('links') - #: Version support status. Valid values are CURRENT or SUPPORTED. - #: CURRENT is newest stable version. SUPPORTED is old supported version. - status = resource2.Body('status') - - def get_version(self, session): - url = self.base_path + '/v1.0' - resp = session.get( - url, headers={"Accept": "application/json"}, endpoint_filter=self.service - ) - self._translate_response(resp, has_body=True) - return self - - def list_version(self, session): - url = self.base_path - resp = session.get( - url, headers={"Accept": "application/json"}, endpoint_filter=self.service - ) - resp = resp.json()[self.resources_key] - - for data in resp: - version = self.existing(**data) - yield version \ No newline at end of file diff --git a/ecl/object_store/__init__.py b/ecl/object_store/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/ecl/object_store/object_store_service.py b/ecl/object_store/object_store_service.py deleted file mode 100755 index 14f272c..0000000 --- a/ecl/object_store/object_store_service.py +++ /dev/null @@ -1,24 +0,0 @@ -# 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 ecl import service_filter - - -class ObjectStoreService(service_filter.ServiceFilter): - """The object store service.""" - - valid_versions = [service_filter.ValidVersion('v1')] - - def __init__(self, version=None): - """Create an object store service.""" - super(ObjectStoreService, self).__init__(service_type='object-store', - version=version) diff --git a/ecl/object_store/v1/__init__.py b/ecl/object_store/v1/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/ecl/object_store/v1/_base.py b/ecl/object_store/v1/_base.py deleted file mode 100755 index 57844ca..0000000 --- a/ecl/object_store/v1/_base.py +++ /dev/null @@ -1,86 +0,0 @@ -# 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 ecl.object_store import object_store_service -from ecl import resource - - -class BaseResource(resource.Resource): - service = object_store_service.ObjectStoreService() - - #: Metadata stored for this resource. *Type: dict* - metadata = dict() - - _custom_metadata_prefix = None - _system_metadata = dict() - - def _calculate_headers(self, metadata): - headers = dict() - for key in metadata: - if key in self._system_metadata: - header = self._system_metadata[key] - else: - header = self._custom_metadata_prefix + key - headers[header] = metadata[key] - return headers - - def set_metadata(self, session, metadata): - url = self._get_url(self, self.id) - session.post(url, endpoint_filter=self.service, - headers=self._calculate_headers(metadata)) - - def delete_metadata(self, session, keys): - url = self._get_url(self, self.id) - headers = {key: '' for key in keys} - session.post(url, endpoint_filter=self.service, - headers=self._calculate_headers(headers)) - - def _set_metadata(self): - self.metadata = dict() - headers = self.get_headers() - - for header in headers: - if header.startswith(self._custom_metadata_prefix): - key = header[len(self._custom_metadata_prefix):].lower() - self.metadata[key] = headers[header] - - def get(self, session, include_headers=False, args=None): - super(BaseResource, self).get(session, include_headers, args) - self._set_metadata() - return self - - def head(self, session): - super(BaseResource, self).head(session) - self._set_metadata() - return self - - @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:`~ecl.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()) - headers['Accept'] = '' - return session.post(url, endpoint_filter=cls.service, - headers=headers).headers diff --git a/ecl/object_store/v1/_proxy.py b/ecl/object_store/v1/_proxy.py deleted file mode 100755 index bd4addd..0000000 --- a/ecl/object_store/v1/_proxy.py +++ /dev/null @@ -1,323 +0,0 @@ -# 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 ecl.object_store.v1 import account as _account -from ecl.object_store.v1 import container as _container -from ecl.object_store.v1 import obj as _obj -from ecl import proxy - - -class Proxy(proxy.BaseProxy): - - def get_account_metadata(self): - """Get metadata for this account. - - :rtype: - :class:`~ecl.object_store.v1.account.Account` - """ - return self._head(_account.Account) - - def set_account_metadata(self, **metadata): - """Set metadata for this account. - - :param kwargs metadata: Key/value pairs to be set as metadata - on the container. Custom metadata can be set. - Custom metadata are keys and values defined - by the user. - """ - account = self._get_resource(_account.Account, None) - account.set_metadata(self.session, metadata) - - def delete_account_metadata(self, keys): - """Delete metadata for this account. - - :param keys: The keys of metadata to be deleted. - """ - account = self._get_resource(_account.Account, None) - account.delete_metadata(self.session, keys) - - def containers(self, **query): - """Obtain Container objects for this account. - - :param kwargs query: Optional query parameters to be sent to limit - the resources being returned. - - :rtype: A generator of - :class:`~ecl.object_store.v1.container.Container` objects. - """ - return list(_container.Container.list(self.session, **query)) - - def create_container(self, **attrs): - """Create a new container from attributes - - :param dict attrs: Keyword arguments which will be used to create - a :class:`~ecl.object_store.v1.container.Container`, - comprised of the properties on the Container class. - - :returns: The results of container creation - :rtype: :class:`~ecl.object_store.v1.container.Container` - """ - return self._create(_container.Container, **attrs) - - def delete_container(self, container, ignore_missing=False): - """Delete a container - - :param container: The value can be either the name of a container or a - :class:`~ecl.object_store.v1.container.Container` - instance. - :param bool ignore_missing: When set to ``False`` - :class:`~ecl.exceptions.ResourceNotFound` will be - raised when the container does not exist. - When set to ``True``, no exception will be set when - attempting to delete a nonexistent server. - - :returns: ``None`` - """ - self._delete(_container.Container, container, - ignore_missing=ignore_missing) - - def get_container_metadata(self, container): - """Get metadata for a container - - :param container: The value can be the name of a container or a - :class:`~ecl.object_store.v1.container.Container` - instance. - - :returns: One :class:`~ecl.object_store.v1.container.Container` - :raises: :class:`~ecl.exceptions.ResourceNotFound` - when no resource can be found. - """ - container = self._head(_container.Container, container) - container.count = container.object_count - container.size = container.bytes_used - return container - - def set_container_metadata(self, container, **metadata): - """Set metadata for a container. - - :param container: The value can be the name of a container or a - :class:`~ecl.object_store.v1.container.Container` - instance. - :param kwargs metadata: Key/value pairs to be set as metadata - on the container. Both custom and system - metadata can be set. Custom metadata are keys - and values defined by the user. System - metadata are keys defined by the Object Store - and values defined by the user. The system - metadata keys are: - - - `content_type` - - `is_content_type_detected` - - `versions_location` - - `read_ACL` - - `write_ACL` - - `sync_to` - - `sync_key` - """ - res = self._get_resource(_container.Container, container) - res.set_metadata(self.session, metadata) - - def delete_container_metadata(self, container, keys): - """Delete metadata for a container. - - :param container: The value can be the ID of a container or a - :class:`~ecl.object_store.v1.container.Container` - instance. - :param keys: The keys of metadata to be deleted. - """ - res = self._get_resource(_container.Container, container) - res.delete_metadata(self.session, keys) - - def objects(self, container, **query): - """Return a generator that yields the Container's objects. - - :param container: A container object or the name of a container - that you want to retrieve objects from. - :type container: - :class:`~ecl.object_store.v1.container.Container` - :param kwargs \*\*query: Optional query parameters to be sent to limit - the resources being returned. - - :rtype: A generator of - :class:`~ecl.object_store.v1.obj.Object` objects. - """ - container = _container.Container.from_id(container) - - objs = _obj.Object.list(self.session, - path_args={"container": container.name}, - **query) - objs = list(objs) - for i in range(len(objs)): - objs[i].container = container.name - - return objs - - def _get_container_name(self, obj, container): - if isinstance(obj, _obj.Object): - if obj.container is not None: - return obj.container - if container is not None: - container = _container.Container.from_id(container) - return container.name - - raise ValueError("container must be specified") - - def get_object(self, obj, container=None): - """Get the data associated with an object - - :param obj: The value can be the name of an object or a - :class:`~ecl.object_store.v1.obj.Object` instance. - :param container: The value can be the name of a container or a - :class:`~ecl.object_store.v1.container.Container` - instance. - - :returns: The contents of the object. Use the - :func:`~get_object_metadata` - method if you want an object resource. - :raises: :class:`~ecl.exceptions.ResourceNotFound` - when no resource can be found. - """ - # TODO(briancurtin): call this download_object and make sure it's - # just returning the raw data, like download_image does - container_name = self._get_container_name(obj, container) - - return self._get(_obj.Object, obj, - path_args={"container": container_name}) - - def download_object(self, obj, container=None, path=None): - """Download the data contained inside an object to disk. - - :param obj: The value can be the name of an object or a - :class:`~ecl.object_store.v1.obj.Object` instance. - :param container: The value can be the name of a container or a - :class:`~ecl.object_store.v1.container.Container` - instance. - :param path str: Location to write the object contents. - - :raises: :class:`~ecl.exceptions.ResourceNotFound` - when no resource can be found. - """ - # TODO(briancurtin): download_object should really have the behavior - # of get_object, and this writing to a file should not exist. - # TODO(briancurtin): This method should probably offload the get - # operation into another thread or something of that nature. - with open(path, "w") as out: - out.write(self.get_object(obj, container)) - - def upload_object(self, **attrs): - """Upload a new object from attributes - - :param dict attrs: Keyword arguments which will be used to create - a :class:`~ecl.object_store.v1.obj.Object`, - comprised of the properties on the Object class. - **Required**: A `container` argument must be specified, - which is either the ID of a container or a - :class:`~ecl.object_store.v1.container.Container` - instance. - - :returns: The results of object creation - :rtype: :class:`~ecl.object_store.v1.container.Container` - """ - container = attrs.pop("container", None) - container_name = self._get_container_name(None, container) - - return self._create(_obj.Object, - path_args={"container": container_name}, **attrs) - - def copy_object(self): - """Copy an object.""" - raise NotImplementedError - - def delete_object(self, obj, ignore_missing=False, container=None): - """Delete an object - - :param obj: The value can be either the name of an object or a - :class:`~ecl.object_store.v1.container.Container` - instance. - :param container: The value can be the ID of a container or a - :class:`~ecl.object_store.v1.container.Container` - instance. - :param bool ignore_missing: When set to ``False`` - :class:`~ecl.exceptions.ResourceNotFound` will be - raised when the object does not exist. - When set to ``True``, no exception will be set when - attempting to delete a nonexistent server. - - :returns: ``None`` - """ - container_name = self._get_container_name(obj, container) - - self._delete(_obj.Object, obj, ignore_missing=ignore_missing, - path_args={"container": container_name}) - - def get_object_metadata(self, obj, container=None): - """Get metadata for an object. - - :param obj: The value can be the name of an object or a - :class:`~ecl.object_store.v1.obj.Object` instance. - :param container: The value can be the ID of a container or a - :class:`~ecl.object_store.v1.container.Container` - instance. - - :returns: One :class:`~ecl.object_store.v1.obj.Object` - :raises: :class:`~ecl.exceptions.ResourceNotFound` - when no resource can be found. - """ - container_name = self._get_container_name(obj, container) - - return self._head(_obj.Object, obj, - path_args={"container": container_name}) - - def set_object_metadata(self, obj, container=None, **metadata): - """Set metadata for an object. - - Note: This method will do an extra HEAD call. - - :param obj: The value can be the name of an object or a - :class:`~ecl.object_store.v1.obj.Object` instance. - :param container: The value can be the name of a container or a - :class:`~ecl.object_store.v1.container.Container` - instance. - :param kwargs metadata: Key/value pairs to be set as metadata - on the container. Both custom and system - metadata can be set. Custom metadata are keys - and values defined by the user. System - metadata are keys defined by the Object Store - and values defined by the user. The system - metadata keys are: - - - `content_type` - - `content_encoding` - - `content_disposition` - - `delete_after` - - `delete_at` - - `is_content_type_detected` - """ - container_name = self._get_container_name(obj, container) - res = self._get_resource(_obj.Object, obj, - path_args={"container": container_name}) - res.set_metadata(self.session, metadata) - - def delete_object_metadata(self, obj, container=None, keys=None): - """Delete metadata for an object. - - :param obj: The value can be the name of an object or a - :class:`~ecl.object_store.v1.obj.Object` instance. - :param container: The value can be the ID of a container or a - :class:`~ecl.object_store.v1.container.Container` - instance. - :param keys: The keys of metadata to be deleted. - """ - container_name = self._get_container_name(obj, container) - res = self._get_resource(_obj.Object, obj, - path_args={"container": container_name}) - res.delete_metadata(self.session, keys) diff --git a/ecl/object_store/v1/account.py b/ecl/object_store/v1/account.py deleted file mode 100755 index 88d5248..0000000 --- a/ecl/object_store/v1/account.py +++ /dev/null @@ -1,42 +0,0 @@ -# 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 ecl.object_store.v1 import _base -from ecl import resource - - -class Account(_base.BaseResource): - _custom_metadata_prefix = "X-Account-Meta-" - - 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") - #: The timestamp of the transaction. - timestamp = resource.header("x-timestamp") diff --git a/ecl/object_store/v1/container.py b/ecl/object_store/v1/container.py deleted file mode 100755 index 6f6842d..0000000 --- a/ecl/object_store/v1/container.py +++ /dev/null @@ -1,165 +0,0 @@ -# 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 ecl.object_store.v1 import _base -from ecl import resource - - -class Container(_base.BaseResource): - _custom_metadata_prefix = "X-Container-Meta-" - _system_metadata = { - "content_type": "content-type", - "is_content_type_detected": "x-detect-content-type", - "versions_location": "x-versions-location", - "read_acl": "x-container-read", - "write_acl": "x-container-write", - "sync_to": "x-container-sync-to", - "sync_key": "x-container-sync-key", - "meta_name": "X-Container-Meta-name", - "meta_access_control_allow_origin": - "X-Container-Meta-Access-Control-Allow-Origin", - "meta_access_control_max_age": - "X-Container-Meta-Access-Control-Max-Age", - "meta_access_control_expose_headers": - "X-Container-Meta-Access-Control-Expose-Headers", - "meta_quota_bytes": "X-Container-Meta-Quota-Bytes", - "meta_quota_count": "X-Container-Meta-Quota-Count", - "meta_temp_url_key": "X-Container-Meta-Temp-URL-Key", - "meta_temp_url_key_2": "X-Container-Meta-Temp-URL-Key-2", - } - - base_path = "/" - id_attribute = "name" - - allow_create = True - allow_retrieve = True - allow_update = True - allow_delete = True - allow_list = True - allow_head = True - - # Container body data (when id=None) - #: The name of the container. - name = resource.prop("name") - #: The number of objects in the container. - count = resource.prop("count") - #: The total number of bytes that are stored in Object Storage - #: for the container. - bytes = resource.prop("bytes") - - # Container metadata (when id=name) - #: The number of objects. - object_count = resource.header("x-container-object-count", type=int) - #: The count of bytes used in total. - bytes_used = resource.header("x-container-bytes-used", type=int) - #: The timestamp of the transaction. (date created) - timestamp = resource.header("x-timestamp") - - # Request headers (when id=None) - #: If set to True, Object Storage queries all replicas to return the - #: most recent one. If you omit this header, Object Storage responds - #: faster after it finds one valid replica. Because setting this - #: header to True is more expensive for the back end, use it only - #: when it is absolutely needed. *Type: bool* - is_newest = resource.header("x-newest", type=bool) - - # Request headers (when id=name) - #: The ACL that grants read access. If not set, this header is not - #: returned by this operation. - read_acl = resource.header("x-container-read") - #: The ACL that grants write access. If not set, this header is not - #: returned by this operation. - write_acl = resource.header("x-container-write") - #: The destination for container synchronization. If not set, - #: this header is not returned by this operation. - sync_to = resource.header("x-container-sync-to") - #: The secret key for container synchronization. If not set, - #: this header is not returned by this operation. - sync_key = resource.header("x-container-sync-key") - #: Enables versioning on this container. The value is the name - #: of another container. You must UTF-8-encode and then URL-encode - #: the name before you include it in the header. To disable - #: versioning, set the header to an empty string. - versions_location = resource.header("x-versions-location") - #: The MIME type of the list of names. - content_type = resource.header("content-type") - #: If set to true, Object Storage guesses the content type based - #: on the file extension and ignores the value sent in the - #: Content-Type header, if present. *Type: bool* - is_content_type_detected = resource.header("x-detect-content-type", - type=bool) - #: In combination with Expect: 100-Continue, specify an - #: "If-None-Match: \*" header to query whether the server already - #: has a copy of the object before any data is sent. - if_none_match = resource.header("if-none-match") - #: The container metadata, where name is the name of metadata item. - #: You must specify an X-Container-Meta-name header for each metadata item - #: (for each name ) that you want to add or update. - meta_name = resource.header("X-Container-Meta-name") - #: Originating URLs allowed to make cross-origin requests (CORS), - #: separated by spaces. - meta_access_control_allow_origin = resource.header( - "X-Container-Meta-Access-Control-Allow-Origin") - #: Maximum time for the origin to hold the preflight results. - meta_access_control_max_age = resource.header( - "X-Container-Meta-Access-Control-Max-Age") - #: Headers the Object Storage service exposes to the browser (technically, - #: through the user-agent setting), - #: in the request response, separated by spaces. - #: By default the Object Storage service returns the following headers - meta_access_control_expose_headers = resource.header( - "X-Container-Meta-Access-Control-Expose-Headers") - #: Sets maximum size of the container, in bytes. - #: Typically these values are set by an administrator. - meta_quota_bytes = resource.header("X-Container-Meta-Quota-Bytes") - #: Sets maximum object count of the container. - #: Typically these values are set by an administrator. - meta_quota_count = resource.header("X-Container-Meta-Quota-Count") - #: The secret key value for temporary URLs. - meta_temp_url_key = resource.header("X-Container-Meta-Temp-URL-Key") - #: A second secret key value for temporary URLs. - #: The second key enables you to rotate keys by having two active keys - #: at the same time. - meta_temp_url_key_2 = resource.header("X-Container-Meta-Temp-URL-Key-2") - - @classmethod - def create_by_id(cls, session, attrs, resource_id=None): - """Create a Resource from its attributes. - - :param session: The session to use for making this request. - :type session: :class:`~ecl.session.Session` - :param dict attrs: The attributes to be sent in the body - of the request. - :param resource_id: This resource's identifier, if needed by - the request. The default is ``None``. - - :return: A ``dict`` representing the response headers. - """ - url = cls._get_url(None, resource_id) - headers = attrs.get(resource.HEADERS, dict()) - headers['Accept'] = '' - return session.put(url, endpoint_filter=cls.service, - headers=headers).headers - - def create(self, session): - """Create a Resource from this instance. - - :param session: The session to use for making this request. - :type session: :class:`~ecl.session.Session` - - :return: This instance. - """ - resp = self.create_by_id(session, self._attrs, self.id) - self.set_headers(resp) - self._reset_dirty() - return self diff --git a/ecl/object_store/v1/obj.py b/ecl/object_store/v1/obj.py deleted file mode 100755 index 847ac4e..0000000 --- a/ecl/object_store/v1/obj.py +++ /dev/null @@ -1,234 +0,0 @@ -# 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 copy -import six - -from ecl.object_store import object_store_service -from ecl.object_store.v1 import _base -from ecl import resource - - -class Object(_base.BaseResource): - _custom_metadata_prefix = "X-Object-Meta-" - _system_metadata = { - "content_disposition": "content-disposition", - "content_encoding": "content-encoding", - "content_type": "content-type", - "delete_after": "x-delete-after", - "delete_at": "x-delete-at", - "is_content_type_detected": "x-detect-content-type", - } - - base_path = "/%(container)s" - service = object_store_service.ObjectStoreService() - id_attribute = "name" - - allow_create = True - allow_retrieve = True - allow_update = True - allow_delete = True - allow_list = True - allow_head = True - - # Data to be passed during a POST call to create an object on the server. - data = None - - # URL parameters - #: The unique name for the container. - container = resource.prop("container") - #: The unique name for the object. - name = resource.prop("name") - - # Object details - hash = resource.prop("hash") - bytes = resource.prop("bytes") - - # Headers for HEAD and GET requests - #: If set to True, Object Storage queries all replicas to return - #: the most recent one. If you omit this header, Object Storage - #: responds faster after it finds one valid replica. Because - #: setting this header to True is more expensive for the back end, - #: use it only when it is absolutely needed. *Type: bool* - is_newest = resource.header("x-newest", type=bool) - #: TODO(briancurtin) there's a lot of content here... - range = resource.header("range", type=dict) - #: See http://www.ietf.org/rfc/rfc2616.txt. - if_match = resource.header("if-match", type=dict) - #: In combination with Expect: 100-Continue, specify an - #: "If-None-Match: \*" header to query whether the server already - #: has a copy of the object before any data is sent. - if_none_match = resource.header("if-none-match", type=dict) - #: See http://www.ietf.org/rfc/rfc2616.txt. - if_modified_since = resource.header("if-modified-since", type=dict) - #: See http://www.ietf.org/rfc/rfc2616.txt. - if_unmodified_since = resource.header("if-unmodified-since", type=dict) - - # Query parameters - #: Used with temporary URLs to sign the request. For more - #: information about temporary URLs, see OpenStack Object Storage - #: API v1 Reference. - signature = resource.header("signature") - #: Used with temporary URLs to specify the expiry time of the - #: signature. For more information about temporary URLs, see - #: OpenStack Object Storage API v1 Reference. - expires_at = resource.header("expires") - #: If you include the multipart-manifest=get query parameter and - #: the object is a large object, the object contents are not - #: returned. Instead, the manifest is returned in the - #: X-Object-Manifest response header for dynamic large objects - #: or in the response body for static large objects. - multipart_manifest = resource.header("multipart-manifest") - - # Response headers from HEAD and GET - #: HEAD operations do not return content. However, in this - #: operation the value in the Content-Length header is not the - #: size of the response body. Instead it contains the size of - #: the object, in bytes. - content_length = resource.header("content-length") - #: The MIME type of the object. - content_type = resource.header("content-type") - #: The type of ranges that the object accepts. - accept_ranges = resource.header("accept-ranges") - #: For objects smaller than 5 GB, this value is the MD5 checksum - #: of the object content. The value is not quoted. - #: For manifest objects, this value is the MD5 checksum of the - #: concatenated string of MD5 checksums and ETags for each of - #: the segments in the manifest, and not the MD5 checksum of - #: the content that was downloaded. Also the value is enclosed - #: in double-quote characters. - #: You are strongly recommended to compute the MD5 checksum of - #: the response body as it is received and compare this value - #: with the one in the ETag header. If they differ, the content - #: was corrupted, so retry the operation. - etag = resource.header("etag") - #: Set to True if this object is a static large object manifest object. - #: *Type: bool* - is_static_large_object = resource.header("x-static-large-object", - type=bool) - #: If set, the value of the Content-Encoding metadata. - #: If not set, this header is not returned by this operation. - content_encoding = resource.header("content-encoding") - #: If set, specifies the override behavior for the browser. - #: For example, this header might specify that the browser use - #: a download program to save this file rather than show the file, - #: which is the default. - #: If not set, this header is not returned by this operation. - content_disposition = resource.header("content-disposition") - #: Specifies the number of seconds after which the object is - #: removed. Internally, the Object Storage system stores this - #: value in the X-Delete-At metadata item. - delete_after = resource.header("x-delete-after") - #: If set, the time when the object will be deleted by the system - #: in the format of a UNIX Epoch timestamp. - #: If not set, this header is not returned by this operation. - delete_at = resource.header("x-delete-at") - #: If set, to this is a dynamic large object manifest object. - #: The value is the container and object name prefix of the - #: segment objects in the form container/prefix. - object_manifest = resource.header("x-object-manifest") - #: The timestamp of the transaction. - timestamp = resource.header("x-timestamp") - #: The date and time that the object was created or the last - #: time that the metadata was changed. - last_modified_at = resource.header("last_modified", alias="last-modified") - - # Headers for PUT and POST requests - #: Set to chunked to enable chunked transfer encoding. If used, - #: do not set the Content-Length header to a non-zero value. - transfer_encoding = resource.header("transfer-encoding") - #: If set to true, Object Storage guesses the content type based - #: on the file extension and ignores the value sent in the - #: Content-Type header, if present. *Type: bool* - is_content_type_detected = resource.header("x-detect-content-type", - type=bool) - #: If set, this is the name of an object used to create the new - #: object by copying the X-Copy-From object. The value is in form - #: {container}/{object}. You must UTF-8-encode and then URL-encode - #: the names of the container and object before you include them - #: in the header. - #: Using PUT with X-Copy-From has the same effect as using the - #: COPY operation to copy an object. - copy_from = resource.header("x-copy-from") - - # The Object Store treats the metadata for its resources inconsistently so - # Object.set_metadata must override the BaseResource.set_metadata to - # account for it. - def set_metadata(self, session, metadata): - # Filter out items with empty values so the create metadata behaviour - # is the same as account and container - filtered_metadata = \ - {key: value for key, value in six.iteritems(metadata) if value} - - # Get a copy of the original metadata so it doesn't get erased on POST - # and update it with the new metadata values. - obj = self.head(session) - metadata2 = copy.deepcopy(obj.metadata) - metadata2.update(filtered_metadata) - - # Include any original system metadata so it doesn't get erased on POST - for key in self._system_metadata: - value = getattr(obj, key) - if value and key not in metadata2: - metadata2[key] = value - - super(Object, self).set_metadata(session, metadata2) - - # The Object Store treats the metadata for its resources inconsistently so - # Object.delete_metadata must override the BaseResource.delete_metadata to - # account for it. - def delete_metadata(self, session, keys): - # Get a copy of the original metadata so it doesn't get erased on POST - # and update it with the new metadata values. - obj = self.head(session) - metadata = copy.deepcopy(obj.metadata) - - # Include any original system metadata so it doesn't get erased on POST - for key in self._system_metadata: - value = getattr(obj, key) - if value: - metadata[key] = value - - # Remove the metadata - for key in keys: - if key == 'delete_after': - del(metadata['delete_at']) - else: - del(metadata[key]) - - url = self._get_url(self, self.id) - session.post(url, endpoint_filter=self.service, - headers=self._calculate_headers(metadata)) - - def get(self, session, include_headers=False, args=None): - url = self._get_url(self, self.id) - headers = {'Accept': 'bytes'} - resp = session.get(url, endpoint_filter=self.service, headers=headers) - resp = resp.content - self._set_metadata() - return resp - - def create(self, session): - url = self._get_url(self, self.id) - - headers = self.get_headers() - headers['Accept'] = '' - if self.data is not None: - resp = session.put(url, endpoint_filter=self.service, - data=self.data, - headers=headers).headers - else: - resp = session.post(url, endpoint_filter=self.service, data=None, - headers=headers).headers - self.set_headers(resp) - return self diff --git a/ecl/profile.py b/ecl/profile.py index 25ae6e9..abbe8d1 100755 --- a/ecl/profile.py +++ b/ecl/profile.py @@ -29,14 +29,13 @@ ~~~~~~~~~~~ A user's preferences are set based on the service type. Service type would -normally be something like 'compute', 'identity', 'object-store', etc.:: +normally be something like 'compute', 'identity', etc.:: from ecl import profile prof = profile.Profile() prof.set_name('compute', 'matrix') prof.set_region(prof.ALL, 'zion') prof.set_version('identity', 'v3') - prof.set_interface('object-store', 'internal') for service in prof.get_services(): print(prof.get_filter(service.service_type) @@ -44,11 +43,9 @@ service_type=compute,region=zion,service_name=matrix service_type=network,region=zion - service_type=database,region=zion service_type=image,region=zion service_type=metering,region=zion service_type=orchestration,region=zion - service_type=object-store,interface=internal,region=zion service_type=identity,region=zion,version=v3 """ @@ -66,7 +63,6 @@ from ecl.image import image_service from ecl import module_loader from ecl.network import network_service -from ecl.object_store import object_store_service from ecl.orchestration import orchestration_service from ecl.provider_connectivity import provider_connectivity_service from ecl.rca import rca_service @@ -79,7 +75,6 @@ ## end of the section from ecl.sss import sss_service from ecl.telemetry import telemetry_service -from ecl.database import database_service from ecl.dns import dns_service from ecl.virtual_network_appliance import virtual_network_appliance_service from ecl.mvna import mvna_service @@ -112,8 +107,6 @@ def __init__(self, plugins=None): self._add_service(image_service.ImageService(version="v2")) self._add_service(network_service.NetworkService(version="v2")) self._add_service(sss_service.SssService(version="v1")) - self._add_service( - object_store_service.ObjectStoreService(version="v1")) self._add_service( orchestration_service.OrchestrationService(version="v1")) self._add_service( @@ -137,7 +130,6 @@ def __init__(self, plugins=None): self._add_service( dedicated_hypervisor_service.DedicatedHypervisorService( version="v1")) - self._add_service(database_service.DatabaseService(version="v1")) self._add_service(dns_service.DnsService(version="v2")) self._add_service( virtual_network_appliance_service.VirtualNetworkApplianceService( diff --git a/ecl/tests/functional/object_store/__init__.py b/ecl/tests/functional/object_store/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/ecl/tests/functional/object_store/v1/__init__.py b/ecl/tests/functional/object_store/v1/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/ecl/tests/functional/object_store/v1/test_account.py b/ecl/tests/functional/object_store/v1/test_account.py deleted file mode 100755 index bd2b96a..0000000 --- a/ecl/tests/functional/object_store/v1/test_account.py +++ /dev/null @@ -1,79 +0,0 @@ -# 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 ecl.tests.functional import base - - -class TestAccount(base.BaseFunctionalTest): - - @classmethod - def tearDownClass(cls): - super(TestAccount, cls).tearDownClass() - account = cls.conn.object_store.get_account_metadata() - cls.conn.object_store.delete_account_metadata(account.metadata.keys()) - - def test_system_metadata(self): - account = self.conn.object_store.get_account_metadata() - self.assertGreaterEqual(account.account_bytes_used, 0) - self.assertGreaterEqual(account.account_container_count, 0) - self.assertGreaterEqual(account.account_object_count, 0) - - def test_custom_metadata(self): - # get custom metadata - account = self.conn.object_store.get_account_metadata() - self.assertFalse(account.metadata) - - # set no custom metadata - self.conn.object_store.set_account_metadata() - account = self.conn.object_store.get_account_metadata() - self.assertFalse(account.metadata) - - # set empty custom metadata - self.conn.object_store.set_account_metadata(k0='') - account = self.conn.object_store.get_account_metadata() - self.assertFalse(account.metadata) - - # set custom metadata - self.conn.object_store.set_account_metadata(k1='v1') - account = self.conn.object_store.get_account_metadata() - self.assertTrue(account.metadata) - self.assertEqual(1, len(account.metadata)) - self.assertIn('k1', account.metadata) - self.assertEqual('v1', account.metadata['k1']) - - # set more custom metadata - self.conn.object_store.set_account_metadata(k2='v2') - account = self.conn.object_store.get_account_metadata() - self.assertTrue(account.metadata) - self.assertEqual(2, len(account.metadata)) - self.assertIn('k1', account.metadata) - self.assertEqual('v1', account.metadata['k1']) - self.assertIn('k2', account.metadata) - self.assertEqual('v2', account.metadata['k2']) - - # update custom metadata - self.conn.object_store.set_account_metadata(k1='v1.1') - account = self.conn.object_store.get_account_metadata() - self.assertTrue(account.metadata) - self.assertEqual(2, len(account.metadata)) - self.assertIn('k1', account.metadata) - self.assertEqual('v1.1', account.metadata['k1']) - self.assertIn('k2', account.metadata) - self.assertEqual('v2', account.metadata['k2']) - - # unset custom metadata - self.conn.object_store.delete_account_metadata(['k1']) - account = self.conn.object_store.get_account_metadata() - self.assertTrue(account.metadata) - self.assertEqual(1, len(account.metadata)) - self.assertIn('k2', account.metadata) - self.assertEqual('v2', account.metadata['k2']) diff --git a/ecl/tests/functional/object_store/v1/test_container.py b/ecl/tests/functional/object_store/v1/test_container.py deleted file mode 100755 index 7be3934..0000000 --- a/ecl/tests/functional/object_store/v1/test_container.py +++ /dev/null @@ -1,134 +0,0 @@ -# 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 uuid - -from ecl.object_store.v1 import container as _container -from ecl.tests.functional import base - - -class TestContainer(base.BaseFunctionalTest): - - NAME = uuid.uuid4().hex - - @classmethod - def setUpClass(cls): - super(TestContainer, cls).setUpClass() - container = cls.conn.object_store.create_container(name=cls.NAME) - assert isinstance(container, _container.Container) - cls.assertIs(cls.NAME, container.name) - - @classmethod - def tearDownClass(cls): - result = cls.conn.object_store.delete_container(cls.NAME, - ignore_missing=True) - cls.assertIs(None, result) - - def test_list(self): - names = [o.name for o in self.conn.object_store.containers()] - self.assertIn(self.NAME, names) - - def test_system_metadata(self): - # get system metadata - container = self.conn.object_store.get_container_metadata(self.NAME) - self.assertEqual(0, container.object_count) - self.assertEqual(0, container.bytes_used) - - # set system metadata - container = self.conn.object_store.get_container_metadata(self.NAME) - self.assertIsNone(container.read_acl) - self.assertIsNone(container.write_acl) - self.conn.object_store.set_container_metadata( - container, read_acl='.r:*', write_acl='demo:demo') - container = self.conn.object_store.get_container_metadata(self.NAME) - self.assertEqual('.r:*', container.read_acl) - self.assertEqual('demo:demo', container.write_acl) - - # update system metadata - self.conn.object_store.set_container_metadata( - container, read_acl='.r:demo') - container = self.conn.object_store.get_container_metadata(self.NAME) - self.assertEqual('.r:demo', container.read_acl) - self.assertEqual('demo:demo', container.write_acl) - - # set system metadata and custom metadata - self.conn.object_store.set_container_metadata( - container, k0='v0', sync_key='1234') - container = self.conn.object_store.get_container_metadata(self.NAME) - self.assertTrue(container.metadata) - self.assertIn('k0', container.metadata) - self.assertEqual('v0', container.metadata['k0']) - self.assertEqual('.r:demo', container.read_acl) - self.assertEqual('demo:demo', container.write_acl) - self.assertEqual('1234', container.sync_key) - - # unset system metadata - self.conn.object_store.delete_container_metadata(container, - ['sync_key']) - container = self.conn.object_store.get_container_metadata(self.NAME) - self.assertTrue(container.metadata) - self.assertIn('k0', container.metadata) - self.assertEqual('v0', container.metadata['k0']) - self.assertEqual('.r:demo', container.read_acl) - self.assertEqual('demo:demo', container.write_acl) - self.assertIsNone(container.sync_key) - - def test_custom_metadata(self): - # get custom metadata - container = self.conn.object_store.get_container_metadata(self.NAME) - self.assertFalse(container.metadata) - - # set no custom metadata - self.conn.object_store.set_container_metadata(container) - container = self.conn.object_store.get_container_metadata(container) - self.assertFalse(container.metadata) - - # set empty custom metadata - self.conn.object_store.set_container_metadata(container, k0='') - container = self.conn.object_store.get_container_metadata(container) - self.assertFalse(container.metadata) - - # set custom metadata - self.conn.object_store.set_container_metadata(container, k1='v1') - container = self.conn.object_store.get_container_metadata(container) - self.assertTrue(container.metadata) - self.assertEqual(1, len(container.metadata)) - self.assertIn('k1', container.metadata) - self.assertEqual('v1', container.metadata['k1']) - - # set more custom metadata by named container - self.conn.object_store.set_container_metadata(self.NAME, k2='v2') - container = self.conn.object_store.get_container_metadata(container) - self.assertTrue(container.metadata) - self.assertEqual(2, len(container.metadata)) - self.assertIn('k1', container.metadata) - self.assertEqual('v1', container.metadata['k1']) - self.assertIn('k2', container.metadata) - self.assertEqual('v2', container.metadata['k2']) - - # update metadata - self.conn.object_store.set_container_metadata(container, k1='v1.1') - container = self.conn.object_store.get_container_metadata(self.NAME) - self.assertTrue(container.metadata) - self.assertEqual(2, len(container.metadata)) - self.assertIn('k1', container.metadata) - self.assertEqual('v1.1', container.metadata['k1']) - self.assertIn('k2', container.metadata) - self.assertEqual('v2', container.metadata['k2']) - - # delete metadata - self.conn.object_store.delete_container_metadata(container, ['k1']) - container = self.conn.object_store.get_container_metadata(self.NAME) - self.assertTrue(container.metadata) - self.assertEqual(1, len(container.metadata)) - self.assertIn('k2', container.metadata) - self.assertEqual('v2', container.metadata['k2']) diff --git a/ecl/tests/functional/object_store/v1/test_obj.py b/ecl/tests/functional/object_store/v1/test_obj.py deleted file mode 100755 index 3f36f0c..0000000 --- a/ecl/tests/functional/object_store/v1/test_obj.py +++ /dev/null @@ -1,154 +0,0 @@ -# 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 uuid - -from ecl.tests.functional import base - - -class TestObject(base.BaseFunctionalTest): - - FOLDER = uuid.uuid4().hex - FILE = uuid.uuid4().hex - DATA = 'abc' - - @classmethod - def setUpClass(cls): - super(TestObject, cls).setUpClass() - cls.conn.object_store.create_container(name=cls.FOLDER) - cls.sot = cls.conn.object_store.upload_object( - container=cls.FOLDER, name=cls.FILE, data=cls.DATA) - - @classmethod - def tearDownClass(cls): - super(TestObject, cls).tearDownClass() - cls.conn.object_store.delete_object(cls.sot, ignore_missing=True) - cls.conn.object_store.delete_container(cls.FOLDER) - - def test_list(self): - names = [o.name for o - in self.conn.object_store.objects(container=self.FOLDER)] - self.assertIn(self.FILE, names) - - def test_get_object(self): - result = self.conn.object_store.get_object( - self.FILE, container=self.FOLDER) - self.assertEqual(self.DATA, result) - result = self.conn.object_store.get_object(self.sot) - self.assertEqual(self.DATA, result) - - def test_system_metadata(self): - # get system metadata - obj = self.conn.object_store.get_object_metadata( - self.FILE, container=self.FOLDER) - self.assertGreaterEqual(0, obj.bytes) - self.assertIsNotNone(obj.etag) - - # set system metadata - obj = self.conn.object_store.get_object_metadata( - self.FILE, container=self.FOLDER) - self.assertIsNone(obj.content_disposition) - self.assertIsNone(obj.content_encoding) - self.conn.object_store.set_object_metadata( - obj, content_disposition='attachment', content_encoding='gzip') - obj = self.conn.object_store.get_object_metadata(obj) - self.assertEqual('attachment', obj.content_disposition) - self.assertEqual('gzip', obj.content_encoding) - - # update system metadata - self.conn.object_store.set_object_metadata( - obj, content_encoding='deflate') - obj = self.conn.object_store.get_object_metadata(obj) - self.assertEqual('attachment', obj.content_disposition) - self.assertEqual('deflate', obj.content_encoding) - - # set system metadata and custom metadata - self.conn.object_store.set_object_metadata( - obj, k0='v0', delete_after='100') - obj = self.conn.object_store.get_object_metadata(obj) - self.assertIn('k0', obj.metadata) - self.assertEqual('v0', obj.metadata['k0']) - self.assertEqual('attachment', obj.content_disposition) - self.assertEqual('deflate', obj.content_encoding) - - # unset system metadata - self.conn.object_store.delete_object_metadata( - obj, keys=['delete_after']) - obj = self.conn.object_store.get_object_metadata(obj) - self.assertIn('k0', obj.metadata) - self.assertEqual('v0', obj.metadata['k0']) - self.assertEqual('attachment', obj.content_disposition) - self.assertEqual('deflate', obj.content_encoding) - self.assertIsNone(obj.delete_at) - - # unset more system metadata - self.conn.object_store.delete_object_metadata( - obj, keys=['content_disposition']) - obj = self.conn.object_store.get_object_metadata(obj) - self.assertIn('k0', obj.metadata) - self.assertEqual('v0', obj.metadata['k0']) - self.assertIsNone(obj.content_disposition) - self.assertEqual('deflate', obj.content_encoding) - self.assertIsNone(obj.delete_at) - - def test_custom_metadata(self): - # get custom metadata - obj = self.conn.object_store.get_object_metadata( - self.FILE, container=self.FOLDER) - self.assertFalse(obj.metadata) - - # set no custom metadata - self.conn.object_store.set_object_metadata(obj) - obj = self.conn.object_store.get_object_metadata(obj) - self.assertFalse(obj.metadata) - - # set empty custom metadata - self.conn.object_store.set_object_metadata(obj, k0='') - obj = self.conn.object_store.get_object_metadata(obj) - self.assertFalse(obj.metadata) - - # set custom metadata - self.conn.object_store.set_object_metadata(obj, k1='v1') - obj = self.conn.object_store.get_object_metadata(obj) - self.assertTrue(obj.metadata) - self.assertEqual(1, len(obj.metadata)) - self.assertIn('k1', obj.metadata) - self.assertEqual('v1', obj.metadata['k1']) - - # set more custom metadata by named object and container - self.conn.object_store.set_object_metadata(self.FILE, self.FOLDER, - k2='v2') - obj = self.conn.object_store.get_object_metadata(obj) - self.assertTrue(obj.metadata) - self.assertEqual(2, len(obj.metadata)) - self.assertIn('k1', obj.metadata) - self.assertEqual('v1', obj.metadata['k1']) - self.assertIn('k2', obj.metadata) - self.assertEqual('v2', obj.metadata['k2']) - - # update custom metadata - self.conn.object_store.set_object_metadata(obj, k1='v1.1') - obj = self.conn.object_store.get_object_metadata(obj) - self.assertTrue(obj.metadata) - self.assertEqual(2, len(obj.metadata)) - self.assertIn('k1', obj.metadata) - self.assertEqual('v1.1', obj.metadata['k1']) - self.assertIn('k2', obj.metadata) - self.assertEqual('v2', obj.metadata['k2']) - - # unset custom metadata - self.conn.object_store.delete_object_metadata(obj, keys=['k1']) - obj = self.conn.object_store.get_object_metadata(obj) - self.assertTrue(obj.metadata) - self.assertEqual(1, len(obj.metadata)) - self.assertIn('k2', obj.metadata) - self.assertEqual('v2', obj.metadata['k2']) diff --git a/ecl/tests/functional/telemetry/v2/test_meter.py b/ecl/tests/functional/telemetry/v2/test_meter.py deleted file mode 100755 index 536cfd8..0000000 --- a/ecl/tests/functional/telemetry/v2/test_meter.py +++ /dev/null @@ -1,32 +0,0 @@ -# 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 unittest -import uuid - -from ecl.tests.functional import base - - -@unittest.skipUnless(base.service_exists(service_type="metering"), - "Metering service does not exist") -class TestMeter(base.BaseFunctionalTest): - - def test_list(self): - # TODO(thowe): Remove this in favor of create_meter call. - # Since we do not have a create meter method at the moment - # make sure there is some data in there - name = uuid.uuid4().hex - tainer = self.conn.object_store.create_container(name=name) - self.conn.object_store.delete_container(tainer) - - names = set([o.name for o in self.conn.telemetry.meters()]) - self.assertIn('storage.objects.incoming.bytes', names) diff --git a/ecl/tests/unit/object_store/__init__.py b/ecl/tests/unit/object_store/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/ecl/tests/unit/object_store/test_object_store_service.py b/ecl/tests/unit/object_store/test_object_store_service.py deleted file mode 100755 index 5a02f2a..0000000 --- a/ecl/tests/unit/object_store/test_object_store_service.py +++ /dev/null @@ -1,28 +0,0 @@ -# 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 ecl.object_store import object_store_service - - -class TestObjectStoreService(testtools.TestCase): - - def test_service(self): - sot = object_store_service.ObjectStoreService() - self.assertEqual('object-store', sot.service_type) - self.assertEqual('public', sot.interface) - self.assertIsNone(sot.region) - self.assertIsNone(sot.service_name) - self.assertEqual(1, len(sot.valid_versions)) - self.assertEqual('v1', sot.valid_versions[0].module) - self.assertEqual('v1', sot.valid_versions[0].path) diff --git a/ecl/tests/unit/object_store/v1/__init__.py b/ecl/tests/unit/object_store/v1/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/ecl/tests/unit/object_store/v1/test_account.py b/ecl/tests/unit/object_store/v1/test_account.py deleted file mode 100755 index a97b61d..0000000 --- a/ecl/tests/unit/object_store/v1/test_account.py +++ /dev/null @@ -1,56 +0,0 @@ -# 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 ecl.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', - 'x-timestamp': '1453413555.88937' -} - - -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) - self.assertEqual(ACCOUNT_EXAMPLE['x-timestamp'], sot.timestamp) diff --git a/ecl/tests/unit/object_store/v1/test_container.py b/ecl/tests/unit/object_store/v1/test_container.py deleted file mode 100755 index f81e0b3..0000000 --- a/ecl/tests/unit/object_store/v1/test_container.py +++ /dev/null @@ -1,171 +0,0 @@ -# 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 mock -import testtools - -from ecl.object_store.v1 import container - - -CONTAINER_NAME = "mycontainer" - -CONT_EXAMPLE = { - "count": 999, - "bytes": 12345, - "name": CONTAINER_NAME -} - -HEAD_EXAMPLE = { - 'content-length': '346', - 'x-container-object-count': '2', - 'accept-ranges': 'bytes', - 'id': 'tx1878fdc50f9b4978a3fdc-0053c31462', - 'date': 'Sun, 13 Jul 2014 23:21:06 GMT', - 'x-container-read': 'read-settings', - 'x-container-write': 'write-settings', - 'x-container-sync-to': 'sync-to', - 'x-container-sync-key': 'sync-key', - 'x-container-bytes-used': '630666', - 'x-versions-location': 'versions-location', - 'content-type': 'application/json; charset=utf-8', - 'x-timestamp': '1453414055.48672' -} - -LIST_EXAMPLE = [ - { - "count": 999, - "bytes": 12345, - "name": "container1" - }, - { - "count": 888, - "bytes": 54321, - "name": "container2" - } -] - - -class TestContainer(testtools.TestCase): - - def setUp(self): - super(TestContainer, self).setUp() - self.resp = mock.Mock() - self.resp.body = {} - self.resp.json = mock.Mock(return_value=self.resp.body) - self.resp.headers = {"X-Trans-Id": "abcdef"} - self.sess = mock.Mock() - self.sess.put = mock.Mock(return_value=self.resp) - self.sess.post = mock.Mock(return_value=self.resp) - - def test_basic(self): - sot = container.Container.new(**CONT_EXAMPLE) - self.assertIsNone(sot.resources_key) - self.assertEqual('name', sot.id_attribute) - self.assertEqual('/', sot.base_path) - self.assertEqual('object-store', sot.service.service_type) - self.assertTrue(sot.allow_update) - self.assertTrue(sot.allow_create) - self.assertTrue(sot.allow_retrieve) - self.assertTrue(sot.allow_delete) - self.assertTrue(sot.allow_list) - self.assertTrue(sot.allow_head) - - def test_make_it(self): - sot = container.Container.new(**CONT_EXAMPLE) - self.assertEqual(CONT_EXAMPLE['name'], sot.id) - self.assertEqual(CONT_EXAMPLE['name'], sot.name) - self.assertEqual(CONT_EXAMPLE['count'], sot.count) - self.assertEqual(CONT_EXAMPLE['bytes'], sot.bytes) - - def test_create_and_head(self): - sot = container.Container(CONT_EXAMPLE) - - # Update container with HEAD data - sot._attrs.update({'headers': HEAD_EXAMPLE}) - - # Attributes from create - self.assertEqual(CONT_EXAMPLE['name'], sot.id) - self.assertEqual(CONT_EXAMPLE['name'], sot.name) - self.assertEqual(CONT_EXAMPLE['count'], sot.count) - self.assertEqual(CONT_EXAMPLE['bytes'], sot.bytes) - - # Attributes from header - self.assertEqual(int(HEAD_EXAMPLE['x-container-object-count']), - sot.object_count) - self.assertEqual(int(HEAD_EXAMPLE['x-container-bytes-used']), - sot.bytes_used) - self.assertEqual(HEAD_EXAMPLE['x-container-read'], - sot.read_ACL) - self.assertEqual(HEAD_EXAMPLE['x-container-write'], - sot.write_ACL) - self.assertEqual(HEAD_EXAMPLE['x-container-sync-to'], - sot.sync_to) - self.assertEqual(HEAD_EXAMPLE['x-container-sync-key'], - sot.sync_key) - self.assertEqual(HEAD_EXAMPLE['x-versions-location'], - sot.versions_location) - self.assertEqual(HEAD_EXAMPLE['x-timestamp'], sot.timestamp) - - @mock.patch("ecl.resource.Resource.list") - def test_list(self, fake_list): - fake_val = [container.Container.existing(**ex) for ex in LIST_EXAMPLE] - fake_list.return_value = fake_val - - # Since the list method is mocked out, just pass None for the session. - response = container.Container.list(None) - - self.assertEqual(len(LIST_EXAMPLE), len(response)) - for item in range(len(response)): - self.assertEqual(container.Container, type(response[item])) - self.assertEqual(LIST_EXAMPLE[item]["name"], response[item].name) - self.assertEqual(LIST_EXAMPLE[item]["count"], response[item].count) - self.assertEqual(LIST_EXAMPLE[item]["bytes"], response[item].bytes) - - def _test_create_update(self, sot, sot_call, sess_method): - sot.read_ACL = "some ACL" - sot.write_ACL = "another ACL" - sot.is_content_type_detected = True - headers = { - "x-container-read": "some ACL", - "x-container-write": "another ACL", - "x-detect-content-type": True, - "Accept": "", - } - sot_call(self.sess) - - url = "/%s" % CONTAINER_NAME - sess_method.assert_called_with(url, endpoint_filter=sot.service, - headers=headers) - - def test_create(self): - sot = container.Container.new(name=CONTAINER_NAME) - self._test_create_update(sot, sot.create, self.sess.put) - - def test_update(self): - sot = container.Container.new(name=CONTAINER_NAME) - self._test_create_update(sot, sot.update, self.sess.post) - - def _test_no_headers(self, sot, sot_call, sess_method): - sot = container.Container.new(name=CONTAINER_NAME) - sot.create(self.sess) - url = "/%s" % CONTAINER_NAME - headers = {'Accept': ''} - self.sess.put.assert_called_with(url, endpoint_filter=sot.service, - headers=headers) - - def test_create_no_headers(self): - sot = container.Container.new(name=CONTAINER_NAME) - self._test_no_headers(sot, sot.create, self.sess.put) - - def test_update_no_headers(self): - sot = container.Container.new(name=CONTAINER_NAME) - self._test_no_headers(sot, sot.update, self.sess.post) diff --git a/ecl/tests/unit/object_store/v1/test_obj.py b/ecl/tests/unit/object_store/v1/test_obj.py deleted file mode 100755 index 2f55798..0000000 --- a/ecl/tests/unit/object_store/v1/test_obj.py +++ /dev/null @@ -1,137 +0,0 @@ -# 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 mock -import testtools - -from ecl.object_store.v1 import obj - - -CONTAINER_NAME = "mycontainer" -OBJECT_NAME = "myobject" - -# Object can receive both last-modified in headers and last_modified in -# the body. However, originally, only last-modified was handled as an -# expected prop but it was named last_modified. Under Python 3, creating -# an Object with the body value last_modified causes the _attrs dictionary -# size to change while iterating over its values as we have an attribute -# called `last_modified` and we attempt to grow an additional attribute -# called `last-modified`, which is the "name" of `last_modified`. -# The same is true of content_type and content-type, or any prop -# attribute which would follow the same pattern. -# This example should represent the body values returned by a GET, so the keys -# must be underscores. -OBJ_EXAMPLE = { - "hash": "243f87b91224d85722564a80fd3cb1f1", - "last_modified": "2014-07-13T18:41:03.319240", - "bytes": 252466, - "name": OBJECT_NAME, - "content_type": "application/octet-stream" -} - -DICT_EXAMPLE = { - 'container': CONTAINER_NAME, - 'name': OBJECT_NAME, - 'content_type': 'application/octet-stream', - 'headers': { - 'content-length': '252466', - 'accept-ranges': 'bytes', - 'last-modified': 'Sun, 13 Jul 2014 18:41:04 GMT', - 'etag': '243f87b91224d85722564a80fd3cb1f1', - 'x-timestamp': '1453414256.28112', - 'date': 'Thu, 28 Aug 2014 14:41:59 GMT', - 'id': 'tx5fb5ad4f4d0846c6b2bc7-0053ff3fb7', - 'x-delete-at': '1453416226.16744' - } -} - - -class TestObject(testtools.TestCase): - - def setUp(self): - super(TestObject, self).setUp() - self.resp = mock.Mock() - self.resp.content = "lol here's some content" - self.resp.headers = {"X-Trans-Id": "abcdef"} - self.sess = mock.Mock() - self.sess.get = mock.Mock(return_value=self.resp) - self.sess.put = mock.Mock(return_value=self.resp) - self.sess.post = mock.Mock(return_value=self.resp) - - def test_basic(self): - sot = obj.Object.new(**OBJ_EXAMPLE) - self.assertIsNone(sot.resources_key) - self.assertEqual("name", sot.id_attribute) - self.assertEqual('/%(container)s', sot.base_path) - self.assertEqual('object-store', sot.service.service_type) - self.assertTrue(sot.allow_update) - self.assertTrue(sot.allow_create) - self.assertTrue(sot.allow_retrieve) - self.assertTrue(sot.allow_delete) - self.assertTrue(sot.allow_list) - self.assertTrue(sot.allow_head) - - def test_new(self): - sot = obj.Object.new(container=CONTAINER_NAME, name=OBJECT_NAME) - self.assertEqual(OBJECT_NAME, sot.name) - self.assertEqual(CONTAINER_NAME, sot.container) - - def test_head(self): - sot = obj.Object.existing(**DICT_EXAMPLE) - - # Attributes from header - self.assertEqual(DICT_EXAMPLE['container'], sot.container) - headers = DICT_EXAMPLE['headers'] - self.assertEqual(headers['content-length'], sot.content_length) - self.assertEqual(headers['accept-ranges'], sot.accept_ranges) - self.assertEqual(headers['last-modified'], sot.last_modified_at) - self.assertEqual(headers['etag'], sot.etag) - self.assertEqual(headers['x-timestamp'], sot.timestamp) - self.assertEqual(headers['content-type'], sot.content_type) - self.assertEqual(headers['x-delete-at'], sot.delete_at) - - def test_get(self): - sot = obj.Object.new(container=CONTAINER_NAME, name=OBJECT_NAME) - sot.is_newest = True - sot.if_match = {"who": "what"} - - rv = sot.get(self.sess) - - url = "%s/%s" % (CONTAINER_NAME, OBJECT_NAME) - # TODO(thowe): Should allow filtering bug #1488269 - # headers = { - # "x-newest": True, - # "if-match": {"who": "what"} - # } - headers = {'Accept': 'bytes'} - self.sess.get.assert_called_with(url, endpoint_filter=sot.service, - headers=headers) - self.assertEqual(self.resp.content, rv) - - def _test_create(self, method, data, accept): - sot = obj.Object.new(container=CONTAINER_NAME, name=OBJECT_NAME, - data=data) - sot.is_newest = True - headers = {"x-newest": True, "Accept": ""} - - rv = sot.create(self.sess) - - url = "%s/%s" % (CONTAINER_NAME, OBJECT_NAME) - method.assert_called_with(url, endpoint_filter=sot.service, data=data, - headers=headers) - self.assertEqual(self.resp.headers, rv.get_headers()) - - def test_create_data(self): - self._test_create(self.sess.put, "data", "bytes") - - def test_create_no_data(self): - self._test_create(self.sess.post, None, None) diff --git a/ecl/tests/unit/object_store/v1/test_proxy.py b/ecl/tests/unit/object_store/v1/test_proxy.py deleted file mode 100755 index 85b216c..0000000 --- a/ecl/tests/unit/object_store/v1/test_proxy.py +++ /dev/null @@ -1,277 +0,0 @@ -# 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 mock -import six - -from ecl.object_store.v1 import _proxy -from ecl.object_store.v1 import account -from ecl.object_store.v1 import container -from ecl.object_store.v1 import obj -from ecl.tests.unit import test_proxy_base - - -class TestObjectStoreProxy(test_proxy_base.TestProxyBase): - - def setUp(self): - super(TestObjectStoreProxy, self).setUp() - self.proxy = _proxy.Proxy(self.session) - - def test_account_metadata_get(self): - self.verify_head(self.proxy.get_account_metadata, account.Account) - - def test_container_metadata_get(self): - self.verify_head(self.proxy.get_container_metadata, - container.Container, value="container") - - def test_container_delete(self): - self.verify_delete(self.proxy.delete_container, - container.Container, False) - - def test_container_delete_ignore(self): - self.verify_delete(self.proxy.delete_container, - container.Container, True) - - def test_container_create_attrs(self): - self.verify_create(self.proxy.create_container, container.Container) - - def test_object_metadata_get(self): - self.verify_head(self.proxy.get_object_metadata, obj.Object, - value="object", container="container") - - def _test_object_delete(self, ignore): - expected_kwargs = {"path_args": {"container": "name"}} - expected_kwargs["ignore_missing"] = ignore - - self._verify2("ecl.proxy.BaseProxy._delete", - self.proxy.delete_object, - method_args=["resource"], - method_kwargs={"container": "name", - "ignore_missing": ignore}, - expected_args=[obj.Object, "resource"], - expected_kwargs=expected_kwargs) - - def test_object_delete(self): - self._test_object_delete(False) - - def test_object_delete_ignore(self): - self._test_object_delete(True) - - def test_object_create_attrs(self): - path_args = {"path_args": {"container": "name"}} - method_kwargs = {"name": "test", "data": "data", "container": "name"} - - expected_kwargs = path_args.copy() - expected_kwargs.update(method_kwargs) - expected_kwargs.pop("container") - - self._verify2("ecl.proxy.BaseProxy._create", - self.proxy.upload_object, - method_kwargs=method_kwargs, - expected_args=[obj.Object], - expected_kwargs=expected_kwargs) - - def test_object_create_no_container(self): - self.assertRaises(ValueError, self.proxy.upload_object) - - def test_object_get(self): - self.verify_get(self.proxy.get_object, obj.Object, - value=["object"], container="container") - - -class Test_containers(TestObjectStoreProxy): - - def setUp(self): - super(Test_containers, self).setUp() - self.proxy = _proxy.Proxy(self.session) - - self.containers_body = [] - for i in range(3): - self.containers_body.append({six.text_type("name"): - six.text_type("container%d" % i)}) - -# @httpretty.activate -# def test_all_containers(self): -# self.stub_url(httpretty.GET, -# path=[container.Container.base_path], -# responses=[httpretty.Response( -# body=json.dumps(self.containers_body), -# status=200, content_type="application/json"), -# httpretty.Response(body=json.dumps([]), -# status=200, content_type="application/json")]) -# -# count = 0 -# for actual, expected in zip(self.proxy.containers(), -# self.containers_body): -# self.assertEqual(expected, actual) -# count += 1 -# self.assertEqual(len(self.containers_body), count) - -# @httpretty.activate -# def test_containers_limited(self): -# limit = len(self.containers_body) + 1 -# limit_param = "?limit=%d" % limit -# -# self.stub_url(httpretty.GET, -# path=[container.Container.base_path + limit_param], -# json=self.containers_body) -# -# count = 0 -# for actual, expected in zip(self.proxy.containers(limit=limit), -# self.containers_body): -# self.assertEqual(actual, expected) -# count += 1 -# -# self.assertEqual(len(self.containers_body), count) -# # Since we've chosen a limit larger than the body, only one request -# # should be made, so it should be the last one. -# self.assertIn(limit_param, httpretty.last_request().path) - -# @httpretty.activate -# def test_containers_with_marker(self): -# marker = six.text_type("container2") -# marker_param = "marker=%s" % marker -# -# self.stub_url(httpretty.GET, -# path=[container.Container.base_path + "?" + -# marker_param], -# json=self.containers_body) -# -# count = 0 -# for actual, expected in zip(self.proxy.containers(marker=marker), -# self.containers_body): -# # Make sure the marker made it into the actual request. -# self.assertIn(marker_param, httpretty.last_request().path) -# self.assertEqual(expected, actual) -# count += 1 -# -# self.assertEqual(len(self.containers_body), count) -# -# # Since we have to make one request beyond the end, because no -# # limit was provided, make sure the last container appears as -# # the marker in this last request. -# self.assertIn(self.containers_body[-1]["name"], -# httpretty.last_request().path) - - -class Test_objects(TestObjectStoreProxy): - - def setUp(self): - super(Test_objects, self).setUp() - self.proxy = _proxy.Proxy(self.session) - - self.container_name = six.text_type("my_container") - - self.objects_body = [] - for i in range(3): - self.objects_body.append({six.text_type("name"): - six.text_type("object%d" % i)}) - - # Returned object bodies have their container inserted. - self.returned_objects = [] - for ob in self.objects_body: - ob[six.text_type("container")] = self.container_name - self.returned_objects.append(ob) - self.assertEqual(len(self.objects_body), len(self.returned_objects)) - -# @httpretty.activate -# def test_all_objects(self): -# self.stub_url(httpretty.GET, -# path=[obj.Object.base_path % -# {"container": self.container_name}], -# responses=[httpretty.Response( -# body=json.dumps(self.objects_body), -# status=200, content_type="application/json"), -# httpretty.Response(body=json.dumps([]), -# status=200, content_type="application/json")]) -# -# count = 0 -# for actual, expected in zip(self.proxy.objects(self.container_name), -# self.returned_objects): -# self.assertEqual(expected, actual) -# count += 1 -# self.assertEqual(len(self.returned_objects), count) - -# @httpretty.activate -# def test_objects_limited(self): -# limit = len(self.objects_body) + 1 -# limit_param = "?limit=%d" % limit -# -# self.stub_url(httpretty.GET, -# path=[obj.Object.base_path % -# {"container": self.container_name} + limit_param], -# json=self.objects_body) -# -# count = 0 -# for actual, expected in zip(self.proxy.objects(self.container_name, -# limit=limit), -# self.returned_objects): -# self.assertEqual(expected, actual) -# count += 1 -# -# self.assertEqual(len(self.returned_objects), count) -# # Since we've chosen a limit larger than the body, only one request -# # should be made, so it should be the last one. -# self.assertIn(limit_param, httpretty.last_request().path) - -# @httpretty.activate -# def test_objects_with_marker(self): -# marker = six.text_type("object2") -# # marker_param = "marker=%s" % marker -# -# self.stub_url(httpretty.GET, -# path=[obj.Object.base_path % -# {"container": self.container_name} + "?" + -# marker_param], -# json=self.objects_body) -# -# count = 0 -# for actual, expected in zip(self.proxy.objects(self.container_name, -# marker=marker), -# self.returned_objects): -# # Make sure the marker made it into the actual request. -# self.assertIn(marker_param, httpretty.last_request().path) -# self.assertEqual(expected, actual) -# count += 1 -# -# self.assertEqual(len(self.returned_objects), count) -# -# # Since we have to make one request beyond the end, because no -# # limit was provided, make sure the last container appears as -# # the marker in this last request. -# self.assertIn(self.returned_objects[-1]["name"], -# httpretty.last_request().path) - - -class Test_download_object(TestObjectStoreProxy): - - @mock.patch("ecl.object_store.v1._proxy.Proxy.get_object") - def test_download(self, mock_get): - the_data = "here's some data" - mock_get.return_value = the_data - ob = mock.Mock() - - fake_open = mock.mock_open() - file_path = "blarga/somefile" - with mock.patch("ecl.object_store.v1._proxy.open", - fake_open, create=True): - self.proxy.download_object(ob, container="tainer", path=file_path) - - fake_open.assert_called_once_with(file_path, "w") - fake_handle = fake_open() - fake_handle.write.assert_called_once_with(the_data) - - -class Test_copy_object(TestObjectStoreProxy): - - def test_copy_object(self): - self.assertRaises(NotImplementedError, self.proxy.copy_object)