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/_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/database/__init__.py b/ecl/mvna/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from ecl/database/__init__.py rename to ecl/mvna/__init__.py diff --git a/ecl/database/database_service.py b/ecl/mvna/mvna_service.py old mode 100755 new mode 100644 similarity index 71% rename from ecl/database/database_service.py rename to ecl/mvna/mvna_service.py index 3818dd1..3fd95bf --- a/ecl/database/database_service.py +++ b/ecl/mvna/mvna_service.py @@ -13,12 +13,12 @@ from ecl import service_filter -class DatabaseService(service_filter.ServiceFilter): - """Database(Trove) service""" +class MVNAService(service_filter.ServiceFilter): + """The mvna 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) + """Create a mvna service.""" + super(MVNAService, self).__init__(service_type='managed-load-balancer', + version=version) diff --git a/ecl/database/v1/__init__.py b/ecl/mvna/v1/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from ecl/database/v1/__init__.py rename to ecl/mvna/v1/__init__.py diff --git a/ecl/mvna/v1/_proxy.py b/ecl/mvna/v1/_proxy.py new file mode 100644 index 0000000..bf0536d --- /dev/null +++ b/ecl/mvna/v1/_proxy.py @@ -0,0 +1,1209 @@ +from ecl import proxy2 +from ecl.mvna.v1 import certificate as _certificate +from ecl.mvna.v1 import health_monitor as _health_monitor +from ecl.mvna.v1 import listener as _listener +from ecl.mvna.v1 import load_balancer as _load_balancer +from ecl.mvna.v1 import maintenance as _maintenance +from ecl.mvna.v1 import operation as _operation +from ecl.mvna.v1 import plan as _plan +from ecl.mvna.v1 import policy as _policy +from ecl.mvna.v1 import route as _route +from ecl.mvna.v1 import rule as _rule +from ecl.mvna.v1 import target_group as _target_group +from ecl.mvna.v1 import tls_security_policy as _tls_security_policy + + +class Proxy(proxy2.BaseProxy): + + def load_balancers(self, **params): + """List Managed Load Balancers.""" + return list(self._list(_load_balancer.LoadBalancer, paginated=False, + **params)) + + # NOTE(NaoShark): :param syslog_servers: will be available from Day 2. + def create_load_balancer(self, plan_id, interfaces, + name=None, description=None, tags=None, + # syslog_servers=None + ): + """Create Managed Load Balancer. + + :param string plan_id: Plan ID of Managed Load Balancer + :param list interfaces: Interface of Managed Load Balancer + :param string name: Name of Managed Load Balancer + :param string description: Description of Managed Load Balancer + :param dict tags: Tags of Managed Load Balancer + # :param list syslog_servers: Syslog Servers of Managed Load Balancer + :return: Managed Load Balancer + """ + body = {"plan_id": plan_id, "interfaces": interfaces} + if name: + body["name"] = name + if description: + body["description"] = description + if tags: + body["tags"] = tags + # if syslog_servers: + # body["syslog_servers"] = syslog_servers + return self._create(_load_balancer.LoadBalancer, **body) + + def get_load_balancer(self, load_balancer_id, changes=None): + """Retrieve Managed Load Balancer Information. + + :param string load_balancer_id: ID of Managed Load Balancer + :param bool changes: Whether or not to retrieve staged configuration + :return: Managed Load Balancer + """ + load_balancer = _load_balancer.LoadBalancer() + return load_balancer.get_resource(self.session, load_balancer_id, + changes) + + def update_load_balancer(self, load_balancer_id, **params): + """Update Managed Load Balancer Attributes. + + :param string load_balancer_id: ID of Managed Load Balancer + :attrs **params: Parameters for load balancer update. + + * string name: Name of Managed Load Balancer + * string description: Description of Managed Load Balancer + * dict tags: Tags of Managed Load Balancer + + :return: Managed Load Balancer + """ + return self._update(_load_balancer.LoadBalancer, load_balancer_id, + **params) + + def delete_load_balancer(self, load_balancer_id, x_mvna_request_id=None, + ignore_missing=False): + """Delete Managed Load Balancer. + + :param string load_balancer_id: ID of Managed Load Balancer + :param string x_mvna_request_id: ID to identify the transaction history + :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 load balancer. + :return: None + """ + load_balancer = _load_balancer.LoadBalancer() + load_balancer.delete_resource(self.session, load_balancer_id, + x_mvna_request_id, ignore_missing) + + def action_load_balancer(self, load_balancer_id, x_mvna_request_id=None, + **body): + """Reflect the configuration to Managed Load Balancer. + + :param string load_balancer_id: ID of Managed Load Balancer + :param string x_mvna_request_id: ID to identify the transaction history + :param dict body: Request Body which want to apply. + :return: None + """ + load_balancer = _load_balancer.LoadBalancer() + load_balancer.action(self.session, load_balancer_id, x_mvna_request_id, + **body) + + # NOTE(NaoShark): :param syslog_servers: will be available from Day 2. + def create_staged_load_balancer_configuration(self, + load_balancer_id, + # syslog_servers=None, + interfaces=None): + """Create Staged Managed Load Balancer Configuration. + + :param string load_balancer_id: ID of Managed Load Balancer + # :param list syslog_servers: Syslog Servers of Managed Load Balancer + :param list interfaces: Interface of Managed Load Balancer + :return: Managed Load Balancer + """ + body = {} + # if syslog_servers: + # body["syslog_servers"] = syslog_servers + if interfaces: + body["interfaces"] = interfaces + + load_balancer = _load_balancer.LoadBalancer() + return load_balancer.create_staged_configuration(self.session, + load_balancer_id, + **body) + + def get_staged_load_balancer_configuration(self, load_balancer_id): + """Retrieve Staged Managed Load Balancer Configuration. + + :param string load_balancer_id: ID of Managed Load Balancer + :return: Managed Load Balancer + """ + return self._get(_load_balancer.LoadBalancer, load_balancer_id) + + # NOTE(NaoShark): :param syslog_servers: will be available from Day 2. + def update_staged_load_balancer_configuration(self, + load_balancer_id, + # syslog_servers=None, + interfaces=None): + """Update Staged Managed Load Balancer Configuration. + + :param string load_balancer_id: ID of Managed Load Balancer + # :param list syslog_servers: Syslog Servers of Managed Load Balancer + :param list interfaces: Interface of Managed Load Balancer + :return: Managed Load Balancer + """ + body = {} + # if syslog_servers: + # body["syslog_servers"] = syslog_servers + if interfaces: + body["interfaces"] = interfaces + + load_balancer = _load_balancer.LoadBalancer() + return load_balancer.update_staged_configuration(self.session, + load_balancer_id, + **body) + + def cancel_staged_load_balancer_configuration(self, load_balancer_id): + """Delete Staged Managed Load Balancer Configuration. + + :param string load_balancer_id: ID of Managed Load Balancer + :return: None + """ + load_balancer = _load_balancer.LoadBalancer() + load_balancer.cancel_staged_configuration(self.session, + load_balancer_id) + + def target_groups(self, **params): + """List Target Groups.""" + return list(self._list( + _target_group.TargetGroup, paginated=False, **params)) + + def create_target_group(self, load_balancer_id, members, + name=None, description=None, tags=None): + """Create Target Group. + + :param string load_balancer_id: Load Balancer ID of Target Group + :param string members: Members of Target Group + :param string name: Name of Target Group + :param string description: Description of Target Group + :param dict tags: Tags of Target Group + :return: Target Group + """ + body = { + 'load_balancer_id': load_balancer_id, + 'members': members + } + if name: + body["name"] = name + if description: + body["description"] = description + if tags: + body["tags"] = tags + return self._create(_target_group.TargetGroup, **body) + + def get_target_group(self, target_group_id, changes=None): + """Retrieve Target Group Information. + + :param string target_group_id: ID of Target Group + :param bool changes: Whether or not to retrieve staged configuration + :return: Target Group + """ + target_group = _target_group.TargetGroup() + return target_group.get_resource(self.session, target_group_id, + changes) + + def update_target_group(self, target_group_id, **params): + """Update Target Group Attributes. + + :param string load_balancer_id: ID of Managed Load Balancer + :attrs **params: Parameters for target group update. + + * string name: Name of Managed Load Balancer + * string description: Description of Managed Load Balancer + * dict tags: Tags of Managed Load Balancer + + :return: Target Group + """ + return self._update(_target_group.TargetGroup, target_group_id, + **params) + + def delete_target_group(self, target_group_id, ignore_missing=False): + """Delete Target Group. + + :param string target_group_id: ID of Target Group + :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 target group. + :return: None + """ + self._delete(_target_group.TargetGroup, target_group_id, + ignore_missing=ignore_missing) + + def create_staged_target_group_configuration(self, target_group_id, + members=None): + """Create Staged Target Group Configuration. + + :param string target_group_id: ID of Target Group + :param string members: Members of Target Group + :return: Target Group + """ + body = {} + if members: + body["members"] = members + + target_group = _target_group.TargetGroup() + return target_group.create_staged_configuration(self.session, + target_group_id, + **body) + + def get_staged_target_group_configuration(self, target_group_id): + """Retrieve Staged Target Group Configuration. + + :param string target_group_id: ID of Target Group + :return: Target Group + """ + return self._get(_target_group.TargetGroup, target_group_id) + + def update_staged_target_group_configuration(self, target_group_id, + members=None): + """Update Staged Target Group Configuration. + + :param string target_group_id: ID of Target Group + :param string members: Members of Target Group + :return: Target Group + """ + body = {} + if members: + body["members"] = members + + target_group = _target_group.TargetGroup() + return target_group.update_staged_configuration(self.session, + target_group_id, + **body) + + def cancel_staged_target_group_configuration(self, target_group_id): + """Delete Staged Target Group Configuration. + + :param string target_group_id: ID of Target Group + :return: None + """ + target_group = _target_group.TargetGroup() + target_group.cancel_staged_configuration(self.session, target_group_id) + + # NOTE(NaoShark): The following features will be available from Day 2 + # (certificates, create_certificate, get_certificate, update_certificate, + # delete_certificate, upload_certificate) + ''' + def certificates(self, **params): + """List Certificates.""" + return list(self._list( + _certificate.Certificate, paginated=False, **params)) + + def create_certificate(self, name=None, description=None, tags=None): + """Create Certificate. + + :param string name: Name of Certificate + :param string description: Description of Certificate + :param string tags: Tags of Certificate + :return: Certificate + """ + body = {} + if name: + body["name"] = name + if description: + body["description"] = description + if tags: + body["tags"] = tags + return self._create(_certificate.Certificate, **body) + + def get_certificate(self, certificate_id): + """Retrieve Certificate Information. + + :param string certificate_id: ID of Certificate + :return: Certificate + """ + return self._get(_certificate.Certificate, certificate_id) + + def update_certificate(self, certificate_id, + name=None, description=None, tags=None): + """Update Certificate Attributes. + + :param string certificate_id: ID of Certificate + :param string name: Name of Certificate + :param string description: Description of Certificate + :param dict tags: Tags of Certificate + :return: Certificate + """ + body = {} + if name: + body["name"] = name + if description: + body["description"] = description + if tags: + body["tags"] = tags + return self._update(_certificate.Certificate, certificate_id, + **body) + + def delete_certificate(self, certificate_id, ignore_missing=False): + """Delete Certificate. + + :param string certificate_id: ID of Certificate + :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 certificate. + :return: None + """ + self._delete(_certificate.Certificate, certificate_id, + ignore_missing=ignore_missing) + + def upload_certificate(self, + certificate_id, certificate_type, certificate_file): + """Upload the Certificate. + + :param string certificate_id: ID of Certificate + :param string certificate_type: Type of Certificate + :param string certificate_file: File of Certificate + :return: None + """ + body = {'type': certificate_type, 'file': certificate_file} + certificate = _certificate.Certificate() + certificate.upload(self.session, certificate_id, **body) + ''' + + def listeners(self, **params): + """List Listeners.""" + return list(self._list( + _listener.Listener, paginated=False, **params)) + + def create_listener(self, ip_address, port, protocol, load_balancer_id, + name=None, description=None, tags=None): + """Create Listener. + + :param string ip_address: IP Address of Listener + :param string port: Port of Listener + :param string protocol: Protocol of Listener + :param string load_balancer_id: Load Balancer ID of Listener + :param string name: Name of Listener + :param string description: Description of Listener + :param dict tags: Tags of Listener + + :return: Listener + """ + body = { + 'ip_address': ip_address, + 'port': port, + 'protocol': protocol, + 'load_balancer_id': load_balancer_id + } + if name: + body["name"] = name + if description: + body["description"] = description + if tags: + body["tags"] = tags + return self._create(_listener.Listener, **body) + + def get_listener(self, listener_id, changes=None): + """Retrieve Listener Information. + + :param string listener_id: ID of Listener + :param bool changes: Whether or not to retrieve staged configuration + :return: Listener + """ + listener = _listener.Listener() + return listener.get_resource(self.session, listener_id, changes) + + def update_listener(self, listener_id, **params): + """Update Listener Attributes. + + :param string listener_id: ID of Listener + + :attrs **params: Parameters for listener update. + + * string name: Name of Listener + * string description: Description of Listener + * dict tags: Tags of Listener + + :return: Listener + """ + return self._update(_listener.Listener, listener_id, **params) + + def delete_listener(self, listener_id, ignore_missing=False): + """Delete Listener. + + :param string listener_id: ID of Listener + :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 listener. + :return: None + """ + self._delete(_listener.Listener, listener_id, + ignore_missing=ignore_missing) + + def create_staged_listener_configuration( + self, listener_id, ip_address=None, port=None, protocol=None): + """Create Staged Listener Configuration. + + :param string listener_id: ID of Listener + :param string ip_address: IP Address of Listener + :param string port: Port of Listener + :param string protocol: Protocol of Listener + :return: Listener + """ + body = {} + if ip_address: + body["ip_address"] = ip_address + if port: + body["port"] = port + if protocol: + body["protocol"] = protocol + + listener = _listener.Listener() + return listener.create_staged_configuration(self.session, + listener_id, + **body) + + def get_staged_listener_configuration(self, listener_id): + """Retrieve Staged Listener Configuration. + + :param string listener_id: ID of Listener + :return: Listener + """ + return self._get(_listener.Listener, listener_id) + + def update_staged_listener_configuration( + self, listener_id, ip_address=None, port=None, protocol=None): + """Update Staged Listener Configuration. + + :param string listener_id: ID of Listener + :param string ip_address: IP Address of Listener + :param string port: Port of Listener + :param string protocol: Protocol of Listener + :return: Listener + """ + body = {} + if ip_address: + body["ip_address"] = ip_address + if port: + body["port"] = port + if protocol: + body["protocol"] = protocol + + listener = _listener.Listener() + return listener.update_staged_configuration(self.session, + listener_id, **body) + + def cancel_staged_listener_configuration(self, listener_id): + """Delete Staged Listener Configuration. + + :param string listener_id: ID of Listener + :return: None + """ + listener = _listener.Listener() + listener.cancel_staged_configuration(self.session, listener_id) + + # NOTE(NaoShark): The following features will be available from Day 2 + # (maintenances, get_maintenance) + ''' + def maintenances(self, **params): + """List Maintenances.""" + return list(self._list( + _maintenance.Maintenance, paginated=False, **params)) + + def get_maintenance(self, maintenance_id): + """Retrieve Maintenance Information. + + :param string maintenance_id: ID of maintenance + :return: Maintenance + """ + return self._get(_maintenance.Maintenance, maintenance_id) + ''' + + def plans(self, **params): + """List Plans.""" + return list(self._list(_plan.Plan, paginated=False, **params)) + + def get_plan(self, plan_id): + """Retrieve Plan Information. + + :param string plan_id: ID of plan + :return: Plan + """ + return self._get(_plan.Plan, plan_id) + + def health_monitors(self, **params): + """List Health Monitors.""" + return list(self._list( + _health_monitor.HealthMonitor, paginated=False, **params)) + + # NOTE(NaoShark): :param path: and :param http_status_code: will be + # available from Day 2. + def create_health_monitor(self, port, protocol, load_balancer_id, + name=None, description=None, tags=None, + interval=None, retry=None, timeout=None, + # path=None, http_status_code=None + ): + """Create Health Monitor. + + :param string port: Port of Health Monitor + :param string protocol: Protocol of Health Monitor + :param string load_balancer_id: Load Balancer ID + :param string name: Name of Health Monitor + :param string description: Description of Health Monitor + :param dict tags: Tags of Health Monitor + :param int interval: Interval of Health Monitor + :param int retry: Retry count of Health Monitor + :param int timeout: Timeout of Health Monitor + # :param string path: Path of Health Monitor + # :param string http_status_code: HTTP Status code of Health Monitor + + :return: Health Monitor + """ + body = { + 'port': port, + 'protocol': protocol, + 'load_balancer_id': load_balancer_id + } + if name: + body["name"] = name + if description: + body["description"] = description + if tags: + body["tags"] = tags + if interval: + body["interval"] = interval + if retry: + body["retry"] = retry + if timeout: + body["timeout"] = timeout + # if path: + # body["path"] = path + # if http_status_code: + # body["http_status_code"] = http_status_code + return self._create(_health_monitor.HealthMonitor, **body) + + def get_health_monitor(self, health_monitor_id, changes=None): + """Retrieve Health Monitor Information. + + :param string health_monitor_id: ID of Health Monitor + :param bool changes: Whether or not to retrieve staged configuration + :return: Health Monitor + """ + health_monitor = _health_monitor.HealthMonitor() + return health_monitor.get_resource(self.session, health_monitor_id, + changes) + + def update_health_monitor(self, health_monitor_id, **params): + """Update Health Monitor Attributes. + + :param string health_monitor_id: ID of Health Monitor + :attrs **params: Parameters for health monitor update. + + * string name: Name of Health Monitor + * string description: Description of Health Monitor + * dict tags: Tags of Health Monitor + + :return: Health Monitor + """ + return self._update(_health_monitor.HealthMonitor, health_monitor_id, + **params) + + def delete_health_monitor(self, health_monitor_id, ignore_missing=False): + """Delete Health Monitor. + + :param string health_monitor_id: ID of Health Monitor + :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 health monitor. + :return: None + """ + self._delete(_health_monitor.HealthMonitor, health_monitor_id, + ignore_missing=ignore_missing) + + # NOTE(NaoShark): :param path: and :param http_status_code: will be + # available from Day 2. + def create_staged_health_monitor_configuration( + self, health_monitor_id, + port=None, protocol=None, interval=None, retry=None, + timeout=None, + # path=None, http_status_code=None + ): + """Create Staged Health Monitor Configuration. + + :param string health_monitor_id: ID of Health Monitor + :param int port: Port of Health Monitor + :param string protocol: Protocol of Health Monitor + :param int interval: Interval of Health Monitor + :param int retry: Retry count of Health Monitor + :param int timeout: Timeout of Health Monitor + # :param string path: Path of Health Monitor + # :param string http_status_code: HTTP Status code of Health Monitor + :return: Health Monitor + """ + body = {} + if port is not None: + body["port"] = port + if protocol: + body["protocol"] = protocol + if interval: + body["interval"] = interval + if retry: + body["retry"] = retry + if timeout: + body["timeout"] = timeout + # if path: + # body["path"] = path + # if http_status_code: + # body["http_status_code"] = http_status_code + + health_monitor = _health_monitor.HealthMonitor() + return health_monitor.create_staged_configuration(self.session, + health_monitor_id, + **body) + + def get_staged_health_monitor_configuration(self, health_monitor_id): + """Retrieve Staged Health Monitor Configuration. + + :param string health_monitor_id: ID of Health_monitor + :return: Health Monitor + """ + return self._get(_health_monitor.HealthMonitor, health_monitor_id) + + # NOTE(NaoShark): :param path: and :param http_status_code: will be + # available from Day 2. + def update_staged_health_monitor_configuration( + self, health_monitor_id, + port=None, protocol=None, interval=None, retry=None, + timeout=None, + # path=None, http_status_code=None + ): + """Update Staged Health Monitor Configuration. + + :param string health_monitor_id: ID of Health Monitor + :param int port: Port of Health Monitor + :param string protocol: Protocol of Health Monitor + :param int interval: Interval of Health Monitor + :param int retry: Retry count of Health Monitor + :param int timeout: Timeout of Health Monitor + # :param string path: Path of Health Monitor + # :param string http_status_code: HTTP Status code of Health Monitor + :return: Health Monitor + """ + body = {} + if port is not None: + body["port"] = port + if protocol: + body["protocol"] = protocol + if interval: + body["interval"] = interval + if retry: + body["retry"] = retry + if timeout: + body["timeout"] = timeout + # if path: + # body["path"] = path + # if http_status_code: + # body["http_status_code"] = http_status_code + + health_monitor = _health_monitor.HealthMonitor() + return health_monitor.update_staged_configuration(self.session, + health_monitor_id, + **body) + + def cancel_staged_health_monitor_configuration(self, health_monitor_id): + """Delete Staged Health Monitor Configuration. + + :param string health_monitor_id: ID of Health Monitor + :return: None + """ + health_monitor = _health_monitor.HealthMonitor() + health_monitor.cancel_staged_configuration(self.session, + health_monitor_id) + + def policies(self, **params): + """List Policies.""" + return list(self._list(_policy.Policy, paginated=False, **params)) + + # NOTE(NaoShark): :param sorry_page_url: and :param certificate_id: and + # :param tls_security_policy_id: will be available from Day 2. + def create_policy(self, health_monitor_id, listener_id, + default_target_group_id, load_balancer_id, + name=None, description=None, tags=None, algorithm=None, + persistence=None, + # sorry_page_url=None, certificate_id=None, + # tls_security_policy_id=None + ): + """Create Policy. + + :param string health_monitor_id: Health Monitor ID of Policy + :param string listener_id: Listener ID of Policy + :param string default_target_group_id: Default Target Group ID + :param string load_balancer_id: Load Balancer ID + :param string name: Name of Policy + :param string description: Description of Policy + :param dict tags: Tags of Policy + :param string algorithm: Algorithm of Policy + :param string persistence: Persistence of Policy + # :param string sorry_page_url: Sorry page URL + # :param string certificate_id: Certificate ID + # :param string tls_security_policy_id: TLS Security Policy ID + :return: Policy + """ + body = { + "health_monitor_id": health_monitor_id, + "listener_id": listener_id, + "default_target_group_id": default_target_group_id, + "load_balancer_id": load_balancer_id, + } + if name: + body["name"] = name + if description: + body["description"] = description + if tags: + body["tags"] = tags + if algorithm: + body["algorithm"] = algorithm + if persistence: + body["persistence"] = persistence + # if sorry_page_url: + # body["sorry_page_url"] = sorry_page_url + # if certificate_id: + # body["certificate_id"] = certificate_id + # if tls_security_policy_id: + # body["tls_security_policy_id"] = tls_security_policy_id + return self._create(_policy.Policy, **body) + + def get_policy(self, policy_id, changes=None): + """Retrieve Policy Information. + + :param string policy_id: ID of Policy + :param bool changes: Whether or not to retrieve staged configuration + :return: Policy + """ + policy = _policy.Policy() + return policy.get_resource(self.session, policy_id, changes) + + def update_policy(self, policy_id, **params): + """Update Policy Attributes. + + :param string policy_id: ID of Policy + :attrs **params: Parameters for policy update. + + * string name: Name of Policy + * string description: Description of Policy + * dict tags: Tags of Policy + + :return: Policy + """ + return self._update(_policy.Policy, policy_id, **params) + + def delete_policy(self, policy_id, ignore_missing=False): + """Delete Policy. + + :param string policy_id: ID of Policy + :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 policy. + :return: None + """ + self._delete(_policy.Policy, policy_id, ignore_missing=ignore_missing) + + # NOTE(NaoShark): :param sorry_page_url: and :param certificate_id: and + # :param tls_security_policy_id: will be available from Day 2. + def create_staged_policy_configuration(self, policy_id, + algorithm=None, persistence=None, + # sorry_page_url=None, + # certificate_id=None, + health_monitor_id=None, + listener_id=None, + default_target_group_id=None, + # tls_security_policy_id=None + ): + """Create Staged Policy Configuration. + + :param string policy_id: ID of Policy + :param string algorithm: Algorithm of Policy + :param string persistence: Persistence of Policy + # :param string sorry_page_url: Sorry page URL + # :param string certificate_id: Certificate ID + :param string health_monitor_id: Health Monitor ID of Policy + :param string listener_id: Listener ID of Policy + :param string default_target_group_id: Default Target Group ID + # :param string tls_security_policy_id: TLS Security Policy ID + :return: Policy + """ + body = {} + if algorithm: + body["algorithm"] = algorithm + if persistence: + body["persistence"] = persistence + # if sorry_page_url: + # body["sorry_page_url"] = sorry_page_url + # if certificate_id: + # body["certificate_id"] = certificate_id + if health_monitor_id: + body["health_monitor_id"] = health_monitor_id + if listener_id: + body["listener_id"] = listener_id + if default_target_group_id: + body["default_target_group_id"] = default_target_group_id + # if tls_security_policy_id: + # body["tls_security_policy_id"] = tls_security_policy_id + + policy = _policy.Policy() + return policy.create_staged_configuration(self.session, + policy_id, **body) + + def get_staged_policy_configuration(self, policy_id): + """Retrieve Staged Policy Configuration. + + :param string policy_id: ID of Policy + :return: Policy + """ + return self._get(_policy.Policy, policy_id) + + # NOTE(NaoShark): :param sorry_page_url: and :param certificate_id: and + # :param tls_security_policy_id: will be available from Day 2. + + def update_staged_policy_configuration(self, policy_id, + algorithm=None, persistence=None, + # sorry_page_url=None, + # certificate_id=None, + health_monitor_id=None, + listener_id=None, + default_target_group_id=None, + # tls_security_policy_id=None + ): + """Update Staged Policy Configuration. + + :param string policy_id: ID of Policy + :param string algorithm: Algorithm of Policy + :param string persistence: Persistence of Policy + # :param string sorry_page_url: Sorry page URL + # :param string certificate_id: Certificate ID + :param string health_monitor_id: Health Monitor ID of Policy + :param string listener_id: Listener ID of Policy + :param string default_target_group_id: Default Target Group ID + # :param string tls_security_policy_id: TLS Security Policy ID + :return: Policy + """ + body = {} + if algorithm: + body["algorithm"] = algorithm + if persistence: + body["persistence"] = persistence + # if sorry_page_url: + # body["sorry_page_url"] = sorry_page_url + # if certificate_id: + # body["certificate_id"] = certificate_id + if health_monitor_id: + body["health_monitor_id"] = health_monitor_id + if listener_id: + body["listener_id"] = listener_id + if default_target_group_id: + body["default_target_group_id"] = default_target_group_id + # if tls_security_policy_id: + # body["tls_security_policy_id"] = tls_security_policy_id + + policy = _policy.Policy() + return policy.update_staged_configuration(self.session, + policy_id, **body) + + def cancel_staged_policy_configuration(self, policy_id): + """Delete Staged Policy Configuration. + + :param string policy_id: ID of Policy + :return: None + """ + policy = _policy.Policy() + policy.cancel_staged_configuration(self.session, policy_id) + + def routes(self, **params): + """List Routes.""" + return list(self._list(_route.Route, paginated=False, **params)) + + def create_route(self, destination_cidr, + next_hop_ip_address, load_balancer_id, + name=None, description=None, tags=None): + """Create Route. + + :param string destination_cidr: Destination CIDR of Route + :param string next_hop_ip_address: Next Hop IP Address of Route + :param string load_balancer_id: Load Balancer ID of Route + :param string name: Name of Route + :param string description: Description of Route + :param dict tags: Tags of Route + + :return: Route + """ + body = { + 'destination_cidr': destination_cidr, + 'next_hop_ip_address': next_hop_ip_address, + 'load_balancer_id': load_balancer_id + } + if name: + body["name"] = name + if description: + body["description"] = description + if tags: + body["tags"] = tags + return self._create(_route.Route, **body) + + def get_route(self, route_id, changes=None): + """Retrieve Route Information. + + :param string route_id: ID of Route + :param bool changes: Whether or not to retrieve staged configuration + :return: Route + """ + route = _route.Route() + return route.get_resource(self.session, route_id, changes) + + def update_route(self, route_id, **params): + """Update Route Attributes. + + :param string route_id: ID of Route + :attrs **params: Parameters for policy update. + + * string name: Name of Route + * string description: Description of Route + * dict tags: Tags of Route + + :return: Route + """ + return self._update(_route.Route, route_id, **params) + + def delete_route(self, route_id, ignore_missing=False): + """Delete Route. + + :param string route_id: ID of Route + :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 route. + :return: None + """ + self._delete(_route.Route, route_id, ignore_missing=ignore_missing) + + def create_staged_route_configuration( + self, route_id, next_hop_ip_address=None): + """Create Staged Route Configuration. + + :param string route_id: ID of Route + :param string next_hop_ip_address: Next Hop IP Address of Route + :return: Route + """ + body = {} + if next_hop_ip_address: + body["next_hop_ip_address"] = next_hop_ip_address + + route = _route.Route() + return route.create_staged_configuration(self.session, + route_id, **body) + + def get_staged_route_configuration(self, route_id): + """Retrieve Staged Route Configuration. + + :param string route_id: ID of Route + :return: Route + """ + return self._get(_route.Route, route_id) + + def update_staged_route_configuration( + self, route_id, next_hop_ip_address=None): + """Update Staged Route Configuration. + + :param string route_id: ID of Route + :param string next_hop_ip_address: Next Hop IP Address of Route + :return: Route + """ + body = {} + if next_hop_ip_address: + body["next_hop_ip_address"] = next_hop_ip_address + + route = _route.Route() + return route.update_staged_configuration(self.session, + route_id, **body) + + def cancel_staged_route_configuration(self, route_id): + """Delete Staged Route Configuration. + + :param string route_id: ID of Route + :return: None + """ + route = _route.Route() + route.cancel_staged_configuration(self.session, route_id) + + # NOTE(NaoShark): The following features will be available from Day 2 + # (rules, create_rule, get_rule, update_rule, delete_rule, + # create_staged_rule_configuration, get_staged_rule_configuration, + # update_staged_rule_configuration, cancel_staged_rule_configuration) + ''' + def rules(self, **params): + """List Rules.""" + return list(self._list(_rule.Rule, paginated=False, **params)) + + def create_rule(self, priority, target_group_id, policy_id, conditions, + name=None, description=None, tags=None): + """Create Rule. + + :param string priority: Priority of Rule + :param string target_group_id: Target group ID of Rule + :param string policy_id: Policy ID of Rule + :param string conditions: Condition IDs of Rule + :param string name: Name of Rule + :param string description: Description of Rule + :param dict tags: Tags of Rule + :return: Rule + """ + body = { + 'priority': priority, + 'target_group_id': target_group_id, + 'policy_id': policy_id, + 'conditions': conditions + } + if name: + body["name"] = name + if description: + body["description"] = description + if tags: + body["tags"] = tags + return self._create(_rule.Rule, **body) + + def get_rule(self, rule_id, changes=None): + """Retrieve Rule Information. + + :param string rule_id: ID of Rule + :param bool changes: Whether or not to retrieve staged configuration + :return: Rule + """ + rule = _rule.Rule() + return rule.get_resource(self.session, rule_id, changes) + + def update_rule(self, rule_id, name=None, description=None, tags=None): + """Update Rule Attributes. + + :param string rule_id: ID of Rule + :param string name: Name of Rule + :param string description: Description of Rule + :param dict tags: Tags of Rule + :return: Rule + """ + body = {} + if name: + body["name"] = name + if description: + body["description"] = description + if tags: + body["tags"] = tags + return self._update(_rule.Rule, rule_id, **body) + + def delete_rule(self, rule_id, ignore_missing=False): + """Delete Rule. + + :param string rule_id: ID of Rule + :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 rule. + :return: None + """ + self._delete(_rule.Rule, rule_id, ignore_missing=ignore_missing) + + def create_staged_rule_configuration( + self, rule_id, + priority=None, target_group_id=None, conditions=None): + """Create Staged Rule Configuration. + + :param string rule_id: ID of Rule + :param string priority: Priority of Rule + :param string target_group_id: Target Group ID of Rule + :param string conditions: Conditions of Rule + :return: Rule + """ + body = {} + if priority: + body["priority"] = priority + if target_group_id: + body["target_group_id"] = target_group_id + if conditions: + body["conditions"] = conditions + + rule = _rule.Rule() + return rule.create_staged_configuration(self.session, rule_id, **body) + + def get_staged_rule_configuration(self, rule_id): + """Retrieve Staged Rule Configuration. + + :param string rule_id: ID of Rule + :return: Rule + """ + return self._get(_rule.Rule, rule_id) + + def update_staged_rule_configuration( + self, rule_id, + priority=None, target_group_id=None, conditions=None): + """Create Staged Rule Configuration. + + :param string rule_id: ID of Rule + :param string priority: Priority of Rule + :param string target_group_id: Target Group ID of Rule + :param string conditions: Conditions of Rule + :return: Rule + """ + body = {} + if priority: + body["priority"] = priority + if target_group_id: + body["target_group_id"] = target_group_id + if conditions: + body["conditions"] = conditions + + rule = _rule.Rule() + return rule.update_staged_configuration(self.session, rule_id, **body) + + def cancel_staged_rule_configuration(self, rule_id): + """Delete Staged Rule Configuration. + + :param string rule_id: ID of Rule + :return: None + """ + rule = _rule.Rule() + rule.cancel_staged_configuration(self.session, rule_id) + ''' + + def operations(self, **params): + """List operations.""" + return list(self._list( + _operation.Operation, paginated=False, **params)) + + def get_operation(self, operation_id): + """Retrieve operation. + + :param string operation_id: ID of specified operation. + :return: Operation + """ + return self._get(_operation.Operation, operation_id) + + # NOTE(NaoShark): The following features will be available from Day 2 + # (tls_security_policies, get_tls_security_policy) + ''' + def tls_security_policies(self, **params): + """List TLS Security Policies.""" + return list(self._list( + _tls_security_policy.TLSSecurityPolicy, paginated=False, **params)) + + def get_tls_security_policy(self, tls_security_policy_id): + """Retrieve TLS Security Policy Information. + + :param string tls_security_policy_id: ID of TLS Security Policy + :return: TLS Security Policy + """ + return self._get( + _tls_security_policy.TLSSecurityPolicy, tls_security_policy_id) + ''' diff --git a/ecl/mvna/v1/base.py b/ecl/mvna/v1/base.py new file mode 100644 index 0000000..4ed140b --- /dev/null +++ b/ecl/mvna/v1/base.py @@ -0,0 +1,47 @@ +from ecl import resource2 + + +class MVNABaseResource(resource2.Resource): + + def get_resource(self, session, resource_id, changes=None): + if changes is not None and type(changes) is bool: + uri = self.base_path + '/%s?changes=%s' % \ + (resource_id, str(changes).lower()) + else: + uri = self.base_path + '/%s' % resource_id + resp = session.get(uri, endpoint_filter=self.service) + self._translate_response(resp, has_body=True) + return self + + def create_staged_configuration(self, session, resource_id, **body): + uri = self.base_path + '/%s/staged' % resource_id + resp = session.post(uri, endpoint_filter=self.service, + json={self.resource_key: body}) + self._translate_response(resp, has_body=True) + return self + + def update_staged_configuration(self, session, resource_id, **body): + uri = self.base_path + '/%s/staged' % resource_id + resp = session.patch(uri, endpoint_filter=self.service, + json={self.resource_key: body}) + self._translate_response(resp, has_body=True) + return self + + def cancel_staged_configuration(self, session, resource_id): + uri = self.base_path + '/%s/staged' % resource_id + resp = session.delete(uri, endpoint_filter=self.service) + self._translate_response(resp, has_body=False) + return self + + +class MVNAQueryParameters(resource2.QueryParameters): + def _transpose(self, query): + result = {} + for key, value in self._mapping.items(): + if key in query: + normalized = str(query[key]).lower() + if normalized == "true" or normalized == "false": + result[value] = normalized + else: + result[value] = query[key] + return result diff --git a/ecl/mvna/v1/certificate.py b/ecl/mvna/v1/certificate.py new file mode 100644 index 0000000..93a9996 --- /dev/null +++ b/ecl/mvna/v1/certificate.py @@ -0,0 +1,53 @@ +from . import base + +from ecl import resource2 +from ecl.mvna import mvna_service + + +class Certificate(resource2.Resource): + resource_key = "certificate" + resources_key = "certificates" + service = mvna_service.MVNAService("v1.0") + base_path = '/' + service.version + '/certificates' + + _query_mapping = base.MVNAQueryParameters( + "id", + "name", + "description", + "tenant_id", + "ca_cert_status", + "ssl_key_status", + "ssl_cert_status" + ) + + # Capabilities + allow_list = True + allow_get = True + allow_create = True + allow_update = True + allow_delete = True + patch_update = True + + # Properties + #: It identifies connection resource uniquely + id = resource2.Body('id') + #: Name of certificate + name = resource2.Body('name') + #: Description of certificate + description = resource2.Body('description') + #: Tags of certificate + tags = resource2.Body('tags') + #: Tenant ID + tenant_id = resource2.Body('tenant_id') + #: SSL Key + ssl_key = resource2.Body('ssl_key') + #: SSL Cert + ssl_cert = resource2.Body('ssl_cert') + #: Ca Cert + ca_cert = resource2.Body('ca_cert') + + def upload(self, session, resource_id, **body): + uri = self.base_path + '/%s/files' % resource_id + resp = session.post(uri, endpoint_filter=self.service, json=body) + self._translate_response(resp, has_body=False) + return self diff --git a/ecl/mvna/v1/health_monitor.py b/ecl/mvna/v1/health_monitor.py new file mode 100644 index 0000000..5ec6e48 --- /dev/null +++ b/ecl/mvna/v1/health_monitor.py @@ -0,0 +1,78 @@ +from . import base + +from ecl import resource2 +from ecl.mvna import mvna_service + + +class HealthMonitor(base.MVNABaseResource): + resource_key = "health_monitor" + resources_key = "health_monitors" + service = mvna_service.MVNAService("v1.0") + base_path = '/' + service.version + '/health_monitors' + + # NOTE(NaoShark): :param path: and :param http_status_code: will be + # available from Day 2. + _query_mapping = base.MVNAQueryParameters( + "id", + "name", + "description", + "configuration_status", + "operation_status", + "port", + "protocol", + "interval", + "retry", + "timeout", + # "path", + # "http_status_code", + "load_balancer_id", + "tenant_id" + ) + + # Capabilities + allow_list = True + allow_get = True + allow_create = True + allow_update = True + allow_delete = True + patch_update = True + + # Properties + #: It identifies connection resource uniquely + id = resource2.Body('id') + #: Name of health monitor + name = resource2.Body('name') + #: Description of health monitor + description = resource2.Body('description') + #: Tags of health monitor + tags = resource2.Body('tags') + #: Configuration status of health monitor + configuration_status = resource2.Body('configuration_status') + #: Operation status of health monitor + operation_status = resource2.Body('operation_status') + #: Port of health monitor + port = resource2.Body('port') + #: Protocol of health monitor + protocol = resource2.Body('protocol') + #: Interval of health monitor + interval = resource2.Body('interval') + #: Retry count of health monitor + retry = resource2.Body('retry') + #: Timeout of health monitor + timeout = resource2.Body('timeout') + + # NOTE(NaoShark): :param path: and :param http_status_code: will be + # available from Day 2. + #: Path of health monitor + # path = resource2.Body('path') + #: HTTP status code of health monitor + # http_status_code = resource2.Body('http_status_code') + + #: Load balancer ID + load_balancer_id = resource2.Body('load_balancer_id') + #: Tenant ID of health monitor + tenant_id = resource2.Body('tenant_id') + #: Current configuration of health monitor + current = resource2.Body('current') + #: Staged configuration of health monitor + staged = resource2.Body('staged') diff --git a/ecl/mvna/v1/listener.py b/ecl/mvna/v1/listener.py new file mode 100644 index 0000000..9e0e4c1 --- /dev/null +++ b/ecl/mvna/v1/listener.py @@ -0,0 +1,60 @@ +from . import base + +from ecl import resource2 +from ecl.mvna import mvna_service + + +class Listener(base.MVNABaseResource): + resource_key = "listener" + resources_key = "listeners" + service = mvna_service.MVNAService("v1.0") + base_path = '/' + service.version + '/listeners' + + _query_mapping = base.MVNAQueryParameters( + "id", + "name", + "description", + "configuration_status", + "operation_status", + "ip_address", + "port", + "protocol", + "load_balancer_id", + "tenant_id" + ) + + # Capabilities + allow_list = True + allow_get = True + allow_create = True + allow_update = True + allow_delete = True + patch_update = True + + # Properties + #: It identifies connection resource uniquely + id = resource2.Body('id') + #: Name of listener + name = resource2.Body('name') + #: Description of listener + description = resource2.Body('description') + #: Tags of listener + tags = resource2.Body('tags') + #: Configuration status of listener + configuration_status = resource2.Body('configuration_status') + #: Operation status of listener + operation_status = resource2.Body('operation_status') + #: IP Address of listener + ip_address = resource2.Body('ip_address') + #: Port of listener + port = resource2.Body('port') + #: Protocol of listener + protocol = resource2.Body('protocol') + #: Load balancer ID of listener + load_balancer_id = resource2.Body('load_balancer_id') + #: Tenant ID of listener + tenant_id = resource2.Body('tenant_id') + #: Current configuration of listener + current = resource2.Body('current') + #: Staged configuration of listener + staged = resource2.Body('staged') diff --git a/ecl/mvna/v1/load_balancer.py b/ecl/mvna/v1/load_balancer.py new file mode 100644 index 0000000..e5a2438 --- /dev/null +++ b/ecl/mvna/v1/load_balancer.py @@ -0,0 +1,108 @@ +from . import base + +from ecl import exceptions +from ecl import resource2 +from ecl.mvna import mvna_service + + +class LoadBalancer(base.MVNABaseResource): + resource_key = "load_balancer" + resources_key = "load_balancers" + service = mvna_service.MVNAService("v1.0") + base_path = '/' + service.version + '/load_balancers' + + _query_mapping = base.MVNAQueryParameters( + "id", + "name", + "description", + "configuration_status", + "monitoring_status", + "operation_status", + "primary_availability_zone", + "secondary_availability_zone", + "active_availability_zone", + "revision", + "plan_id", + "tenant_id" + ) + + # Capabilities + allow_list = True + allow_get = True + allow_create = True + allow_update = True + allow_delete = True + patch_update = True + + # Properties + #: It identifies connection resource uniquely + id = resource2.Body('id') + #: Name of load balancer + name = resource2.Body('name') + #: Description of load balancer + description = resource2.Body('description') + #: Tags of load balancer + tags = resource2.Body('tags') + #: Configuration status of load balancer + configuration_status = resource2.Body('configuration_status') + #: Monitoring status of load balancer + monitoring_status = resource2.Body('monitoring_status') + #: Operation status of load balancer + operation_status = resource2.Body('operation_status') + #: Primary availability zone of load balancer + primary_availability_zone = resource2.Body('primary_availability_zone') + #: Secondary availability zone of load balancer + secondary_availability_zone = resource2.Body('secondary_availability_zone') + #: Active availability zone of load balancer + active_availability_zone = resource2.Body('active_availability_zone') + #: Revision of load balancer + revision = resource2.Body('revision') + #: Plan ID of load balancer + plan_id = resource2.Body('plan_id') + #: Plan name of load balancer + plan_name = resource2.Body('plan_name') + #: Tenant ID of load balancer + tenant_id = resource2.Body('tenant_id') + + # NOTE(NaoShark): :param syslog_servers: will be available from Day 2. + #: Syslog servers of load balancer + # syslog_servers = resource2.Body('syslog_servers') + + #: Interfaces of load balancer + interfaces = resource2.Body('interfaces') + #: Current configuration of load balancer + current = resource2.Body('current') + #: Staged configuration of load balancer + staged = resource2.Body('staged') + + def delete_resource(self, session, resource_id, x_mvna_request_id=None, + ignore_missing=False): + uri = self.base_path + '/%s' % resource_id + + try: + if x_mvna_request_id: + resp = session.delete( + uri, endpoint_filter=self.service, + headers={"X-MVNA-Request-Id": x_mvna_request_id}) + else: + resp = session.delete(uri, endpoint_filter=self.service) + except exceptions.NotFoundException: + if ignore_missing: + return None + raise exceptions.ResourceNotFound( + message="No %s found for %s" % + (self.__class__.__name__, resource_id)) + + self._translate_response(resp, has_body=False) + return self + + def action(self, session, resource_id, x_mvna_request_id=None, **body): + uri = self.base_path + '/%s/action' % resource_id + if x_mvna_request_id: + resp = session.post( + uri, endpoint_filter=self.service, + headers={"X-MVNA-Request-Id": x_mvna_request_id}, json=body) + else: + resp = session.post(uri, endpoint_filter=self.service, json=body) + self._translate_response(resp, has_body=False) + return self diff --git a/ecl/mvna/v1/maintenance.py b/ecl/mvna/v1/maintenance.py new file mode 100644 index 0000000..4a308a1 --- /dev/null +++ b/ecl/mvna/v1/maintenance.py @@ -0,0 +1,50 @@ +from . import base + +from ecl import resource2 +from ecl.mvna import mvna_service + + +class Maintenance(resource2.Resource): + resource_key = "maintenance" + resources_key = "maintenances" + service = mvna_service.MVNAService("v1.0") + base_path = '/' + service.version + '/maintenances' + + _query_mapping = base.MVNAQueryParameters( + "id", + "name", + "description", + "href", + "current_revision", + "next_revision", + "applicable", + "latest" + ) + + # Capabilities + allow_list = True + allow_get = True + allow_create = False + allow_update = False + allow_delete = False + patch_update = False + + # Properties + #: It identifies connection resource uniquely + id = resource2.Body('id') + #: Name of maintenance + name = resource2.Body('name') + #: Description of maintenance + description = resource2.Body('description') + #: href of maintenance + href = resource2.Body('href') + #: Publish datetime of maintenance + publish_datetime = resource2.Body('publish_datetime') + #: Limit datetime of maintenance + limit_datetime = resource2.Body('limit_datetime') + #: Current revision of maintenance + current_revision = resource2.Body('current_revision') + #: Next revision of maintenance + next_revision = resource2.Body('next_revision') + #: Applicable of maintenance + applicable = resource2.Body('applicable') diff --git a/ecl/mvna/v1/operation.py b/ecl/mvna/v1/operation.py new file mode 100755 index 0000000..88fcd0f --- /dev/null +++ b/ecl/mvna/v1/operation.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +from . import base + +from ecl import resource2 +from ecl.mvna import mvna_service + +class Operation(resource2.Resource): + resource_key = "operation" + resources_key = "operations" + service = mvna_service.MVNAService("v1.0") + base_path = '/' + service.version + '/operations' + + _query_mapping = base.MVNAQueryParameters( + "id", + "resource_id", + "resource_type", + "request_id", + "request_type", + "status", + "tenant_id", + "no_deleted", + "latest" + ) + + # Capabilities + allow_list = True + allow_get = True + + # Properties + #: ID of network appliance's operation + id = resource2.Body('id') + #: Target load balancer id of operation. + resource_id = resource2.Body('resource_id') + #: resource type of operation. + resource_type = resource2.Body('resource_type') + #: Request ID of operation. + request_id = resource2.Body('request_id') + #: A string representation of the request type. + request_types = resource2.Body('request_types') + #: Request body(JSON String) of operation. + request_body = resource2.Body('request_body') + #: Status of operation. + status = resource2.Body('status') + #: Reception datetime of operation. + reception_datetime = resource2.Body('reception_datetime') + #: Commit datetime of operation. + commit_datetime = resource2.Body('commit_datetime') + #: Warning of operation. + warning = resource2.Body('warning') + #: Error of operation. + error = resource2.Body('error') + #: Tenant ID of operation. + tenant_id = resource2.Body('tenant_id') diff --git a/ecl/mvna/v1/plan.py b/ecl/mvna/v1/plan.py new file mode 100644 index 0000000..34fac48 --- /dev/null +++ b/ecl/mvna/v1/plan.py @@ -0,0 +1,76 @@ +from . import base + +from ecl import resource2 +from ecl.mvna import mvna_service + + +class Plan(resource2.Resource): + resource_key = "plan" + resources_key = "plans" + service = mvna_service.MVNAService("v1.0") + base_path = '/' + service.version + '/plans' + + # NOTE(NaoShark): :param max_number_of_rules: and :param certificate_id: + # and :param max_number_of_conditions: will be available from Day 2. + _query_mapping = base.MVNAQueryParameters( + "id", + "name", + "description", + "bandwidth", + "redundancy", + "max_number_of_interfaces", + "max_number_of_health_monitors", + "max_number_of_listeners", + "max_number_of_policies", + "max_number_of_routes", + "max_number_of_target_groups", + # "max_number_of_rules", + # "max_number_of_conditions", + "max_number_of_members", + "enabled" + ) + + # Capabilities + allow_list = True + allow_get = True + allow_create = False + allow_update = False + allow_delete = False + patch_update = False + + # Properties + #: It identifies connection resource uniquely + id = resource2.Body('id') + #: Name of plan + name = resource2.Body('name') + #: Description of plan + description = resource2.Body('description') + #: Bandwidth of plan + bandwidth = resource2.Body('bandwidth') + #: Redundancy of plan + redundancy = resource2.Body('redundancy') + #: Max number of interfaces + max_number_of_interfaces = resource2.Body('max_number_of_interfaces') + #: Max number of health monitors + max_number_of_health_monitors = \ + resource2.Body('max_number_of_health_monitors') + #: Max number of listeners + max_number_of_listeners = resource2.Body('max_number_of_listeners') + #: Max number of policies + max_number_of_policies = resource2.Body('max_number_of_policies') + #: Max numbers of routes + max_number_of_routes = resource2.Body('max_number_of_routes') + #: Max number of target groups + max_number_of_target_groups = resource2.Body('max_number_of_target_groups') + + # NOTE(NaoShark): :param max_number_of_rules: and :param certificate_id: + # and :param max_number_of_conditions: will be available from Day 2. + #: Max number of rules + # max_number_of_rules = resource2.Body('max_number_of_rules') + #: Max number of conditions + # max_number_of_conditions = resource2.Body('max_number_of_conditions') + + #: Max number of members + max_number_of_members = resource2.Body('max_number_of_members') + #: Enabled or disabled + enabled = resource2.Body('enabled') diff --git a/ecl/mvna/v1/policy.py b/ecl/mvna/v1/policy.py new file mode 100644 index 0000000..8eb6639 --- /dev/null +++ b/ecl/mvna/v1/policy.py @@ -0,0 +1,81 @@ +from . import base + +from ecl import resource2 +from ecl.mvna import mvna_service + + +class Policy(base.MVNABaseResource): + resource_key = "policy" + resources_key = "policies" + service = mvna_service.MVNAService("v1.0") + base_path = '/' + service.version + '/policies' + + # NOTE(NaoShark): :param sorry_page_url: and :param certificate_id: and + # :param tls_security_policy_id: will be available from Day 2. + _query_mapping = base.MVNAQueryParameters( + "id", + "name", + "description", + "configuration_status", + "operation_status", + "algorithm", + "persistence", + # "sorry_page_url", + # "certificate_id", + "health_monitor_id", + "listener_id", + "default_target_group_id", + # "tls_security_policy_id", + "load_balancer_id", + "tenant_id" + ) + + # Capabilities + allow_list = True + allow_get = True + allow_create = True + allow_update = True + allow_delete = True + patch_update = True + + # Properties + #: It identifies connection resource uniquely + id = resource2.Body('id') + #: Name of policy + name = resource2.Body('name') + #: Description of policy + description = resource2.Body('description') + #: Tags of policy + tags = resource2.Body('tags') + #: Configuration status of policy + configuration_status = resource2.Body('configuration_status') + #: Operation status of policy + operation_status = resource2.Body('operation_status') + #: Algorithm of policy + algorithm = resource2.Body('algorithm') + #: persistence of policy + persistence = resource2.Body('persistence') + + # NOTE(NaoShark): :param sorry_page_url: and :param certificate_id: and + # :param tls_security_policy_id: will be available from Day 2. + #: Sorry page URL of policy + # sorry_page_url = resource2.Body('sorry_page_url') + #: Certificate ID of policy + # certificate_id = resource2.Body('certificate_id') + #: TLS security policy ID of policy + # tls_security_policy_id = resource2.Body('tls_security_policy_id') + + #: Health monitor ID of policy + health_monitor_id = resource2.Body('health_monitor_id') + #: Listener ID of policy + listener_id = resource2.Body('listener_id') + #: Default target group ID of policy + default_target_group_id = resource2.Body('default_target_group_id') + #: Load balancer ID of policy + load_balancer_id = resource2.Body('load_balancer_id') + #: Tenant ID of policy + tenant_id = resource2.Body('tenant_id') + #: Current configuration of policy + current = resource2.Body('current') + #: Staged configuration of policy + staged = resource2.Body('staged') diff --git a/ecl/mvna/v1/route.py b/ecl/mvna/v1/route.py new file mode 100644 index 0000000..2009fb3 --- /dev/null +++ b/ecl/mvna/v1/route.py @@ -0,0 +1,57 @@ +from . import base + +from ecl import resource2 +from ecl.mvna import mvna_service + + +class Route(base.MVNABaseResource): + resource_key = "route" + resources_key = "routes" + service = mvna_service.MVNAService("v1.0") + base_path = '/' + service.version + '/routes' + + _query_mapping = base.MVNAQueryParameters( + "id", + "name", + "description", + "configuration_status", + "operation_status", + "destination_cidr", + "next_hop_ip_address", + "load_balancer_id", + "tenant_id" + ) + + # Capabilities + allow_list = True + allow_get = True + allow_create = True + allow_update = True + allow_delete = True + patch_update = True + + # Properties + #: It identifies connection resource uniquely + id = resource2.Body('id') + #: Name of route + name = resource2.Body('name') + #: Description of route + description = resource2.Body('description') + #: Tags of route + tags = resource2.Body('tags') + #: Configuration status of route + configuration_status = resource2.Body('configuration_status') + #: Operation status of route + operation_status = resource2.Body('operation_status') + #: Destination cidr of route + destination_cidr = resource2.Body('destination_cidr') + #: Next hop ip address of route + next_hop_ip_address = resource2.Body('next_hop_ip_address') + #: Load balancer ID of route + load_balancer_id = resource2.Body('load_balancer_id') + #: Tenant ID of route + tenant_id = resource2.Body('tenant_id') + #: Current configuration of route + current = resource2.Body('current') + #: Staged configuration of route + staged = resource2.Body('staged') diff --git a/ecl/mvna/v1/rule.py b/ecl/mvna/v1/rule.py new file mode 100644 index 0000000..3f42b7f --- /dev/null +++ b/ecl/mvna/v1/rule.py @@ -0,0 +1,62 @@ +from . import base + +from ecl import resource2 +from ecl.mvna import mvna_service + + +class Rule(base.MVNABaseResource): + resource_key = "rule" + resources_key = "rules" + service = mvna_service.MVNAService("v1.0") + base_path = '/' + service.version + '/rules' + + _query_mapping = base.MVNAQueryParameters( + "id", + "name", + "description", + "configuration_status", + "operation_status", + "priority", + "target_group_id", + "policy_id", + "load_balancer_id", + "tenant_id" + ) + + # Capabilities + allow_list = True + allow_get = True + allow_create = True + allow_update = True + allow_delete = True + patch_update = True + + # Properties + #: It identifies connection resource uniquely + id = resource2.Body('id') + #: Name of rule + name = resource2.Body('name') + #: Description of rule + description = resource2.Body('description') + #: Tags of rule + tags = resource2.Body('tags') + #: Configuration status of rule + configuration_status = resource2.Body('configuration_status') + #: Operation status of rule + operation_status = resource2.Body('operation_status') + #: Priority of rule + priority = resource2.Body('priority') + #: Target group ID of rule + target_group_id = resource2.Body('target_group_id') + #: Policy ID of rule + policy_id = resource2.Body('policy_id') + #: Load balancer ID of rule + load_balancer_id = resource2.Body('load_balancer_id') + #: Tenant ID of rule + tenant_id = resource2.Body('tenant_id') + #: Conditions of rule + conditions = resource2.Body('conditions') + #: Current configuration of rule + current = resource2.Body('current') + #: Staged configuration of rule + staged = resource2.Body('staged') diff --git a/ecl/mvna/v1/target_group.py b/ecl/mvna/v1/target_group.py new file mode 100644 index 0000000..fe7ee25 --- /dev/null +++ b/ecl/mvna/v1/target_group.py @@ -0,0 +1,53 @@ +from . import base + +from ecl import resource2 +from ecl.mvna import mvna_service + + +class TargetGroup(base.MVNABaseResource): + resource_key = "target_group" + resources_key = "target_groups" + service = mvna_service.MVNAService("v1.0") + base_path = '/' + service.version + '/target_groups' + + _query_mapping = base.MVNAQueryParameters( + "id", + "name", + "description", + "configuration_status", + "operation_status", + "load_balancer_id", + "tenant_id" + ) + + # Capabilities + allow_list = True + allow_get = True + allow_create = True + allow_update = True + allow_delete = True + patch_update = True + + # Properties + #: It identifies connection resource uniquely + id = resource2.Body('id') + #: Name of target group + name = resource2.Body('name') + #: Description of target group + description = resource2.Body('description') + #: Tags of target group + tags = resource2.Body('tags') + #: Configuration status of target group + configuration_status = resource2.Body('configuration_status') + #: Operation status of target group + operation_status = resource2.Body('operation_status') + #: Load balancer ID of target group + load_balancer_id = resource2.Body('load_balancer_id') + #: Tenant ID of target group + tenant_id = resource2.Body('tenant_id') + #: Members of target group + members = resource2.Body('members') + #: Current of target group + current = resource2.Body('current') + #: Staged of target group + staged = resource2.Body('staged') diff --git a/ecl/mvna/v1/tls_security_policy.py b/ecl/mvna/v1/tls_security_policy.py new file mode 100644 index 0000000..4a59f26 --- /dev/null +++ b/ecl/mvna/v1/tls_security_policy.py @@ -0,0 +1,37 @@ +from . import base + +from ecl import resource2 +from ecl.mvna import mvna_service + + +class TLSSecurityPolicy(resource2.Resource): + resource_key = "tls_security_policy" + resources_key = "tls_security_policies" + service = mvna_service.MVNAService("v1.0") + base_path = '/' + service.version + '/tls_security_policies' + + _query_mapping = base.MVNAQueryParameters( + "id", "name", "description", "default", + ) + + # Capabilities + allow_list = True + allow_get = True + allow_create = False + allow_update = False + allow_delete = False + patch_update = False + + # Properties + #: It identifies connection resource uniquely + id = resource2.Body('id') + #: Name of tls security policy + name = resource2.Body('name') + #: Description of tls security policy + description = resource2.Body('description') + #: Default of tls security policy + default = resource2.Body('default') + #: TLS protocols of tls security policy + tls_protocols = resource2.Body('tls_protocols') + #: Cipher suites of tls security policy + cipher_suites = resource2.Body('cipher_suites') 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 15cd934..683c087 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,9 +75,9 @@ ## 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 _logger = logging.getLogger(__name__) @@ -110,9 +106,7 @@ def __init__(self, plugins=None): self._add_service(identity_service.IdentityService(version="v3")) 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(sss_service.SssService(version="v2")) self._add_service( orchestration_service.OrchestrationService(version="v1")) self._add_service( @@ -136,11 +130,11 @@ 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( version="v1")) + self._add_service(mvna_service.MVNAService(version="v1")) # NOTE: The Metric service is not added here as it currently # only retrieves the /capabilities API. diff --git a/ecl/sss/sss_service.py b/ecl/sss/sss_service.py index e25fbf6..dcbb0f9 100755 --- a/ecl/sss/sss_service.py +++ b/ecl/sss/sss_service.py @@ -16,9 +16,9 @@ class SssService(service_filter.ServiceFilter): """The SSS service.""" - valid_versions = [service_filter.ValidVersion('v1')] + valid_versions = [service_filter.ValidVersion('v2')] def __init__(self, version=None): """Create a SSS service.""" - super(SssService, self).__init__(service_type='sss', + super(SssService, self).__init__(service_type='sssv2', version=version) \ No newline at end of file diff --git a/ecl/object_store/__init__.py b/ecl/sss/v2/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from ecl/object_store/__init__.py rename to ecl/sss/v2/__init__.py diff --git a/ecl/sss/v2/_proxy.py b/ecl/sss/v2/_proxy.py new file mode 100644 index 0000000..b723370 --- /dev/null +++ b/ecl/sss/v2/_proxy.py @@ -0,0 +1,545 @@ +# 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.sss.v2 import user as _user +from ecl.sss.v2 import tenant as _tenant +from ecl.sss.v2 import api_key as _api_key +from ecl.sss.v2 import channel as _channel +from ecl.sss.v2 import contract as _contract +from ecl.sss.v2 import iam_group as _iam_group +from ecl.sss.v2 import iam_role as _iam_role +from ecl.sss.v2 import workspace as _workspace +from ecl import proxy2 + + +class Proxy(proxy2.BaseProxy): + def users(self): + """ + List users in the designated contract. + + :return: A generator of user instances. + :rtype: :class:`~ecl.sss.v2.user.User` + """ + return list(self._list(_user.User, paginated=False)) + + def find_user(self, user_id, ignore_missing=False): + """ + Find a user. Get user information such as login id, email, apikey, etc. + + :param user_id: ID of a user + :param ignore_missing: When set to ``True``, None will be returned when + attempting to find a nonexistent resource. + :return: One :class:`~ecl.sss.v2.user.User` or None + """ + return self._find(_user.User, user_id, + ignore_missing=ignore_missing) + + def get_user(self, user): + """ + Get user information such as login id, email, apikey, etc. + + :param user: ID of a user or a :class:`~ecl.sss.v2.user.User` instance. + :return: One :class:`~ecl.sss.v2.user.User` or + :class:`~ecl.exceptions.ResourceNotFound`when no + resource can be found. + """ + return self._get(_user.User, user) + + def create_user(self, login_id, mail_address, notify_password, + password=None): + """ + Create user in the designated contract. Only supser user (contract + owner user) allowed. + + :param login_id: Login id of new user. + :param mail_address: Mail address of new user. + :param notify_password: If this flag is set 'true', + notification email will be sent to new users email + :param password: Initial password of new user. + If this parameter is not designated, random initial password is + generated and applied to new user. + :return: The results of user creation + :rtype: :class:`~ecl.sss.v2.user.User` + """ + body = {} + body["login_id"] = login_id + body["mail_address"] = mail_address + body["notify_password"] = notify_password + if password: + body["password"] = password + return self._create(_user.User, **body) + + def update_user(self, user_id, login_id=None, mail_address=None, + new_password=None): + """ + Update user's informain. + + :param user_id: Specified user_id. + :param login_id: Login id of new user. + :param mail_address: Mail address of new user. + :param new_password: New password of the user. + :return: ``None`` + """ + body = {} + if login_id: + body["login_id"] = login_id + if mail_address: + body["mail_address"] = mail_address + if new_password: + body["new_password"] = new_password + user = _user.User() + return user.update(self.session, user_id, **body) + + def delete_user(self, user, ignore_missing=False): + """ + Delete user. Only supser user (contract owner user) allowed. Contract + owner user itself cannot be deleted + + :param user: Delete target user's user id. + :param ignore_missing: When set to ``False`` + :class:`~ecl.exceptions.ResourceNotFound` will be + raised when the user does not exist. + When set to ``True``, no exception will be set when + attempting to delete a nonexistent server + :return: ``None`` + """ + self._delete(_user.User, user, ignore_missing=ignore_missing) + + def tenants(self, **query): + """ + List tenants in the designated contract. + + :param kwargs \*\*query: Optional query parameters to be sent to limit + the resources being returned. + + :return: A generator of tenant instances. + :rtype: :class:`~ecl.sss.v2.tenant.Tenant` + """ + return list(self._list(_tenant.Tenant, paginated=False, **query)) + + def find_tenant(self, tenant_id, ignore_missing=False): + """ + Find a tenant. Get tenant information such as tenant name, etc. + + :param tenant_id: ID of a tenant + :param ignore_missing: When set to ``True``, None will be returned when + attempting to find a nonexistent resource. + :return: One :class:`~ecl.sss.v2.tenant.Tenant` or None + """ + return self._find(_tenant.Tenant, tenant_id, + ignore_missing=ignore_missing) + + def create_tenant(self, **attrs): + """ + Create new tenant in the designated contract. Only supser user + (contract owner user) allowed. + + :param attrs: Keyword arguments which will be used to create + a :class:`~ecl.sss.v2.tenant.Tenant`, + comprised of the properties on the Tenant class. + :return: The results of tenant creation + :rtype: :class:`~ecl.sss.v2.tenant.Tenant` + """ + return self._create(_tenant.Tenant, **attrs) + + def update_api_key(self, user_id): + """ + Update API key pair of target user. + + :param user_id: Change target user's user id. + :return: The attributes to update on the api_key represented by + ``Api_key``. + """ + key = _api_key.Api_key() + return key.update(session=self.session, user_id=user_id) + + def channels(self, get_contracts, **query): + """ + Getting lists of information about the own channel and end user channel + that own contract belongs. Only partner user allowed. + + :param get_contracts: The flag of whether getting contracts + (true or false(default)). + :return: A generator of channels instances. + :rtype: :class:`~ecl.sss.v2.channel.Channel` + """ + return list(self._list(_channel.Channel, paginated=False, + get_contracts=get_contracts, **query)) + + def create_contract(self, login_id, mail_address, channel_id, password=None, + external_reference_id=None, notify_password=None): + """ + Create contract in designated channel. Only partner user allowed. + + :param login_id: Login ID of new user. + :param mail_address: E-mail address of the user. + :param channel_id: The channel means the group to manage contracts. + The partner user will be given 2 channels. One is the channel that + contains own contract. The other is the channel that contains all + end user contracts which the partner user has. By executing the List + Channel API(For partner user only), + the user can get your (and enduser's) channel ID. + :param password: Password of the user. If the API user set this item as + blank, the system set initial random password automatically. + :param external_reference_id: By using this item, the partner API user + can associate optional string to the constract(e.g. The end user + management ID in the partner user's system). Note that this ID will + be NOT used to control the contract in ECL2.0 internal system. + If the item is set as blank, ECL 2.0 system set the end user's + contract ID automatically(e.g. econXXXXXXXX). + :param notify_password: Setting true or false(default is false). + This item designate whether the system should send to the login_ID + and Password with e-mail. + :return: :class:`~ecl.sss.v2.contract.Contract` + """ + body = {} + body["login_id"] = login_id + body["mail_address"] = mail_address + body["channel_id"] = channel_id + if password: + body["password"] = password + if external_reference_id: + body["external_reference_id"] = external_reference_id + if notify_password: + body["notify_password"] = notify_password + return self._create(_contract.Contract, **body) + + def contracts(self, channel_id, include_deleted="false"): + """ + List Contracts in the designated channel. Only partner user allowed. + + :param channel_id: Target channel_id under own contract. + :param include_deleted: Setting true or false(default is false) + (true : Include deleted contract/ false: Not include deleted contract. + :return: A generator of contracts instances. + :rtype: :class:`~ecl.sss.v2.contract.Contract` + """ + contract = _contract.Contract() + return list(contract.list(session=self.session, channel_id=channel_id, + include_deleted=include_deleted)) + + def delete_contract(self, contract_id, ignore_missing=False): + """ + Delete contract in designated channel. Only partner user allowed. + + :param contract_id: Contract ID of Delete target + :param ignore_missing: When set to ``False`` + :class:`~ecl.exceptions.ResourceNotFound` will be + raised when the user does not exist. + When set to ``True``, no exception will be set when + attempting to delete a nonexistent server + :return: ``None`` + """ + return self._delete(_contract.Contract, contract_id, + ignore_missing=ignore_missing) + + def get_contract(self, contract_id): + """ + Get the information of the designated contract. + + :param contract_id: The contract ID getting more information. + :return: One :class:`~ecl.sss.v2.contract.Contract` + """ + return self._get(_contract.Contract, contract_id) + + def get_monthly_billing_of_each_contract(self, contract_id, target_month, + target_contract_id): + """ + Get montly billing for each contract. Only partner user allowed. + + :param contract_id: Contract ID of this request. + :param target_month: Target billing month with YYYY-MM format + :param target_contract_id: Target contract ID + :return: + """ + bill_info = _contract.Contract() + return bill_info.get_monthly_billing_of_each_contract( + session=self.session, + contract_id=contract_id, target_month=target_month, + target_contract_id=target_contract_id + ) + + def iam_groups(self, contract_id): + """ + List iam groups by contract id. + + :param contract_id: Contract ID ( Default is the Contract ID of + API executing user ) . + :return: A list of iam groups. + :rtype: :class:`~ecl.sss.v2.iam_group.IAMGroup` + """ + iam_group = _iam_group.IAMGroup() + return list(iam_group.list(session=self.session, + contract_id=contract_id)) + + def create_iam_group(self, iam_group_name, contract_id=None, + description=None): + """ + Create iam group. + + :param iam_group_name: New IAM Group name. + Alphanumeric characters and @, -, ., _ can be used. + :param contract_id: Contract ID ( Default is the Contract ID of API + executing user ) . + :param description: Description of the IAM Group. + :return: :class:`~ecl.sss.v2.iam_group.IAMGroup` + """ + body = {} + body["iam_group_name"] = iam_group_name + if contract_id: + body["contract_id"] = contract_id + if description: + body["description"] = description + return self._create(_iam_group.IAMGroup, **body) + + def delete_iam_group(self, iam_group_id, ignore_missing=False): + """ + Delete iam group. + + :param iam_group_id: Group ID that you want to delete. + :param ignore_missing: When set to ``False`` + :class:`~ecl.exceptions.ResourceNotFound` will be + raised when the user does not exist. + When set to ``True``, no exception will be set when + attempting to delete a nonexistent server + :return: ``None`` + """ + return self._delete(_iam_group.IAMGroup, iam_group_id, + ignore_missing=ignore_missing) + + def assign_iam_role(self, iam_group_id, iam_role_id): + """ + Assignment of the IAM Role to the IAM Group. + + :param iam_group_id: IAM Group ID that assign to the Role. + :param iam_role_id: IAM Role ID that assign to the Group. + :return: :class:`~ecl.sss.v2.iam_group.IAMGroup` + """ + iam_group = _iam_group.IAMGroup() + return iam_group.assign_iam_role(session=self.session, + iam_group_id=iam_group_id, + iam_role_id=iam_role_id) + + def delete_assign_iam_role(self, iam_group_id, iam_role_id): + """ + Delete Assignment of the IAM Role to the IAM Group. + + :param iam_group_id: IAM Group ID. + :param iam_role_id: IAM Role ID. + :return: ``None`` + """ + iam_group = _iam_group.IAMGroup() + return iam_group.delete_assign_iam_role(session=self.session, + iam_group_id=iam_group_id, + iam_role_id=iam_role_id) + + def users_designated_iam_group(self, iam_group_id): + """ + List User list in the designated IAM Group ID. + + :param iam_group_id: IAM Group ID that you want to show user list. + :return: :class:`~ecl.sss.v2.iam_group.IAMGroup` + """ + iam_group = _iam_group.IAMGroup() + return iam_group.list_users(session=self.session, + iam_group_id=iam_group_id) + + def assign_user(self, iam_group_id, user_id): + """ + Assignment of the IAM User to the IAM Group. + + :param iam_group_id: IAM Group ID that assign to the User. + :param user_id: User ID that assign to the Group. + :return: :class:`~ecl.sss.v2.iam_group.IAMGroup` + """ + iam_group = _iam_group.IAMGroup() + return iam_group.assign_user(session=self.session, + iam_group_id=iam_group_id, + user_id=user_id) + + def delete_assign_user(self, iam_group_id, user_id): + """ + Delete Assignment of the User to the IAM Group. + + :param iam_group_id: IAM Group ID. + :param user_id: User ID. + :return: ``None`` + """ + iam_group = _iam_group.IAMGroup() + return iam_group.delete_assign_user(session=self.session, + iam_group_id=iam_group_id, + user_id=user_id) + + def iam_roles(self, contract_id): + """ + List IAM Role list in the designated contract. + + :param contract_id: Contract ID ( Default is the Contract ID of API + executing user ) . + :return: A list of iam groups. + :rtype: :class:`~ecl.sss.v2.iam_role.IAMRole` + """ + iam_role = _iam_role.IAMRole() + return list(iam_role.list(session=self.session, + contract_id=contract_id)) + + def get_iam_role(self, iam_role_id): + """ + Show a IAM Role's information. You can check a IAM Role's + name, ID and resources by executing this API. + + :param iam_role_id: IAM Role ID that you want to check information. + :return: :class:`~ecl.sss.v2.iam_role.IAMRole` + """ + return self._get(_iam_role.IAMRole, iam_role_id) + + def create_iam_role(self, iam_role_name, resources, contract_id=None, + description=None): + """ + Create IAM Role in the designated contract. Only supser user + (contract owner user) can use this API. + + :param iam_role_name: New IAM Role name. + Alphanumeric characters and @, -, ., _ can be used. + :param resources: Whitelist rules of API execution. + ( resources item is mandatory, but a user can define any rule by + using follow parameters. ) + :param contract_id: Contract ID ( Default is the Contract ID of API + executing user ). + :param description: Description of the IAM Role. + :return: :class:`~ecl.sss.v2.iam_group.IAMGroup` + """ + body = {} + body["iam_role_name"] = iam_role_name + body["resources"] = resources + if contract_id: + body["contract_id"] = contract_id + if description: + body["description"] = description + return self._create(_iam_role.IAMRole, **body) + + def delete_iam_role(self, iam_role_id, ignore_missing=False): + """ + Delete designated IAM Role. Only supser user (contract owner user) + can use this API. + + :param iam_role_id: IAM Role ID that you want to delete. + :return: ``None`` + """ + return self._delete(_iam_role.IAMRole, iam_role_id, + ignore_missing=ignore_missing) + + def create_workspace(self, workspace_name, description=None, contract_id=None): + """ + Create workspace in the designated contract. + + :param workspace_name: Workspace name. + :param description: Descriptions for this workspace. + :param contract_id: Contract ID for workspace creation. + :return: The results of workspace creation + :rtype: :class:`~ecl.sss.v2.workspace.Workspace` + """ + body = {} + body["workspace_name"] = workspace_name + if description: + body["description"] = description + if contract_id: + body["contract_id"] = contract_id + return self._create(_workspace.Workspace, **body) + + def get_workspace(self, workspace_id): + """ + Get information about a workspace. + + :param workspace_id: ID of the workspace. + :return: One :class:`~ecl.sss.v2.workspace.Workspace` + """ + return self._get(_workspace.Workspace, workspace_id) + + def workspaces(self, contract_id): + """ + Get list of workspace. Only workspaces for which the user has access + rights are output. + + :param contract_id: Contract ID( Default is the Contract ID of API + executing user. ). + :return: A generator of workspace instances. + :rtype: :class:`~ecl.sss.v2.workspace.Workspace` + """ + query = {} + if contract_id: + query = {'contract_id': contract_id} + return list(self._list(_workspace.Workspace, paginated=False, **query)) + + def delete_workspace(self, workspace_id, ignore_missing=False): + """ + Delete workspace. Only supser user (contract owner user) and partner + user allowed. If the user delete workspace, the all user's token who + has role to this workspace are expired even though 1 hour has not + passed. + + :param workspace_id: Delete target workspace's workspace id. + :param ignore_missing: When set to ``False`` + :class:`~ecl.exceptions.ResourceNotFound` will be + raised when the user does not exist. + When set to ``True``, no exception will be set when + attempting to delete a nonexistent server. + :return: ``None`` + """ + return self._delete(_workspace.Workspace, workspace_id, + ignore_missing=ignore_missing) + + def update_workspace(self, workspace_id, description): + """ + Updates the description for the designated workspace. + + :param workspace_id: The workspace id. + :param description: New description of the workspace. + :return: ``None`` + """ + body = {} + body["description"] = description + workspace = _workspace.Workspace() + return workspace.update(self.session, workspace_id, **body) + + def add_workspace_role_assignment(self, user_id, workspace_id): + """ + Add role between user and workspace.Contract owner user always have + role to all workspaces in the contract. Only supser user + (contract owner user) and partner user allowed. + + :param user_id: User's id of the role. + :param workspace_id: Add target workspace's workspace id. + :return: :class:`~ecl.sss.v2.workspace.Workspace` + """ + body = {} + body["user_id"] = user_id + body["workspace_id"] = workspace_id + workspace_role = _workspace.Workspace() + return workspace_role.add_workspace_role_assignment( + session=self.session, **body + ) + + def delete_workspace_role_assignment(self, workspace_id, user_id): + """ + Delete role between user and workspace. Contract owner user always have + role to all workspaces in the contract. Only supser user + (contract owner user) and partner user allowed. + + :param workspace_id: Delete target workspace's workspace id. + :param user_id: User's id of the role. + :return: ``None`` + """ + workspace_role = _workspace.Workspace() + return workspace_role.delete_workspace_role_assignment( + session=self.session, workspace_id=workspace_id, user_id=user_id + ) diff --git a/ecl/sss/v2/api_key.py b/ecl/sss/v2/api_key.py new file mode 100644 index 0000000..43358ab --- /dev/null +++ b/ecl/sss/v2/api_key.py @@ -0,0 +1,39 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from ecl.sss import sss_service +from ecl import resource2 + +class Api_key(resource2.Resource): + resource_key = None + resources_key = None + base_path = '/keys' + service = sss_service.SssService() + + # Capabilities + allow_update = True + + # Properties + #: User's id whose API key updated. + user_id = resource2.Body('user_id', alternate_id=True) + #: New API key(keystone username) + keystone_name = resource2.Body('keystone_name') + #: New API secret(keystone password) + keystone_password = resource2.Body('keystone_password') + #: Update status. 'Success' for successful update + status = resource2.Body('status') + + def update(self, session, user_id): + url = '/keys/%s' % user_id + resp = session.put(url, endpoint_filter=self.service) + self._translate_response(resp, has_body=True) + return self diff --git a/ecl/sss/v2/channel.py b/ecl/sss/v2/channel.py new file mode 100644 index 0000000..ff370da --- /dev/null +++ b/ecl/sss/v2/channel.py @@ -0,0 +1,50 @@ +# 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.sss import sss_service +from ecl import resource2 + +class Channel(resource2.Resource): + resource_key = None + resources_key = "channels" + base_path = "/channels?get_contracts=%(get_contracts)s" + service = sss_service.SssService() + + #Capabilities + allow_list = True + + #_query_mapping = resource2.QueryParameters("get_contracts") + + #Properties + #: Channel ID. + channel_id = resource2.Body("channel_id", alternate_id=True) + #: Channel name. + channel_name = resource2.Body("channel_name") + #: This item setting will relate to language setting of E-mail that will + #: send by ECL2.0. Please note that NOT related to user's display language + #: setting(That setting is rely on the user browser's language setting.) + language = resource2.Body("language") + #: Whether this channel_id is the partner management channel(true), or + #: not(false). + management_channel = resource2.Body("management_channel") + #: The parent channel ID means partner's channel ID that belongs the end + #: user. + parent_channel_id = resource2.Body("parent_channel_id") + #: List of contracts has two parameters: + #: contract_id: Contract ID. + #: status: The status of the contract(enable or deleted). + contracts = resource2.Body("contracts") + + def __init__(self, synchronized=False, **attrs): + super(Channel, self).__init__(synchronized=synchronized, **attrs) + if "get_contracts" in attrs: + attrs.pop("get_contracts") diff --git a/ecl/sss/v2/contract.py b/ecl/sss/v2/contract.py new file mode 100644 index 0000000..fd47938 --- /dev/null +++ b/ecl/sss/v2/contract.py @@ -0,0 +1,127 @@ +# 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.sss import sss_service +from ecl import resource2 + + +class Contract(resource2.Resource): + resource_key = None + resources_key = None + base_path = '/contracts' + service = sss_service.SssService() + + # Capabilities + allow_create = True + allow_get = True + allow_delete = True + allow_list = True + put_create = False + + # Properties + #: Contract ID. + contract_id = resource2.Body('contract_id', alternate_id=True) + #: Login ID of user. + login_id = resource2.Body('login_id') + #: E-mail address of the user. + mail_address = resource2.Body('mail_addresss') + #: Password of the user. If user set this item as blank, the system + #: set initial random password automatically. + password = resource2.Body('password') + #: By using this item, the partner API user can associate optional + #: string to the constract(e.g. The end user management ID in the + #: partner user's system). Note that this ID will be NOT used to + #: control the contract in ECL2.0 internal system. If the item is + #: set as blank, ECL 2.0 system set the end user's contract ID + #: automatically + external_reference_id = resource2.Body('external_reference_id') + #: Setting true or false(default is false). This item designate + #: whether the system should send to the login_ID and Password with + #: e-mail. + notify_password = resource2.Body('notify_password') + #: User id. format is ecid[0-9]{10}. + user_id = resource2.Body('user_id') + #: This user's API key for keystone authentication. + keystone_name = resource2.Body('keystone_name') + #: This user's API secret for keystone authentication. + keystone_password = resource2.Body('keystone_password') + #: Keystone address this user can use to get token for SSS API + #: request. + keystone_endpoint = resource2.Body('keystone_endpoint') + #: SSS endpoint recommended for user. + sss_endpoint = resource2.Body('sss_endpoint') + #: status + status = resource2.Body('status') + #: customer_name + customer_name = resource2.Body('customer_name') + #: This ID is equal to external_reference_id. + customer_number = resource2.Body('customer_number') + #: Channel name. + channel_name = resource2.Body('channel_name') + #: Channel ID of this contract. + channel_id = resource2.Body('channel_id') + #: Whether this channel_id is the partner management channel(true), + #: or not(false). + management_channel = resource2.Body('management_channel') + #: The owner user ID in the Contract + contract_owner_user_id = resource2.Body('contract_owner_user_id') + #: Start time of the contract + start_time = resource2.Body('start_time') + #: End time of the contract + end_time = resource2.Body('end_time') + #: Internal use(Login type) + login_integration = resource2.Body('login_integration') + #: Access point to use APIs in the decided region + sss_endpoint = resource2.Body('sss_endpoint') + #: keystone_endpoint + keystone_endpoint = resource2.Body('keystone_endpoint') + #: Internal use + company_code = resource2.Body('company_code') + #: Internal use + glass_customer_id = resource2.Body('glass_customer_id') + #: Internal use + glass_user_id = resource2.Body('glass_user_id') + #: The status of the acquired charge information (estimated: + #: undetermined / fixed: Committed) + charge_status = resource2.Body('charge_status') + #: Period of the acquired charge information(Start time) + cycle_start_time = resource2.Body('cycle_start_time') + #: Period of the acquired charge information(End time) + cycle_end_time = resource2.Body('cycle_end_time') + #: The detail of information + charge_data = resource2.Body('charge_data') + #: The designated contract ID by request's target_contract_id. + owner_contract_id = resource2.Body('owner_contract_id') + + def list(self, session, channel_id, include_deleted): + """List contracts by channel id""" + + url = self.base_path + '?channel_id=%s&include_deleted=%s' % ( + channel_id, include_deleted + ) + resp = session.get( + url, endpoint_filter=self.service + ) + self._translate_response(resp, has_body=True) + return self + + def get_monthly_billing_of_each_contract( + self, session, contract_id, target_month, target_contract_id + ): + """Get montly billing for each contract.""" + + url = self.base_path + "/%s/billing/%s/target_contract/%s" % ( + contract_id, target_month, target_contract_id + ) + resp = session.get(url, endpoint_filter=self.service) + self._translate_response(resp, has_body=True) + return self diff --git a/ecl/sss/v2/iam_group.py b/ecl/sss/v2/iam_group.py new file mode 100644 index 0000000..8666bbb --- /dev/null +++ b/ecl/sss/v2/iam_group.py @@ -0,0 +1,96 @@ +# 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.sss import sss_service +from ecl import resource2 + + +class IAMGroup(resource2.Resource): + resource_key = None + resources_key = 'iam_groups' + base_path = '/iam/groups' + + # Capabilities + allow_create = True + allow_delete = True + allow_list = True + allow_update = True + + # Properties + #: The IAM Group ID. + iam_group_id = resource2.Body('iam_group_id', alternate_id=True) + #: The IAM Group name. + iam_group_name = resource2.Body('iam_group_name') + #: Description of the IAM group. + description = resource2.Body('description') + #: IAM Role Object. + #: * iam_role_id: The IAM Role ID. + #: * iam_role_name: The IAM Role name. + iam_roles = resource2.Body('iam_roles') + #: The IAM Role ID. + iam_role_id = resource2.Body('iam_role_id') + #: The IAM Role name. + iam_role_name = resource2.Body('iam_role_name') + #: User ID that belongs in the designated IAM Group ID. + users = resource2.Body('users') + #: The User ID. + user_id = resource2.Body('user_id') + #: The contact ID that the IAM Group belongs. + contract_id = resource2.Body('contract_id') + + def list(self, session, contract_id): + """List iam groups by contract id""" + + url = self.base_path + '?contract_id=%s' % contract_id + resp = session.get(url, endpoint_filter=self.service) + self._translate_response(resp, has_body=True) + return self + + def assign_iam_role(self, session, iam_group_id, iam_role_id): + """Assignment of the IAM Role to the IAM Group.""" + + url = self.base_path + '/%s/roles/%s' % (iam_group_id, iam_role_id) + resp = session.put(url, endpoint_filter=self.service) + self._translate_response(resp, has_body=True) + return self + + def delete_assign_iam_role(self, session, iam_group_id, iam_role_id): + """Delete Assignment of the IAM Role to the IAM Group.""" + + url = self.base_path + '/%s/roles/%s' % (iam_group_id, iam_role_id) + resp = session.delete(url, endpoint_filter=self.service) + self._translate_response(resp, has_body=False) + return self + + def list_users(self, session, iam_group_id): + """Show User list in the designated IAM Group ID.""" + + url = self.base_path + '/%s/users' % iam_group_id + resp = session.get(url, endpoint_filter=self.service) + self._translate_response(resp, has_body=True) + return self + + def assign_user(self, session, iam_group_id, user_id): + """Assignment of the IAM User to the IAM Group.""" + + url = self.base_path + '/%s/users/%s' % (iam_group_id, user_id) + resp = session.put(url, endpoint_filter=self.service) + self._translate_response(resp, has_body=True) + return self + + def delete_assign_user(self, session, iam_group_id, user_id): + """Delete Assignment of the IAM User to the IAM Group.""" + + url = self.base_path + '/%s/users/%s' % (iam_group_id, user_id) + resp = session.delete(url, endpoint_filter=self.service) + self._translate_response(resp, has_body=False) + return self diff --git a/ecl/sss/v2/iam_role.py b/ecl/sss/v2/iam_role.py new file mode 100644 index 0000000..a473dfd --- /dev/null +++ b/ecl/sss/v2/iam_role.py @@ -0,0 +1,46 @@ +# 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.sss import sss_service +from ecl import resource2 + + +class IAMRole(resource2.Resource): + resource_key = None + resources_key = 'iam_roles' + base_path = '/iam/roles' + + # Capabilities + allow_create = True + allow_delete = True + allow_list = True + allow_get = True + + # Properties + #: The IAM Role's ID. + iam_role_id = resource2.Body('iam_role_id', alternate_id=True) + #: The IAM Role's name. + iam_role_name = resource2.Body('iam_role_name') + #: Description of the IAM Role. + description = resource2.Body('description') + #: Whitelist rules of API exectution. + resources = resource2.Body('resources') + #: The contact ID that the IAM Role belongs. + contract_id = resource2.Body('contract_id') + + def list(self, session, contract_id): + """List IAM Role list in the designated contract.""" + + url = self.base_path + '?contract_id=%s' % contract_id + resp = session.get(url, endpoint_filter=self.service) + self._translate_response(resp, has_body=True) + return self diff --git a/ecl/sss/v2/tenant.py b/ecl/sss/v2/tenant.py new file mode 100644 index 0000000..7f4d8b8 --- /dev/null +++ b/ecl/sss/v2/tenant.py @@ -0,0 +1,78 @@ +# 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.sss import sss_service +from ecl import resource2 +from ecl import exceptions + +class Tenant(resource2.Resource): + resources_key = 'tenants' + resource_key = None + base_path = '/tenants' + service = sss_service.SssService() + + # Capabilities + allow_create = True + allow_list = True + put_create = False + + # Properties + #: Workspace ID which this tenant belongs. + workspace_id = resource2.Body("workspace_id") + #: Tenant's id. + tenant_id = resource2.Body("tenant_id", alternate_id=True) + #: Tenant name. + tenant_name = resource2.Body("tenant_name") + #: Tenant's description. + description = resource2.Body("description") + #: Region which the tenant belongs to. + region = resource2.Body("region") + #: Contract which the tenant belongs to. + contract_id = resource2.Body("contract_id") + + @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/sss/v2/user.py b/ecl/sss/v2/user.py new file mode 100644 index 0000000..577fdb6 --- /dev/null +++ b/ecl/sss/v2/user.py @@ -0,0 +1,117 @@ +# 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.sss import sss_service +from ecl import resource2 +from ecl import exceptions +from ecl import utils + +class User(resource2.Resource): + resource_key = None + resources_key = 'users' + base_path = '/users' + service = sss_service.SssService() + + # Capabilities + allow_create = True + allow_get = True + allow_delete = True + allow_list = True + allow_update = True + put_create = False + + # Properties + #: login id of the user. When this contract is tied with icp, this + #: parameter is fixed {email}_{user_id}. + login_id = resource2.Body('login_id') + #: Mail address of the user. + mail_address = resource2.Body('mail_address') + #: User id. format is ecid[0-9]{10}. + user_id = resource2.Body('user_id', alternate_id=True) + #: If this user is the Super user in this contract, 1. If not, 0. + contract_owner = resource2.Body('contract_owner') + #: Contract ID which this user belongs. contract id format is econ[0-9]{10}. + contract_id = resource2.Body('contract_id') + #: This user's API key for keystone authentication. + keystone_name = resource2.Body('keystone_name') + #: Keystone address this user can use to get token for SSS API request. + keystone_endpoint = resource2.Body('keystone_endpoint') + #: This user's API secret for keystone authentication. + keystone_password = resource2.Body('keystone_password') + #: SSS endpoint recommended for this user + sss_endpoint = resource2.Body('sss_endpoint') + #: Password of the user + password = resource2.Body('password') + #: If this flag is set 'true', notification eamil will be sent to new + #: user's email. + notify_password = resource2.Body('notify_password') + #: New password of the user + new_password = resource2.Body('new_password') + #: User list. + users = resource2.Body('users') + #: If this user's contract is tied with NTT Communications business portal, + #: 'icp' is shown. + login_integration = resource2.Body('login_integration') + #: External system oriented contract id. If this user's contract is NTT + #: Communications, customer number with 15 numbers will be shown. + external_reference_id = resource2.Body('external_reference_id') + #: If this user is the Super user in this contract, true. If not, false + super_user = resource2.Body('super_user') + + def update(self, session, user_id, **attrs): + """Update user's information""" + + uri = utils.urljoin(self.base_path, user_id) + resp = session.put( + uri, endpoint_filter=self.service, + json=attrs + ) + self._translate_response(resp, has_body=False) + return self + + @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/sss/v2/workspace.py b/ecl/sss/v2/workspace.py new file mode 100644 index 0000000..8163990 --- /dev/null +++ b/ecl/sss/v2/workspace.py @@ -0,0 +1,75 @@ +# 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.sss import sss_service +from ecl import resource2 +from ecl import utils + +class Workspace(resource2.Resource): + resource_key = None + resources_key = 'workspaces' + base_path = '/workspaces' + service = sss_service.SssService() + + # Capabilities + allow_create = True + allow_get = True + allow_list = True + allow_delete = True + allow_update = True + + _query_mapping = resource2.QueryParameters("contract_id") + + # Properties + #: ID of the contract. + contract_id = resource2.Body('contract_id') + #: ID of the workspace. + workspace_id = resource2.Body('workspace_id', alternate_id=True) + #: Name of the workspace. Workspace name is also a unique identifier of workspaces. + workspace_name = resource2.Body('workspace_name') + #: Description of the workspace. + description = resource2.Body('description') + #: Workspace created time. + start_time = resource2.Body('start_time') + #: list of workspace. + workspaces = resource2.Body('workspaces') + #: Array of region information where tenants can be created. + regions = resource2.Body('regions') + #: ID of the user. + user_id = resource2.Body('user_id') + #: list of user. + users = resource2.Body('users') + + def update(self, session, workspace_id, **attrs): + """Updates the description for the designated workspace.""" + + uri = utils.urljoin(self.base_path, workspace_id) + resp = session.put( + uri, endpoint_filter=self.service, json=attrs) + self._translate_response(resp, has_body=False) + return self + + def add_workspace_role_assignment(self, session, user_id, workspace_id): + """Add role between user and workspace.""" + + url = '/workspace-roles' + resp = session.post(url, endpoint_filter=self.service, json={"user_id": user_id, "workspace_id": workspace_id}) + self._translate_response(resp, has_body=True) + return self + + def delete_workspace_role_assignment(self, session, workspace_id, user_id): + """Delete role between user and workspace.""" + + url = '/workspace-roles/workspaces/%s/users/%s' % (workspace_id, user_id) + resp = session.delete(url, endpoint_filter=self.service) + self._translate_response(resp, has_body=False) + return self 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)