From 930ef63304a476c7f5ef3502f0542495310efab1 Mon Sep 17 00:00:00 2001 From: NaoShark <49853899+NaoShark@users.noreply.github.com> Date: Tue, 6 Apr 2021 16:08:23 +0900 Subject: [PATCH 01/18] Add MVNA Resource. (#74) --- ecl/mvna/__init__.py | 0 ecl/mvna/mvna_service.py | 24 + ecl/mvna/v1/__init__.py | 0 ecl/mvna/v1/_proxy.py | 1179 +++++++++++++++++++++++++++++++++ ecl/mvna/v1/base.py | 28 + ecl/mvna/v1/certificate.py | 39 ++ ecl/mvna/v1/health_monitor.py | 57 ++ ecl/mvna/v1/listener.py | 47 ++ ecl/mvna/v1/load_balancer.py | 57 ++ ecl/mvna/v1/maintenance.py | 37 ++ ecl/mvna/v1/plan.py | 50 ++ ecl/mvna/v1/policy.py | 57 ++ ecl/mvna/v1/route.py | 45 ++ ecl/mvna/v1/rule.py | 49 ++ ecl/mvna/v1/target_group.py | 45 ++ ecl/profile.py | 2 + 16 files changed, 1716 insertions(+) create mode 100644 ecl/mvna/__init__.py create mode 100644 ecl/mvna/mvna_service.py create mode 100644 ecl/mvna/v1/__init__.py create mode 100644 ecl/mvna/v1/_proxy.py create mode 100644 ecl/mvna/v1/base.py create mode 100644 ecl/mvna/v1/certificate.py create mode 100644 ecl/mvna/v1/health_monitor.py create mode 100644 ecl/mvna/v1/listener.py create mode 100644 ecl/mvna/v1/load_balancer.py create mode 100644 ecl/mvna/v1/maintenance.py create mode 100644 ecl/mvna/v1/plan.py create mode 100644 ecl/mvna/v1/policy.py create mode 100644 ecl/mvna/v1/route.py create mode 100644 ecl/mvna/v1/rule.py create mode 100644 ecl/mvna/v1/target_group.py diff --git a/ecl/mvna/__init__.py b/ecl/mvna/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ecl/mvna/mvna_service.py b/ecl/mvna/mvna_service.py new file mode 100644 index 0000000..3fd95bf --- /dev/null +++ b/ecl/mvna/mvna_service.py @@ -0,0 +1,24 @@ +# 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 MVNAService(service_filter.ServiceFilter): + """The mvna service.""" + + valid_versions = [service_filter.ValidVersion('v1')] + + def __init__(self, version=None): + """Create a mvna service.""" + super(MVNAService, self).__init__(service_type='managed-load-balancer', + version=version) diff --git a/ecl/mvna/v1/__init__.py b/ecl/mvna/v1/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ecl/mvna/v1/_proxy.py b/ecl/mvna/v1/_proxy.py new file mode 100644 index 0000000..2f76b05 --- /dev/null +++ b/ecl/mvna/v1/_proxy.py @@ -0,0 +1,1179 @@ +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 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 + + +class Proxy(proxy2.BaseProxy): + + def load_balancers(self, **params): + """List Managed Load Balancers.""" + return self._list(_load_balancer.LoadBalancer, paginated=False, + **params) + + def create_load_balancer(self, plan_id, interfaces, + name=None, description=None, tags=None, + default_gateway=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 string default_gateway: Default Gateway 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 default_gateway: + body["default_gateway"] = default_gateway + if syslog_servers: + body["syslog_servers"] = syslog_servers + return self._create(_load_balancer.LoadBalancer, **body) + + def get_load_balancer(self, load_balancer_id): + """Retrieve Managed Load Balancer Information. + + :param string load_balancer_id: ID of Managed Load Balancer + :return: Managed Load Balancer + """ + return self._get(_load_balancer.LoadBalancer, load_balancer_id) + + def update_load_balancer(self, load_balancer_id, + name=None, description=None, tags=None): + """Update Managed Load Balancer Attributes. + + :param string load_balancer_id: ID 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 + :return: Managed Load Balancer + """ + body = {} + if name: + body["name"] = name + if description: + body["description"] = description + if tags: + body["tags"] = tags + return self._update(_load_balancer.LoadBalancer, load_balancer_id, + **body) + + def delete_load_balancer(self, load_balancer_id, ignore_missing=False): + """Delete Managed Load Balancer. + + :param string load_balancer_id: ID of Managed Load Balancer + :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 + """ + self._delete(_load_balancer.LoadBalancer, load_balancer_id, + ignore_missing=ignore_missing) + + def action_load_balancer(self, load_balancer_id, **body): + """Reflect the configuration to Managed Load Balancer. + + :param string load_balancer_id: ID of Managed Load Balancer + :param dict body: Request Body which want to apply. + :return: None + """ + load_balancer = _load_balancer.LoadBalancer() + load_balancer.action(self.session, load_balancer_id, **body) + + def create_staged_load_balancer_configuration(self, + load_balancer_id, + default_gateway=None, + syslog_servers=None, + interfaces=None): + """Create Staged Managed Load Balancer Configuration. + + :param string load_balancer_id: ID of Managed Load Balancer + :param string default_gateway: Default Gateway 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 default_gateway: + body["default_gateway"] = default_gateway + 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 + """ + load_balancer = _load_balancer.LoadBalancer() + return load_balancer.get_staged_configuration(self.session, + load_balancer_id) + + def update_staged_load_balancer_configuration(self, + load_balancer_id, + default_gateway=None, + syslog_servers=None, + interfaces=None): + """Update Staged Managed Load Balancer Configuration. + + :param string load_balancer_id: ID of Managed Load Balancer + :param string default_gateway: Default Gateway 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 default_gateway: + body["default_gateway"] = default_gateway + 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 self._list(_target_group.TargetGroup, paginated=False, **params) + + def create_target_group(self, default_port, load_balancer_id, members, + name=None, description=None, tags=None): + """Create Target Group. + + :param string default_port: Default Port of 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 = { + 'default_port': default_port, + '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): + """Retrieve Target Group Information. + + :param string target_group_id: ID of Target Group + :return: Target Group + """ + return self._get(_target_group.TargetGroup, target_group_id) + + def update_target_group(self, target_group_id, + name=None, description=None, tags=None): + """Update Target Group Attributes. + + :param string target_group_id: ID 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 = {} + if name: + body["name"] = name + if description: + body["description"] = description + if tags: + body["tags"] = tags + return self._update(_target_group.TargetGroup, target_group_id, **body) + + 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, default_port=None): + """Create Staged Target Group Configuration. + + :param string target_group_id: ID of Target Group + :param string members: Members of Target Group + :param string default_port: Default Port of Target Group + :return: Target Group + """ + body = {} + if members: + body["members"] = members + if default_port: + body["default_port"] = default_port + + 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 + """ + target_group = _target_group.TargetGroup() + return target_group.get_staged_configuration(self.session, + target_group_id) + + def update_staged_target_group_configuration( + self, target_group_id, members=None, default_port=None): + """Update Staged Target Group Configuration. + + :param string target_group_id: ID of Target Group + :param string members: Members of Target Group + :param string default_port: Default Port of Target Group + :return: Target Group + """ + body = {} + if members: + body["members"] = members + if default_port: + body["default_port"] = default_port + + 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) + + def certificates(self, **params): + """List Certificates.""" + return 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 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): + """Retrieve Listener Information. + + :param string listener_id: ID of Listener + :return: Listener + """ + return self._get(_listener.Listener, listener_id) + + def update_listener(self, listener_id, + name=None, description=None, tags=None): + """Update Listener Attributes. + + :param string listener_id: ID of Listener + :param string name: Name of Listener + :param string description: Description of Listener + :param dict tags: Tags of Listener + :return: Listener + """ + body = {} + if name: + body["name"] = name + if description: + body["description"] = description + if tags: + body["tags"] = tags + return self._update(_listener.Listener, listener_id, + **body) + + 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 + """ + listener = _listener.Listener() + return listener.get_staged_configuration(self.session, 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) + + def maintenances(self, **params): + """List Maintenances.""" + return 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 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 self._list(_health_monitor.HealthMonitor, paginated=False, + **params) + + def create_health_monitor(self, port, protocol, load_balancer_id, + name=None, description=None, tags=None, + interval=None, retry=None, threshold_count=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 threshold_count: Threshold 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 threshold_count: + body["threshold_count"] = threshold_count + 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): + """Retrieve Health Monitor Information. + + :param string health_monitor_id: ID of Health Monitor + :return: Health Monitor + """ + return self._get(_health_monitor.HealthMonitor, health_monitor_id) + + def update_health_monitor(self, health_monitor_id, + name=None, description=None, tags=None): + """Update Health Monitor Attributes. + + :param string health_monitor_id: ID of Health Monitor + :param string name: Name of Health Monitor + :param string description: Description of Health Monitor + :param dict tags: Tags of Health Monitor + :return: Health Monitor + """ + body = {} + if name: + body["name"] = name + if description: + body["description"] = description + if tags: + body["tags"] = tags + return self._update(_health_monitor.HealthMonitor, health_monitor_id, + **body) + + 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) + + def create_staged_health_monitor_configuration( + self, health_monitor_id, + port=None, protocol=None, interval=None, retry=None, + threshold_count=None, timeout=None, path=None, + http_status_code=None): + """Create Staged Health Monitor Configuration. + + :param string health_monitor_id: ID of Health Monitor + :param string 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 threshold_count: Threshold 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: + body["port"] = port + if protocol: + body["protocol"] = protocol + if interval: + body["interval"] = interval + if retry: + body["retry"] = retry + if threshold_count: + body["threshold_count"] = threshold_count + 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 + """ + health_monitor = _health_monitor.HealthMonitor() + return health_monitor.get_staged_configuration(self.session, + health_monitor_id) + + def update_staged_health_monitor_configuration( + self, health_monitor_id, + port=None, protocol=None, interval=None, retry=None, + threshold_count=None, timeout=None, path=None, + http_status_code=None): + """Update Staged Health Monitor Configuration. + + :param string health_monitor_id: ID of Health Monitor + :param string 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 threshold_count: Threshold 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: + body["port"] = port + if protocol: + body["protocol"] = protocol + if interval: + body["interval"] = interval + if retry: + body["retry"] = retry + if threshold_count: + body["threshold_count"] = threshold_count + 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 self._list(_policy.Policy, paginated=False, **params) + + 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): + """Retrieve Policy Information. + + :param string policy_id: ID of Policy + :return: Policy + """ + return self._get(_policy.Policy, policy_id) + + def update_policy(self, policy_id, name=None, description=None, tags=None): + """Update Policy Attributes. + + :param string policy_id: ID of Policy + :param string name: Name of Policy + :param string description: Description of Policy + :param dict tags: Tags of Policy + :return: Policy + """ + body = {} + if name: + body["name"] = name + if description: + body["description"] = description + if tags: + body["tags"] = tags + return self._update(_policy.Policy, policy_id, **body) + + 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) + + 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 + """ + policy = _policy.Policy() + return policy.get_staged_configuration(self.session, policy_id) + + 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 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): + """Retrieve Route Information. + + :param string route_id: ID of Route + :return: Route + """ + return self._get(_route.Route, route_id) + + def update_route(self, route_id, + name=None, description=None, tags=None): + """Update Route Attributes. + + :param string route_id: ID of Route + :param string name: Name of Route + :param string description: Description of Route + :param dict tags: Tags of Route + :return: Route + """ + body = {} + if name: + body["name"] = name + if description: + body["description"] = description + if tags: + body["tags"] = tags + return self._update(_route.Route, route_id, **body) + + 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 + """ + route = _route.Route() + return route.get_staged_configuration(self.session, 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) + + def rules(self, **params): + """List Rules.""" + return self._list(_rule.Rule, paginated=False, **params) + + def create_rule(self, priority, target_group_id, policy_id, condition, + 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 condition: Condition ID 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, + 'condition': condition + } + 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): + """Retrieve Rule Information. + + :param string rule_id: ID of Rule + :return: Rule + """ + return self._get(_rule.Rule, rule_id) + + 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, condition=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 condition: Condition of Rule + :return: Rule + """ + body = {} + if priority: + body["priority"] = priority + if target_group_id: + body["target_group_id"] = target_group_id + if condition: + body["condition"] = condition + + 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 + """ + rule = _rule.Rule() + return rule.get_staged_configuration(self.session, rule_id) + + def update_staged_rule_configuration( + self, rule_id, + priority=None, target_group_id=None, condition=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 condition: Condition of Rule + :return: Rule + """ + body = {} + if priority: + body["priority"] = priority + if target_group_id: + body["target_group_id"] = target_group_id + if condition: + body["condition"] = condition + + 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) diff --git a/ecl/mvna/v1/base.py b/ecl/mvna/v1/base.py new file mode 100644 index 0000000..fe146e5 --- /dev/null +++ b/ecl/mvna/v1/base.py @@ -0,0 +1,28 @@ +from ecl import resource2 + + +class MVNABaseResource(resource2.Resource): + + 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 get_staged_configuration(self, session, resource_id): + uri = self.base_path + '/%s/staged' % resource_id + resp = session.get(uri, endpoint_filter=self.service) + 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 + session.delete(uri, endpoint_filter=self.service) diff --git a/ecl/mvna/v1/certificate.py b/ecl/mvna/v1/certificate.py new file mode 100644 index 0000000..b833df6 --- /dev/null +++ b/ecl/mvna/v1/certificate.py @@ -0,0 +1,39 @@ +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' + + # 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 + session.post(uri, endpoint_filter=self.service, json=body) diff --git a/ecl/mvna/v1/health_monitor.py b/ecl/mvna/v1/health_monitor.py new file mode 100644 index 0000000..558a6a3 --- /dev/null +++ b/ecl/mvna/v1/health_monitor.py @@ -0,0 +1,57 @@ +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' + + # 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') + #: Threshold count of health monitor + threshold_count = resource2.Body('threshold_count') + #: Timeout of health monitor + timeout = resource2.Body('timeout') + #: 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..b25586c --- /dev/null +++ b/ecl/mvna/v1/listener.py @@ -0,0 +1,47 @@ +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' + + # 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..cd2ae30 --- /dev/null +++ b/ecl/mvna/v1/load_balancer.py @@ -0,0 +1,57 @@ +from . import base + +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' + + # 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') + #: Availability zones of load balancer + availability_zones = resource2.Body('availability_zones') + #: Default gateway of load balancer + default_gateway = resource2.Body('default_gateway') + #: Revision of load balancer + revision = resource2.Body('revision') + #: Plan ID of load balancer + plan_id = resource2.Body('plan_id') + #: Tenant ID of load balancer + tenant_id = resource2.Body('tenant_id') + #: 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 action(self, session, resource_id, **body): + uri = self.base_path + '/%s/action' % resource_id + session.post(uri, endpoint_filter=self.service, json=body) diff --git a/ecl/mvna/v1/maintenance.py b/ecl/mvna/v1/maintenance.py new file mode 100644 index 0000000..983945c --- /dev/null +++ b/ecl/mvna/v1/maintenance.py @@ -0,0 +1,37 @@ +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' + + # 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/plan.py b/ecl/mvna/v1/plan.py new file mode 100644 index 0000000..b2dc9d8 --- /dev/null +++ b/ecl/mvna/v1/plan.py @@ -0,0 +1,50 @@ +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' + + # 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') + #: 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..8b08ed3 --- /dev/null +++ b/ecl/mvna/v1/policy.py @@ -0,0 +1,57 @@ +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' + + # 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') + #: Sorry page URL of policy + sorry_page_url = resource2.Body('sorry_page_url') + #: Certificate ID of policy + certificate_id = resource2.Body('certificate_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') + #: TLS security policy ID of policy + tls_security_policy_id = resource2.Body('tls_security_policy_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..a7889b4 --- /dev/null +++ b/ecl/mvna/v1/route.py @@ -0,0 +1,45 @@ +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' + + # 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..67732a6 --- /dev/null +++ b/ecl/mvna/v1/rule.py @@ -0,0 +1,49 @@ +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' + + # 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') + #: Condition of rule + condition = resource2.Body('condition') + #: 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..125ac6c --- /dev/null +++ b/ecl/mvna/v1/target_group.py @@ -0,0 +1,45 @@ +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' + + # 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') + #: Default port of target group + default_port = resource2.Body('default_port') + #: 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/profile.py b/ecl/profile.py index 15cd934..25ae6e9 100755 --- a/ecl/profile.py +++ b/ecl/profile.py @@ -82,6 +82,7 @@ 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__) @@ -141,6 +142,7 @@ def __init__(self, plugins=None): 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. From c9c97c29ce40d877273f07fafc411895f261246c Mon Sep 17 00:00:00 2001 From: NaoShark <49853899+NaoShark@users.noreply.github.com> Date: Fri, 16 Apr 2021 09:36:02 +0900 Subject: [PATCH 02/18] Support additional mvna parameter (#76) * Support List Query Parameters. * Support changes query parameter. * Support X-MVNA-Request-Id Header Parameter. * Add `ignore_missing` argument to delete_load_balancer function. * Refactoring the code. --- ecl/mvna/v1/_proxy.py | 104 +++++++++++++++++++++++----------- ecl/mvna/v1/base.py | 22 ++++++- ecl/mvna/v1/certificate.py | 14 ++++- ecl/mvna/v1/health_monitor.py | 17 ++++++ ecl/mvna/v1/listener.py | 13 +++++ ecl/mvna/v1/load_balancer.py | 47 ++++++++++++++- ecl/mvna/v1/maintenance.py | 11 ++++ ecl/mvna/v1/plan.py | 17 ++++++ ecl/mvna/v1/policy.py | 18 ++++++ ecl/mvna/v1/route.py | 12 ++++ ecl/mvna/v1/rule.py | 13 +++++ ecl/mvna/v1/target_group.py | 11 ++++ 12 files changed, 260 insertions(+), 39 deletions(-) diff --git a/ecl/mvna/v1/_proxy.py b/ecl/mvna/v1/_proxy.py index 2f76b05..910cc91 100644 --- a/ecl/mvna/v1/_proxy.py +++ b/ecl/mvna/v1/_proxy.py @@ -45,13 +45,16 @@ def create_load_balancer(self, plan_id, interfaces, body["syslog_servers"] = syslog_servers return self._create(_load_balancer.LoadBalancer, **body) - def get_load_balancer(self, load_balancer_id): + 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 """ - return self._get(_load_balancer.LoadBalancer, load_balancer_id) + load_balancer = _load_balancer.LoadBalancer() + return load_balancer.get_resource(self.session, load_balancer_id, + changes) def update_load_balancer(self, load_balancer_id, name=None, description=None, tags=None): @@ -73,10 +76,12 @@ def update_load_balancer(self, load_balancer_id, return self._update(_load_balancer.LoadBalancer, load_balancer_id, **body) - def delete_load_balancer(self, load_balancer_id, ignore_missing=False): + 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. @@ -84,18 +89,22 @@ def delete_load_balancer(self, load_balancer_id, ignore_missing=False): attempting to delete a nonexistent load balancer. :return: None """ - self._delete(_load_balancer.LoadBalancer, load_balancer_id, - ignore_missing=ignore_missing) + 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, **body): + 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, **body) + load_balancer.action(self.session, load_balancer_id, x_mvna_request_id, + **body) def create_staged_load_balancer_configuration(self, load_balancer_id, @@ -123,15 +132,18 @@ def create_staged_load_balancer_configuration(self, load_balancer_id, **body) - def get_staged_load_balancer_configuration(self, load_balancer_id): + def get_staged_load_balancer_configuration(self, load_balancer_id, + changes=None): """Retrieve Staged Managed Load Balancer Configuration. :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_staged_configuration(self.session, - load_balancer_id) + load_balancer_id, + changes) def update_staged_load_balancer_configuration(self, load_balancer_id, @@ -198,13 +210,16 @@ def create_target_group(self, default_port, load_balancer_id, members, body["tags"] = tags return self._create(_target_group.TargetGroup, **body) - def get_target_group(self, target_group_id): + 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 """ - return self._get(_target_group.TargetGroup, target_group_id) + target_group = _target_group.TargetGroup() + return target_group.get_resource(self.session, target_group_id, + changes) def update_target_group(self, target_group_id, name=None, description=None, tags=None): @@ -259,15 +274,18 @@ def create_staged_target_group_configuration( target_group_id, **body) - def get_staged_target_group_configuration(self, target_group_id): + def get_staged_target_group_configuration(self, target_group_id, + changes=None): """Retrieve Staged Target Group Configuration. :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_staged_configuration(self.session, - target_group_id) + target_group_id, + changes) def update_staged_target_group_configuration( self, target_group_id, members=None, default_port=None): @@ -408,13 +426,15 @@ def create_listener(self, ip_address, port, protocol, load_balancer_id, body["tags"] = tags return self._create(_listener.Listener, **body) - def get_listener(self, listener_id): + 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 """ - return self._get(_listener.Listener, listener_id) + listener = _listener.Listener() + return listener.get_resource(self.session, listener_id, changes) def update_listener(self, listener_id, name=None, description=None, tags=None): @@ -473,14 +493,16 @@ def create_staged_listener_configuration( listener_id, **body) - def get_staged_listener_configuration(self, listener_id): + def get_staged_listener_configuration(self, listener_id, changes=None): """Retrieve Staged Listener Configuration. :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_staged_configuration(self.session, listener_id) + return listener.get_staged_configuration(self.session, listener_id, + changes) def update_staged_listener_configuration( self, listener_id, ip_address=None, port=None, protocol=None): @@ -589,13 +611,16 @@ def create_health_monitor(self, port, protocol, load_balancer_id, body["http_status_code"] = http_status_code return self._create(_health_monitor.HealthMonitor, **body) - def get_health_monitor(self, health_monitor_id): + 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 """ - return self._get(_health_monitor.HealthMonitor, health_monitor_id) + health_monitor = _health_monitor.HealthMonitor() + return health_monitor.get_resource(self.session, health_monitor_id, + changes) def update_health_monitor(self, health_monitor_id, name=None, description=None, tags=None): @@ -672,15 +697,18 @@ def create_staged_health_monitor_configuration( health_monitor_id, **body) - def get_staged_health_monitor_configuration(self, health_monitor_id): + def get_staged_health_monitor_configuration(self, health_monitor_id, + changes=None): """Retrieve Staged Health Monitor Configuration. :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_staged_configuration(self.session, - health_monitor_id) + health_monitor_id, + changes) def update_staged_health_monitor_configuration( self, health_monitor_id, @@ -782,13 +810,15 @@ def create_policy(self, health_monitor_id, listener_id, body["tls_security_policy_id"] = tls_security_policy_id return self._create(_policy.Policy, **body) - def get_policy(self, policy_id): + 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 """ - return self._get(_policy.Policy, policy_id) + policy = _policy.Policy() + return policy.get_resource(self.session, policy_id, changes) def update_policy(self, policy_id, name=None, description=None, tags=None): """Update Policy Attributes. @@ -864,14 +894,16 @@ def create_staged_policy_configuration(self, policy_id, return policy.create_staged_configuration(self.session, policy_id, **body) - def get_staged_policy_configuration(self, policy_id): + def get_staged_policy_configuration(self, policy_id, changes=None): """Retrieve Staged Policy Configuration. :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_staged_configuration(self.session, policy_id) + return policy.get_staged_configuration(self.session, policy_id, + changes) def update_staged_policy_configuration(self, policy_id, algorithm=None, persistence=None, @@ -956,13 +988,15 @@ def create_route(self, destination_cidr, body["tags"] = tags return self._create(_route.Route, **body) - def get_route(self, route_id): + 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 """ - return self._get(_route.Route, route_id) + route = _route.Route() + return route.get_resource(self.session, route_id, changes) def update_route(self, route_id, name=None, description=None, tags=None): @@ -1012,14 +1046,15 @@ def create_staged_route_configuration( return route.create_staged_configuration(self.session, route_id, **body) - def get_staged_route_configuration(self, route_id): + def get_staged_route_configuration(self, route_id, changes=None): """Retrieve Staged Route Configuration. :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_staged_configuration(self.session, route_id) + return route.get_staged_configuration(self.session, route_id, changes) def update_staged_route_configuration( self, route_id, next_hop_ip_address=None): @@ -1077,13 +1112,15 @@ def create_rule(self, priority, target_group_id, policy_id, condition, body["tags"] = tags return self._create(_rule.Rule, **body) - def get_rule(self, rule_id): + 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 """ - return self._get(_rule.Rule, rule_id) + 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. @@ -1138,14 +1175,15 @@ def create_staged_rule_configuration( rule = _rule.Rule() return rule.create_staged_configuration(self.session, rule_id, **body) - def get_staged_rule_configuration(self, rule_id): + def get_staged_rule_configuration(self, rule_id, changes=None): """Retrieve Staged Rule Configuration. :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_staged_configuration(self.session, rule_id) + return rule.get_staged_configuration(self.session, rule_id, changes) def update_staged_rule_configuration( self, rule_id, diff --git a/ecl/mvna/v1/base.py b/ecl/mvna/v1/base.py index fe146e5..bf754f1 100644 --- a/ecl/mvna/v1/base.py +++ b/ecl/mvna/v1/base.py @@ -3,6 +3,16 @@ 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, @@ -10,8 +20,12 @@ def create_staged_configuration(self, session, resource_id, **body): self._translate_response(resp, has_body=True) return self - def get_staged_configuration(self, session, resource_id): - uri = self.base_path + '/%s/staged' % resource_id + def get_staged_configuration(self, session, resource_id, changes=None): + if changes is not None and type(changes) is bool: + uri = self.base_path + '/%s/staged?changes=%s' % \ + (resource_id, str(changes).lower()) + else: + uri = self.base_path + '/%s/staged' % resource_id resp = session.get(uri, endpoint_filter=self.service) self._translate_response(resp, has_body=True) return self @@ -25,4 +39,6 @@ def update_staged_configuration(self, session, resource_id, **body): def cancel_staged_configuration(self, session, resource_id): uri = self.base_path + '/%s/staged' % resource_id - session.delete(uri, endpoint_filter=self.service) + resp = session.delete(uri, endpoint_filter=self.service) + self._translate_response(resp, has_body=False) + return self diff --git a/ecl/mvna/v1/certificate.py b/ecl/mvna/v1/certificate.py index b833df6..a0c84e2 100644 --- a/ecl/mvna/v1/certificate.py +++ b/ecl/mvna/v1/certificate.py @@ -8,6 +8,16 @@ class Certificate(resource2.Resource): service = mvna_service.MVNAService("v1.0") base_path = '/' + service.version + '/certificates' + _query_mapping = resource2.QueryParameters( + "id", + "name", + "description", + "tenant_id", + "ca_cert_status", + "ssl_key_status", + "ssl_cert_status" + ) + # Capabilities allow_list = True allow_get = True @@ -36,4 +46,6 @@ class Certificate(resource2.Resource): def upload(self, session, resource_id, **body): uri = self.base_path + '/%s/files' % resource_id - session.post(uri, endpoint_filter=self.service, json=body) + 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 index 558a6a3..d59eb64 100644 --- a/ecl/mvna/v1/health_monitor.py +++ b/ecl/mvna/v1/health_monitor.py @@ -10,6 +10,23 @@ class HealthMonitor(base.MVNABaseResource): service = mvna_service.MVNAService("v1.0") base_path = '/' + service.version + '/health_monitors' + _query_mapping = resource2.QueryParameters( + "id", + "name", + "description", + "configuration_status", + "operation_status", + "port", + "protocol", + "interval", + "retry", + "threshold_count", + "timeout", + "path", + "load_balancer_id", + "tenant_id" + ) + # Capabilities allow_list = True allow_get = True diff --git a/ecl/mvna/v1/listener.py b/ecl/mvna/v1/listener.py index b25586c..23045d3 100644 --- a/ecl/mvna/v1/listener.py +++ b/ecl/mvna/v1/listener.py @@ -10,6 +10,19 @@ class Listener(base.MVNABaseResource): service = mvna_service.MVNAService("v1.0") base_path = '/' + service.version + '/listeners' + _query_mapping = resource2.QueryParameters( + "id", + "name", + "description", + "configuration_status", + "operation_status", + "ip_address", + "port", + "protocol", + "load_balancer_id", + "tenant_id" + ) + # Capabilities allow_list = True allow_get = True diff --git a/ecl/mvna/v1/load_balancer.py b/ecl/mvna/v1/load_balancer.py index cd2ae30..21aca68 100644 --- a/ecl/mvna/v1/load_balancer.py +++ b/ecl/mvna/v1/load_balancer.py @@ -1,5 +1,6 @@ from . import base +from ecl import exceptions from ecl import resource2 from ecl.mvna import mvna_service @@ -10,6 +11,20 @@ class LoadBalancer(base.MVNABaseResource): service = mvna_service.MVNAService("v1.0") base_path = '/' + service.version + '/load_balancers' + _query_mapping = resource2.QueryParameters( + "id", + "name", + "description", + "configuration_status", + "monitoring_status", + "operation_status", + "availability_zone", + "default_gateway", + "revision", + "plan_id", + "tenant_id" + ) + # Capabilities allow_list = True allow_get = True @@ -52,6 +67,34 @@ class LoadBalancer(base.MVNABaseResource): #: Staged configuration of load balancer staged = resource2.Body('staged') - def action(self, session, resource_id, **body): + 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 - session.post(uri, endpoint_filter=self.service, json=body) + 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 index 983945c..77db032 100644 --- a/ecl/mvna/v1/maintenance.py +++ b/ecl/mvna/v1/maintenance.py @@ -8,6 +8,17 @@ class Maintenance(resource2.Resource): service = mvna_service.MVNAService("v1.0") base_path = '/' + service.version + '/maintenances' + _query_mapping = resource2.QueryParameters( + "id", + "name", + "description", + "href", + "current_revision", + "next_revision", + "applicable", + "latest" + ) + # Capabilities allow_list = True allow_get = True diff --git a/ecl/mvna/v1/plan.py b/ecl/mvna/v1/plan.py index b2dc9d8..de157c8 100644 --- a/ecl/mvna/v1/plan.py +++ b/ecl/mvna/v1/plan.py @@ -8,6 +8,23 @@ class Plan(resource2.Resource): service = mvna_service.MVNAService("v1.0") base_path = '/' + service.version + '/plans' + _query_mapping = resource2.QueryParameters( + "id", + "name", + "description", + "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 diff --git a/ecl/mvna/v1/policy.py b/ecl/mvna/v1/policy.py index 8b08ed3..837f7e4 100644 --- a/ecl/mvna/v1/policy.py +++ b/ecl/mvna/v1/policy.py @@ -10,6 +10,24 @@ class Policy(base.MVNABaseResource): service = mvna_service.MVNAService("v1.0") base_path = '/' + service.version + '/policies' + _query_mapping = resource2.QueryParameters( + "id", + "name", + "description", + "configuration_status", + "operation_status", + "algorithm", + "persistence", + "sorry_page_url", + "certificate_id", + "health_monitor_id", + "listener_id", + "default_target_group_id", + "tls_protocol", + "load_balancer_id", + "tenant_id" + ) + # Capabilities allow_list = True allow_get = True diff --git a/ecl/mvna/v1/route.py b/ecl/mvna/v1/route.py index a7889b4..2935a43 100644 --- a/ecl/mvna/v1/route.py +++ b/ecl/mvna/v1/route.py @@ -10,6 +10,18 @@ class Route(base.MVNABaseResource): service = mvna_service.MVNAService("v1.0") base_path = '/' + service.version + '/routes' + _query_mapping = resource2.QueryParameters( + "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 diff --git a/ecl/mvna/v1/rule.py b/ecl/mvna/v1/rule.py index 67732a6..4ec5b16 100644 --- a/ecl/mvna/v1/rule.py +++ b/ecl/mvna/v1/rule.py @@ -10,6 +10,19 @@ class Rule(base.MVNABaseResource): service = mvna_service.MVNAService("v1.0") base_path = '/' + service.version + '/rules' + _query_mapping = resource2.QueryParameters( + "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 diff --git a/ecl/mvna/v1/target_group.py b/ecl/mvna/v1/target_group.py index 125ac6c..ab81995 100644 --- a/ecl/mvna/v1/target_group.py +++ b/ecl/mvna/v1/target_group.py @@ -10,6 +10,17 @@ class TargetGroup(base.MVNABaseResource): service = mvna_service.MVNAService("v1.0") base_path = '/' + service.version + '/target_groups' + _query_mapping = resource2.QueryParameters( + "id", + "name", + "description", + "configuration_status", + "operation_status", + "default_port", + "load_balancer_id", + "tenant_id" + ) + # Capabilities allow_list = True allow_get = True From 69bbe69927c50cc28bebd95b64c47b2324f74895 Mon Sep 17 00:00:00 2001 From: NaoShark <49853899+NaoShark@users.noreply.github.com> Date: Tue, 20 Apr 2021 16:56:43 +0900 Subject: [PATCH 03/18] Add MVNA TLS Security Policy (#77) --- ecl/mvna/v1/_proxy.py | 15 +++++++++++++ ecl/mvna/v1/tls_security_policy.py | 35 ++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 ecl/mvna/v1/tls_security_policy.py diff --git a/ecl/mvna/v1/_proxy.py b/ecl/mvna/v1/_proxy.py index 910cc91..ec2e86b 100644 --- a/ecl/mvna/v1/_proxy.py +++ b/ecl/mvna/v1/_proxy.py @@ -9,6 +9,7 @@ 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): @@ -1215,3 +1216,17 @@ def cancel_staged_rule_configuration(self, rule_id): """ rule = _rule.Rule() rule.cancel_staged_configuration(self.session, rule_id) + + def tls_security_policies(self, **params): + """List TLS Security Policies.""" + return 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/tls_security_policy.py b/ecl/mvna/v1/tls_security_policy.py new file mode 100644 index 0000000..eb49d8f --- /dev/null +++ b/ecl/mvna/v1/tls_security_policy.py @@ -0,0 +1,35 @@ +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 = resource2.QueryParameters( + "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') From a7a7ce96ddcfda02d417d7f75982557b420d03da Mon Sep 17 00:00:00 2001 From: Manabu Miwa Date: Wed, 12 May 2021 13:17:24 +0900 Subject: [PATCH 04/18] =?UTF-8?q?=E2=9C=A8=20IF-5804=20Add=20Operation=20r?= =?UTF-8?q?esource=20to=20mVNA=20LB=20(#79)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ IF-5804 Add Operation resource to mVNA LB * ✨ IF-5804 Support additional params * ✨ IF-5804 Remove unsupported param * ✨ IF-5804 Add method to normalize boolean parameters * ✨ IF-5804 Apply previously commited changes for rest of resources * ✨ IF-5804 Make code better and more readable * ✨ IF-5804 Add new line to base.py --- ecl/mvna/v1/_proxy.py | 49 +++++++++++++++++---------- ecl/mvna/v1/base.py | 13 ++++++++ ecl/mvna/v1/certificate.py | 4 ++- ecl/mvna/v1/health_monitor.py | 2 +- ecl/mvna/v1/listener.py | 2 +- ecl/mvna/v1/load_balancer.py | 2 +- ecl/mvna/v1/maintenance.py | 4 ++- ecl/mvna/v1/operation.py | 53 ++++++++++++++++++++++++++++++ ecl/mvna/v1/plan.py | 4 ++- ecl/mvna/v1/policy.py | 2 +- ecl/mvna/v1/route.py | 2 +- ecl/mvna/v1/rule.py | 2 +- ecl/mvna/v1/target_group.py | 2 +- ecl/mvna/v1/tls_security_policy.py | 4 ++- 14 files changed, 117 insertions(+), 28 deletions(-) create mode 100755 ecl/mvna/v1/operation.py diff --git a/ecl/mvna/v1/_proxy.py b/ecl/mvna/v1/_proxy.py index ec2e86b..ca5af3f 100644 --- a/ecl/mvna/v1/_proxy.py +++ b/ecl/mvna/v1/_proxy.py @@ -4,6 +4,7 @@ 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 @@ -16,8 +17,8 @@ class Proxy(proxy2.BaseProxy): def load_balancers(self, **params): """List Managed Load Balancers.""" - return self._list(_load_balancer.LoadBalancer, paginated=False, - **params) + return list(self._list(_load_balancer.LoadBalancer, paginated=False, + **params)) def create_load_balancer(self, plan_id, interfaces, name=None, description=None, tags=None, @@ -184,7 +185,8 @@ def cancel_staged_load_balancer_configuration(self, load_balancer_id): def target_groups(self, **params): """List Target Groups.""" - return self._list(_target_group.TargetGroup, paginated=False, **params) + return list(self._list( + _target_group.TargetGroup, paginated=False, **params)) def create_target_group(self, default_port, load_balancer_id, members, name=None, description=None, tags=None): @@ -319,8 +321,8 @@ def cancel_staged_target_group_configuration(self, target_group_id): def certificates(self, **params): """List Certificates.""" - return self._list(_certificate.Certificate, paginated=False, - **params) + return list(self._list( + _certificate.Certificate, paginated=False, **params)) def create_certificate(self, name=None, description=None, tags=None): """Create Certificate. @@ -396,8 +398,8 @@ def upload_certificate(self, def listeners(self, **params): """List Listeners.""" - return self._list(_listener.Listener, paginated=False, - **params) + 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): @@ -538,8 +540,8 @@ def cancel_staged_listener_configuration(self, listener_id): def maintenances(self, **params): """List Maintenances.""" - return self._list(_maintenance.Maintenance, paginated=False, - **params) + return list(self._list( + _maintenance.Maintenance, paginated=False, **params)) def get_maintenance(self, maintenance_id): """Retrieve Maintenance Information. @@ -551,7 +553,7 @@ def get_maintenance(self, maintenance_id): def plans(self, **params): """List Plans.""" - return self._list(_plan.Plan, paginated=False, **params) + return list(self._list(_plan.Plan, paginated=False, **params)) def get_plan(self, plan_id): """Retrieve Plan Information. @@ -563,8 +565,8 @@ def get_plan(self, plan_id): def health_monitors(self, **params): """List Health Monitors.""" - return self._list(_health_monitor.HealthMonitor, paginated=False, - **params) + return list(self._list( + _health_monitor.HealthMonitor, paginated=False, **params)) def create_health_monitor(self, port, protocol, load_balancer_id, name=None, description=None, tags=None, @@ -764,7 +766,7 @@ def cancel_staged_health_monitor_configuration(self, health_monitor_id): def policies(self, **params): """List Policies.""" - return self._list(_policy.Policy, paginated=False, **params) + return list(self._list(_policy.Policy, paginated=False, **params)) def create_policy(self, health_monitor_id, listener_id, default_target_group_id, load_balancer_id, @@ -960,7 +962,7 @@ def cancel_staged_policy_configuration(self, policy_id): def routes(self, **params): """List Routes.""" - return self._list(_route.Route, paginated=False, **params) + return list(self._list(_route.Route, paginated=False, **params)) def create_route(self, destination_cidr, next_hop_ip_address, load_balancer_id, @@ -1084,7 +1086,7 @@ def cancel_staged_route_configuration(self, route_id): def rules(self, **params): """List Rules.""" - return self._list(_rule.Rule, paginated=False, **params) + return list(self._list(_rule.Rule, paginated=False, **params)) def create_rule(self, priority, target_group_id, policy_id, condition, name=None, description=None, tags=None): @@ -1217,10 +1219,23 @@ def cancel_staged_rule_configuration(self, rule_id): 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) + def tls_security_policies(self, **params): """List TLS Security Policies.""" - return self._list( - _tls_security_policy.TLSSecurityPolicy, paginated=False, **params) + 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. diff --git a/ecl/mvna/v1/base.py b/ecl/mvna/v1/base.py index bf754f1..060e9ab 100644 --- a/ecl/mvna/v1/base.py +++ b/ecl/mvna/v1/base.py @@ -42,3 +42,16 @@ def cancel_staged_configuration(self, session, 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 index a0c84e2..93a9996 100644 --- a/ecl/mvna/v1/certificate.py +++ b/ecl/mvna/v1/certificate.py @@ -1,3 +1,5 @@ +from . import base + from ecl import resource2 from ecl.mvna import mvna_service @@ -8,7 +10,7 @@ class Certificate(resource2.Resource): service = mvna_service.MVNAService("v1.0") base_path = '/' + service.version + '/certificates' - _query_mapping = resource2.QueryParameters( + _query_mapping = base.MVNAQueryParameters( "id", "name", "description", diff --git a/ecl/mvna/v1/health_monitor.py b/ecl/mvna/v1/health_monitor.py index d59eb64..ebab422 100644 --- a/ecl/mvna/v1/health_monitor.py +++ b/ecl/mvna/v1/health_monitor.py @@ -10,7 +10,7 @@ class HealthMonitor(base.MVNABaseResource): service = mvna_service.MVNAService("v1.0") base_path = '/' + service.version + '/health_monitors' - _query_mapping = resource2.QueryParameters( + _query_mapping = base.MVNAQueryParameters( "id", "name", "description", diff --git a/ecl/mvna/v1/listener.py b/ecl/mvna/v1/listener.py index 23045d3..9e0e4c1 100644 --- a/ecl/mvna/v1/listener.py +++ b/ecl/mvna/v1/listener.py @@ -10,7 +10,7 @@ class Listener(base.MVNABaseResource): service = mvna_service.MVNAService("v1.0") base_path = '/' + service.version + '/listeners' - _query_mapping = resource2.QueryParameters( + _query_mapping = base.MVNAQueryParameters( "id", "name", "description", diff --git a/ecl/mvna/v1/load_balancer.py b/ecl/mvna/v1/load_balancer.py index 21aca68..d5f7104 100644 --- a/ecl/mvna/v1/load_balancer.py +++ b/ecl/mvna/v1/load_balancer.py @@ -11,7 +11,7 @@ class LoadBalancer(base.MVNABaseResource): service = mvna_service.MVNAService("v1.0") base_path = '/' + service.version + '/load_balancers' - _query_mapping = resource2.QueryParameters( + _query_mapping = base.MVNAQueryParameters( "id", "name", "description", diff --git a/ecl/mvna/v1/maintenance.py b/ecl/mvna/v1/maintenance.py index 77db032..4a308a1 100644 --- a/ecl/mvna/v1/maintenance.py +++ b/ecl/mvna/v1/maintenance.py @@ -1,3 +1,5 @@ +from . import base + from ecl import resource2 from ecl.mvna import mvna_service @@ -8,7 +10,7 @@ class Maintenance(resource2.Resource): service = mvna_service.MVNAService("v1.0") base_path = '/' + service.version + '/maintenances' - _query_mapping = resource2.QueryParameters( + _query_mapping = base.MVNAQueryParameters( "id", "name", "description", 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 index de157c8..59ab5b2 100644 --- a/ecl/mvna/v1/plan.py +++ b/ecl/mvna/v1/plan.py @@ -1,3 +1,5 @@ +from . import base + from ecl import resource2 from ecl.mvna import mvna_service @@ -8,7 +10,7 @@ class Plan(resource2.Resource): service = mvna_service.MVNAService("v1.0") base_path = '/' + service.version + '/plans' - _query_mapping = resource2.QueryParameters( + _query_mapping = base.MVNAQueryParameters( "id", "name", "description", diff --git a/ecl/mvna/v1/policy.py b/ecl/mvna/v1/policy.py index 837f7e4..2f44ddc 100644 --- a/ecl/mvna/v1/policy.py +++ b/ecl/mvna/v1/policy.py @@ -10,7 +10,7 @@ class Policy(base.MVNABaseResource): service = mvna_service.MVNAService("v1.0") base_path = '/' + service.version + '/policies' - _query_mapping = resource2.QueryParameters( + _query_mapping = base.MVNAQueryParameters( "id", "name", "description", diff --git a/ecl/mvna/v1/route.py b/ecl/mvna/v1/route.py index 2935a43..2009fb3 100644 --- a/ecl/mvna/v1/route.py +++ b/ecl/mvna/v1/route.py @@ -10,7 +10,7 @@ class Route(base.MVNABaseResource): service = mvna_service.MVNAService("v1.0") base_path = '/' + service.version + '/routes' - _query_mapping = resource2.QueryParameters( + _query_mapping = base.MVNAQueryParameters( "id", "name", "description", diff --git a/ecl/mvna/v1/rule.py b/ecl/mvna/v1/rule.py index 4ec5b16..5316a8c 100644 --- a/ecl/mvna/v1/rule.py +++ b/ecl/mvna/v1/rule.py @@ -10,7 +10,7 @@ class Rule(base.MVNABaseResource): service = mvna_service.MVNAService("v1.0") base_path = '/' + service.version + '/rules' - _query_mapping = resource2.QueryParameters( + _query_mapping = base.MVNAQueryParameters( "id", "name", "description", diff --git a/ecl/mvna/v1/target_group.py b/ecl/mvna/v1/target_group.py index ab81995..919e0c4 100644 --- a/ecl/mvna/v1/target_group.py +++ b/ecl/mvna/v1/target_group.py @@ -10,7 +10,7 @@ class TargetGroup(base.MVNABaseResource): service = mvna_service.MVNAService("v1.0") base_path = '/' + service.version + '/target_groups' - _query_mapping = resource2.QueryParameters( + _query_mapping = base.MVNAQueryParameters( "id", "name", "description", diff --git a/ecl/mvna/v1/tls_security_policy.py b/ecl/mvna/v1/tls_security_policy.py index eb49d8f..4a59f26 100644 --- a/ecl/mvna/v1/tls_security_policy.py +++ b/ecl/mvna/v1/tls_security_policy.py @@ -1,3 +1,5 @@ +from . import base + from ecl import resource2 from ecl.mvna import mvna_service @@ -8,7 +10,7 @@ class TLSSecurityPolicy(resource2.Resource): service = mvna_service.MVNAService("v1.0") base_path = '/' + service.version + '/tls_security_policies' - _query_mapping = resource2.QueryParameters( + _query_mapping = base.MVNAQueryParameters( "id", "name", "description", "default", ) From edc33d339d4c99e09d19b012b94aef63e639ee9d Mon Sep 17 00:00:00 2001 From: NaoShark <49853899+NaoShark@users.noreply.github.com> Date: Tue, 18 May 2021 11:09:53 +0900 Subject: [PATCH 05/18] Follow MVNA api spec changes (#80) --- ecl/mvna/v1/_proxy.py | 105 ++++++++-------------------------- ecl/mvna/v1/base.py | 10 ---- ecl/mvna/v1/health_monitor.py | 3 - ecl/mvna/v1/load_balancer.py | 3 - ecl/mvna/v1/target_group.py | 3 - 5 files changed, 25 insertions(+), 99 deletions(-) diff --git a/ecl/mvna/v1/_proxy.py b/ecl/mvna/v1/_proxy.py index ca5af3f..9845b5a 100644 --- a/ecl/mvna/v1/_proxy.py +++ b/ecl/mvna/v1/_proxy.py @@ -18,11 +18,11 @@ class Proxy(proxy2.BaseProxy): def load_balancers(self, **params): """List Managed Load Balancers.""" return list(self._list(_load_balancer.LoadBalancer, paginated=False, - **params)) + **params)) def create_load_balancer(self, plan_id, interfaces, name=None, description=None, tags=None, - default_gateway=None, syslog_servers=None): + syslog_servers=None): """Create Managed Load Balancer. :param string plan_id: Plan ID of Managed Load Balancer @@ -30,7 +30,6 @@ def create_load_balancer(self, plan_id, interfaces, :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 string default_gateway: Default Gateway of Managed Load Balancer :param list syslog_servers: Syslog Servers of Managed Load Balancer :return: Managed Load Balancer """ @@ -41,8 +40,6 @@ def create_load_balancer(self, plan_id, interfaces, body["description"] = description if tags: body["tags"] = tags - if default_gateway: - body["default_gateway"] = default_gateway if syslog_servers: body["syslog_servers"] = syslog_servers return self._create(_load_balancer.LoadBalancer, **body) @@ -110,20 +107,16 @@ def action_load_balancer(self, load_balancer_id, x_mvna_request_id=None, def create_staged_load_balancer_configuration(self, load_balancer_id, - default_gateway=None, syslog_servers=None, interfaces=None): """Create Staged Managed Load Balancer Configuration. :param string load_balancer_id: ID of Managed Load Balancer - :param string default_gateway: Default Gateway 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 default_gateway: - body["default_gateway"] = default_gateway if syslog_servers: body["syslog_servers"] = syslog_servers if interfaces: @@ -134,35 +127,26 @@ def create_staged_load_balancer_configuration(self, load_balancer_id, **body) - def get_staged_load_balancer_configuration(self, load_balancer_id, - changes=None): + 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 - :param bool changes: Whether or not to retrieve staged configuration :return: Managed Load Balancer """ - load_balancer = _load_balancer.LoadBalancer() - return load_balancer.get_staged_configuration(self.session, - load_balancer_id, - changes) + return self._get(_load_balancer.LoadBalancer, load_balancer_id) def update_staged_load_balancer_configuration(self, load_balancer_id, - default_gateway=None, syslog_servers=None, interfaces=None): """Update Staged Managed Load Balancer Configuration. :param string load_balancer_id: ID of Managed Load Balancer - :param string default_gateway: Default Gateway 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 default_gateway: - body["default_gateway"] = default_gateway if syslog_servers: body["syslog_servers"] = syslog_servers if interfaces: @@ -188,11 +172,10 @@ def target_groups(self, **params): return list(self._list( _target_group.TargetGroup, paginated=False, **params)) - def create_target_group(self, default_port, load_balancer_id, members, + def create_target_group(self, load_balancer_id, members, name=None, description=None, tags=None): """Create Target Group. - :param string default_port: Default Port of 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 @@ -201,7 +184,6 @@ def create_target_group(self, default_port, load_balancer_id, members, :return: Target Group """ body = { - 'default_port': default_port, 'load_balancer_id': load_balancer_id, 'members': members } @@ -257,53 +239,42 @@ def delete_target_group(self, target_group_id, ignore_missing=False): self._delete(_target_group.TargetGroup, target_group_id, ignore_missing=ignore_missing) - def create_staged_target_group_configuration( - self, target_group_id, members=None, default_port=None): + 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 - :param string default_port: Default Port of Target Group :return: Target Group """ body = {} if members: body["members"] = members - if default_port: - body["default_port"] = default_port 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, - changes=None): + def get_staged_target_group_configuration(self, target_group_id): """Retrieve Staged Target Group Configuration. :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_staged_configuration(self.session, - target_group_id, - changes) + return self._get(_target_group.TargetGroup, target_group_id) - def update_staged_target_group_configuration( - self, target_group_id, members=None, default_port=None): + 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 - :param string default_port: Default Port of Target Group :return: Target Group """ body = {} if members: body["members"] = members - if default_port: - body["default_port"] = default_port target_group = _target_group.TargetGroup() return target_group.update_staged_configuration(self.session, @@ -496,16 +467,13 @@ def create_staged_listener_configuration( listener_id, **body) - def get_staged_listener_configuration(self, listener_id, changes=None): + def get_staged_listener_configuration(self, listener_id): """Retrieve Staged Listener Configuration. :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_staged_configuration(self.session, listener_id, - changes) + return self._get(_listener.Listener, listener_id) def update_staged_listener_configuration( self, listener_id, ip_address=None, port=None, protocol=None): @@ -570,8 +538,8 @@ def health_monitors(self, **params): def create_health_monitor(self, port, protocol, load_balancer_id, name=None, description=None, tags=None, - interval=None, retry=None, threshold_count=None, - timeout=None, path=None, http_status_code=None): + interval=None, retry=None, timeout=None, + path=None, http_status_code=None): """Create Health Monitor. :param string port: Port of Health Monitor @@ -582,7 +550,6 @@ def create_health_monitor(self, port, protocol, load_balancer_id, :param dict tags: Tags of Health Monitor :param int interval: Interval of Health Monitor :param int retry: Retry count of Health Monitor - :param int threshold_count: Threshold 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 @@ -604,8 +571,6 @@ def create_health_monitor(self, port, protocol, load_balancer_id, body["interval"] = interval if retry: body["retry"] = retry - if threshold_count: - body["threshold_count"] = threshold_count if timeout: body["timeout"] = timeout if path: @@ -662,8 +627,7 @@ def delete_health_monitor(self, health_monitor_id, ignore_missing=False): def create_staged_health_monitor_configuration( self, health_monitor_id, port=None, protocol=None, interval=None, retry=None, - threshold_count=None, timeout=None, path=None, - http_status_code=None): + timeout=None, path=None, http_status_code=None): """Create Staged Health Monitor Configuration. :param string health_monitor_id: ID of Health Monitor @@ -671,7 +635,6 @@ def create_staged_health_monitor_configuration( :param string protocol: Protocol of Health Monitor :param int interval: Interval of Health Monitor :param int retry: Retry count of Health Monitor - :param int threshold_count: Threshold 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 @@ -686,8 +649,6 @@ def create_staged_health_monitor_configuration( body["interval"] = interval if retry: body["retry"] = retry - if threshold_count: - body["threshold_count"] = threshold_count if timeout: body["timeout"] = timeout if path: @@ -700,24 +661,18 @@ def create_staged_health_monitor_configuration( health_monitor_id, **body) - def get_staged_health_monitor_configuration(self, health_monitor_id, - changes=None): + def get_staged_health_monitor_configuration(self, health_monitor_id): """Retrieve Staged Health Monitor Configuration. :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_staged_configuration(self.session, - health_monitor_id, - changes) + return self._get(_health_monitor.HealthMonitor, health_monitor_id) def update_staged_health_monitor_configuration( self, health_monitor_id, port=None, protocol=None, interval=None, retry=None, - threshold_count=None, timeout=None, path=None, - http_status_code=None): + timeout=None, path=None, http_status_code=None): """Update Staged Health Monitor Configuration. :param string health_monitor_id: ID of Health Monitor @@ -725,7 +680,6 @@ def update_staged_health_monitor_configuration( :param string protocol: Protocol of Health Monitor :param int interval: Interval of Health Monitor :param int retry: Retry count of Health Monitor - :param int threshold_count: Threshold 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 @@ -740,8 +694,6 @@ def update_staged_health_monitor_configuration( body["interval"] = interval if retry: body["retry"] = retry - if threshold_count: - body["threshold_count"] = threshold_count if timeout: body["timeout"] = timeout if path: @@ -897,16 +849,13 @@ def create_staged_policy_configuration(self, policy_id, return policy.create_staged_configuration(self.session, policy_id, **body) - def get_staged_policy_configuration(self, policy_id, changes=None): + def get_staged_policy_configuration(self, policy_id): """Retrieve Staged Policy Configuration. :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_staged_configuration(self.session, policy_id, - changes) + return self._get(_policy.Policy, policy_id) def update_staged_policy_configuration(self, policy_id, algorithm=None, persistence=None, @@ -1049,15 +998,13 @@ def create_staged_route_configuration( return route.create_staged_configuration(self.session, route_id, **body) - def get_staged_route_configuration(self, route_id, changes=None): + def get_staged_route_configuration(self, route_id): """Retrieve Staged Route Configuration. :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_staged_configuration(self.session, route_id, changes) + return self._get(_route.Route, route_id) def update_staged_route_configuration( self, route_id, next_hop_ip_address=None): @@ -1178,15 +1125,13 @@ def create_staged_rule_configuration( rule = _rule.Rule() return rule.create_staged_configuration(self.session, rule_id, **body) - def get_staged_rule_configuration(self, rule_id, changes=None): + def get_staged_rule_configuration(self, rule_id): """Retrieve Staged Rule Configuration. :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_staged_configuration(self.session, rule_id, changes) + return self._get(_rule.Rule, rule_id) def update_staged_rule_configuration( self, rule_id, diff --git a/ecl/mvna/v1/base.py b/ecl/mvna/v1/base.py index 060e9ab..4ed140b 100644 --- a/ecl/mvna/v1/base.py +++ b/ecl/mvna/v1/base.py @@ -20,16 +20,6 @@ def create_staged_configuration(self, session, resource_id, **body): self._translate_response(resp, has_body=True) return self - def get_staged_configuration(self, session, resource_id, changes=None): - if changes is not None and type(changes) is bool: - uri = self.base_path + '/%s/staged?changes=%s' % \ - (resource_id, str(changes).lower()) - else: - uri = self.base_path + '/%s/staged' % resource_id - resp = session.get(uri, endpoint_filter=self.service) - 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, diff --git a/ecl/mvna/v1/health_monitor.py b/ecl/mvna/v1/health_monitor.py index ebab422..8e643af 100644 --- a/ecl/mvna/v1/health_monitor.py +++ b/ecl/mvna/v1/health_monitor.py @@ -20,7 +20,6 @@ class HealthMonitor(base.MVNABaseResource): "protocol", "interval", "retry", - "threshold_count", "timeout", "path", "load_balancer_id", @@ -56,8 +55,6 @@ class HealthMonitor(base.MVNABaseResource): interval = resource2.Body('interval') #: Retry count of health monitor retry = resource2.Body('retry') - #: Threshold count of health monitor - threshold_count = resource2.Body('threshold_count') #: Timeout of health monitor timeout = resource2.Body('timeout') #: Path of health monitor diff --git a/ecl/mvna/v1/load_balancer.py b/ecl/mvna/v1/load_balancer.py index d5f7104..49c9e63 100644 --- a/ecl/mvna/v1/load_balancer.py +++ b/ecl/mvna/v1/load_balancer.py @@ -19,7 +19,6 @@ class LoadBalancer(base.MVNABaseResource): "monitoring_status", "operation_status", "availability_zone", - "default_gateway", "revision", "plan_id", "tenant_id" @@ -50,8 +49,6 @@ class LoadBalancer(base.MVNABaseResource): operation_status = resource2.Body('operation_status') #: Availability zones of load balancer availability_zones = resource2.Body('availability_zones') - #: Default gateway of load balancer - default_gateway = resource2.Body('default_gateway') #: Revision of load balancer revision = resource2.Body('revision') #: Plan ID of load balancer diff --git a/ecl/mvna/v1/target_group.py b/ecl/mvna/v1/target_group.py index 919e0c4..fe7ee25 100644 --- a/ecl/mvna/v1/target_group.py +++ b/ecl/mvna/v1/target_group.py @@ -16,7 +16,6 @@ class TargetGroup(base.MVNABaseResource): "description", "configuration_status", "operation_status", - "default_port", "load_balancer_id", "tenant_id" ) @@ -42,8 +41,6 @@ class TargetGroup(base.MVNABaseResource): configuration_status = resource2.Body('configuration_status') #: Operation status of target group operation_status = resource2.Body('operation_status') - #: Default port of target group - default_port = resource2.Body('default_port') #: Load balancer ID of target group load_balancer_id = resource2.Body('load_balancer_id') #: Tenant ID of target group From c949fccc61ddde4dc5d2dfce36f174475e07588e Mon Sep 17 00:00:00 2001 From: shiso Date: Mon, 31 May 2021 12:33:39 +0900 Subject: [PATCH 06/18] IF-5871 fix parameter name (#81) --- ecl/mvna/v1/_proxy.py | 22 +++++++++++----------- ecl/mvna/v1/rule.py | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/ecl/mvna/v1/_proxy.py b/ecl/mvna/v1/_proxy.py index 9845b5a..8dcd26c 100644 --- a/ecl/mvna/v1/_proxy.py +++ b/ecl/mvna/v1/_proxy.py @@ -1035,14 +1035,14 @@ 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, condition, + 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 condition: Condition 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 @@ -1052,7 +1052,7 @@ def create_rule(self, priority, target_group_id, policy_id, condition, 'priority': priority, 'target_group_id': target_group_id, 'policy_id': policy_id, - 'condition': condition + 'conditions': conditions } if name: body["name"] = name @@ -1105,13 +1105,13 @@ def delete_rule(self, rule_id, ignore_missing=False): def create_staged_rule_configuration( self, rule_id, - priority=None, target_group_id=None, condition=None): + 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 condition: Condition of Rule + :param string conditions: Conditions of Rule :return: Rule """ body = {} @@ -1119,8 +1119,8 @@ def create_staged_rule_configuration( body["priority"] = priority if target_group_id: body["target_group_id"] = target_group_id - if condition: - body["condition"] = condition + if conditions: + body["conditions"] = conditions rule = _rule.Rule() return rule.create_staged_configuration(self.session, rule_id, **body) @@ -1135,13 +1135,13 @@ def get_staged_rule_configuration(self, rule_id): def update_staged_rule_configuration( self, rule_id, - priority=None, target_group_id=None, condition=None): + 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 condition: Condition of Rule + :param string conditions: Conditions of Rule :return: Rule """ body = {} @@ -1149,8 +1149,8 @@ def update_staged_rule_configuration( body["priority"] = priority if target_group_id: body["target_group_id"] = target_group_id - if condition: - body["condition"] = condition + if conditions: + body["conditions"] = conditions rule = _rule.Rule() return rule.update_staged_configuration(self.session, rule_id, **body) diff --git a/ecl/mvna/v1/rule.py b/ecl/mvna/v1/rule.py index 5316a8c..3f42b7f 100644 --- a/ecl/mvna/v1/rule.py +++ b/ecl/mvna/v1/rule.py @@ -54,8 +54,8 @@ class Rule(base.MVNABaseResource): load_balancer_id = resource2.Body('load_balancer_id') #: Tenant ID of rule tenant_id = resource2.Body('tenant_id') - #: Condition of rule - condition = resource2.Body('condition') + #: Conditions of rule + conditions = resource2.Body('conditions') #: Current configuration of rule current = resource2.Body('current') #: Staged configuration of rule From 484e47e4a8a51e2b0d59f4350dcc57eef99e8068 Mon Sep 17 00:00:00 2001 From: NaoShark <49853899+NaoShark@users.noreply.github.com> Date: Wed, 16 Jun 2021 09:27:12 +0900 Subject: [PATCH 07/18] Drop MVNA day2 functions (#82) --- ecl/mvna/v1/_proxy.py | 180 +++++++++++++++++++++------------- ecl/mvna/v1/health_monitor.py | 13 ++- ecl/mvna/v1/load_balancer.py | 19 +++- ecl/mvna/v1/plan.py | 15 ++- ecl/mvna/v1/policy.py | 20 ++-- 5 files changed, 161 insertions(+), 86 deletions(-) diff --git a/ecl/mvna/v1/_proxy.py b/ecl/mvna/v1/_proxy.py index 8dcd26c..04a107a 100644 --- a/ecl/mvna/v1/_proxy.py +++ b/ecl/mvna/v1/_proxy.py @@ -20,9 +20,11 @@ def load_balancers(self, **params): 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): + # syslog_servers=None + ): """Create Managed Load Balancer. :param string plan_id: Plan ID of Managed Load Balancer @@ -30,7 +32,7 @@ def create_load_balancer(self, plan_id, interfaces, :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 + # :param list syslog_servers: Syslog Servers of Managed Load Balancer :return: Managed Load Balancer """ body = {"plan_id": plan_id, "interfaces": interfaces} @@ -40,8 +42,8 @@ def create_load_balancer(self, plan_id, interfaces, body["description"] = description if tags: body["tags"] = tags - if syslog_servers: - body["syslog_servers"] = syslog_servers + # 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): @@ -105,20 +107,21 @@ def action_load_balancer(self, load_balancer_id, x_mvna_request_id=None, 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, + # 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 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 syslog_servers: + # body["syslog_servers"] = syslog_servers if interfaces: body["interfaces"] = interfaces @@ -135,20 +138,21 @@ def get_staged_load_balancer_configuration(self, load_balancer_id): """ 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, + # 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 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 syslog_servers: + # body["syslog_servers"] = syslog_servers if interfaces: body["interfaces"] = interfaces @@ -290,6 +294,10 @@ def cancel_staged_target_group_configuration(self, target_group_id): 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( @@ -366,6 +374,7 @@ def upload_certificate(self, body = {'type': certificate_type, 'file': certificate_file} certificate = _certificate.Certificate() certificate.upload(self.session, certificate_id, **body) + ''' def listeners(self, **params): """List Listeners.""" @@ -506,6 +515,9 @@ def cancel_staged_listener_configuration(self, listener_id): 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( @@ -518,6 +530,7 @@ def get_maintenance(self, maintenance_id): :return: Maintenance """ return self._get(_maintenance.Maintenance, maintenance_id) + ''' def plans(self, **params): """List Plans.""" @@ -536,10 +549,13 @@ def health_monitors(self, **params): 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): + # path=None, http_status_code=None + ): """Create Health Monitor. :param string port: Port of Health Monitor @@ -551,8 +567,8 @@ def create_health_monitor(self, port, protocol, load_balancer_id, :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 + # :param string path: Path of Health Monitor + # :param string http_status_code: HTTP Status code of Health Monitor :return: Health Monitor """ @@ -573,10 +589,10 @@ def create_health_monitor(self, port, protocol, load_balancer_id, body["retry"] = retry if timeout: body["timeout"] = timeout - if path: - body["path"] = path - if http_status_code: - body["http_status_code"] = http_status_code + # 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): @@ -624,10 +640,14 @@ def delete_health_monitor(self, health_monitor_id, ignore_missing=False): 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): + timeout=None, + # path=None, http_status_code=None + ): """Create Staged Health Monitor Configuration. :param string health_monitor_id: ID of Health Monitor @@ -636,8 +656,8 @@ def create_staged_health_monitor_configuration( :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 + # :param string path: Path of Health Monitor + # :param string http_status_code: HTTP Status code of Health Monitor :return: Health Monitor """ body = {} @@ -651,10 +671,10 @@ def create_staged_health_monitor_configuration( body["retry"] = retry if timeout: body["timeout"] = timeout - if path: - body["path"] = path - if http_status_code: - body["http_status_code"] = http_status_code + # 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, @@ -669,10 +689,14 @@ def get_staged_health_monitor_configuration(self, health_monitor_id): """ 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): + timeout=None, + # path=None, http_status_code=None + ): """Update Staged Health Monitor Configuration. :param string health_monitor_id: ID of Health Monitor @@ -681,8 +705,8 @@ def update_staged_health_monitor_configuration( :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 + # :param string path: Path of Health Monitor + # :param string http_status_code: HTTP Status code of Health Monitor :return: Health Monitor """ body = {} @@ -696,10 +720,10 @@ def update_staged_health_monitor_configuration( body["retry"] = retry if timeout: body["timeout"] = timeout - if path: - body["path"] = path - if http_status_code: - body["http_status_code"] = http_status_code + # 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, @@ -720,11 +744,15 @@ 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): + 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 @@ -736,9 +764,9 @@ def create_policy(self, health_monitor_id, listener_id, :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 + # :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 = { @@ -757,12 +785,12 @@ def create_policy(self, health_monitor_id, listener_id, 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 + # 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): @@ -806,25 +834,28 @@ def delete_policy(self, policy_id, ignore_missing=False): """ 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, + # sorry_page_url=None, + # certificate_id=None, health_monitor_id=None, listener_id=None, default_target_group_id=None, - tls_security_policy_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 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 + # :param string tls_security_policy_id: TLS Security Policy ID :return: Policy """ body = {} @@ -832,18 +863,18 @@ def create_staged_policy_configuration(self, policy_id, 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 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 + # if tls_security_policy_id: + # body["tls_security_policy_id"] = tls_security_policy_id policy = _policy.Policy() return policy.create_staged_configuration(self.session, @@ -857,25 +888,28 @@ def get_staged_policy_configuration(self, policy_id): """ 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, + # sorry_page_url=None, + # certificate_id=None, health_monitor_id=None, listener_id=None, default_target_group_id=None, - tls_security_policy_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 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 + # :param string tls_security_policy_id: TLS Security Policy ID :return: Policy """ body = {} @@ -883,18 +917,18 @@ def update_staged_policy_configuration(self, policy_id, 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 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 + # if tls_security_policy_id: + # body["tls_security_policy_id"] = tls_security_policy_id policy = _policy.Policy() return policy.update_staged_configuration(self.session, @@ -1031,6 +1065,11 @@ def cancel_staged_route_configuration(self, route_id): 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)) @@ -1163,6 +1202,7 @@ def cancel_staged_rule_configuration(self, rule_id): """ rule = _rule.Rule() rule.cancel_staged_configuration(self.session, rule_id) + ''' def operations(self, **params): """List operations.""" @@ -1177,6 +1217,9 @@ def get_operation(self, operation_id): """ 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( @@ -1190,3 +1233,4 @@ def get_tls_security_policy(self, tls_security_policy_id): """ return self._get( _tls_security_policy.TLSSecurityPolicy, tls_security_policy_id) + ''' diff --git a/ecl/mvna/v1/health_monitor.py b/ecl/mvna/v1/health_monitor.py index 8e643af..5ec6e48 100644 --- a/ecl/mvna/v1/health_monitor.py +++ b/ecl/mvna/v1/health_monitor.py @@ -10,6 +10,8 @@ class HealthMonitor(base.MVNABaseResource): 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", @@ -21,7 +23,8 @@ class HealthMonitor(base.MVNABaseResource): "interval", "retry", "timeout", - "path", + # "path", + # "http_status_code", "load_balancer_id", "tenant_id" ) @@ -57,10 +60,14 @@ class HealthMonitor(base.MVNABaseResource): 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') + # path = resource2.Body('path') #: HTTP status code of health monitor - http_status_code = resource2.Body('http_status_code') + # http_status_code = resource2.Body('http_status_code') + #: Load balancer ID load_balancer_id = resource2.Body('load_balancer_id') #: Tenant ID of health monitor diff --git a/ecl/mvna/v1/load_balancer.py b/ecl/mvna/v1/load_balancer.py index 49c9e63..e5a2438 100644 --- a/ecl/mvna/v1/load_balancer.py +++ b/ecl/mvna/v1/load_balancer.py @@ -18,7 +18,9 @@ class LoadBalancer(base.MVNABaseResource): "configuration_status", "monitoring_status", "operation_status", - "availability_zone", + "primary_availability_zone", + "secondary_availability_zone", + "active_availability_zone", "revision", "plan_id", "tenant_id" @@ -47,16 +49,25 @@ class LoadBalancer(base.MVNABaseResource): monitoring_status = resource2.Body('monitoring_status') #: Operation status of load balancer operation_status = resource2.Body('operation_status') - #: Availability zones of load balancer - availability_zones = resource2.Body('availability_zones') + #: 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') + # syslog_servers = resource2.Body('syslog_servers') + #: Interfaces of load balancer interfaces = resource2.Body('interfaces') #: Current configuration of load balancer diff --git a/ecl/mvna/v1/plan.py b/ecl/mvna/v1/plan.py index 59ab5b2..34fac48 100644 --- a/ecl/mvna/v1/plan.py +++ b/ecl/mvna/v1/plan.py @@ -10,10 +10,13 @@ class Plan(resource2.Resource): 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", @@ -21,8 +24,8 @@ class Plan(resource2.Resource): "max_number_of_policies", "max_number_of_routes", "max_number_of_target_groups", - "max_number_of_rules", - "max_number_of_conditions", + # "max_number_of_rules", + # "max_number_of_conditions", "max_number_of_members", "enabled" ) @@ -59,10 +62,14 @@ class Plan(resource2.Resource): 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_rules = resource2.Body('max_number_of_rules') #: Max number of conditions - max_number_of_conditions = resource2.Body('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 diff --git a/ecl/mvna/v1/policy.py b/ecl/mvna/v1/policy.py index 2f44ddc..8eb6639 100644 --- a/ecl/mvna/v1/policy.py +++ b/ecl/mvna/v1/policy.py @@ -10,6 +10,8 @@ class Policy(base.MVNABaseResource): 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", @@ -18,12 +20,12 @@ class Policy(base.MVNABaseResource): "operation_status", "algorithm", "persistence", - "sorry_page_url", - "certificate_id", + # "sorry_page_url", + # "certificate_id", "health_monitor_id", "listener_id", "default_target_group_id", - "tls_protocol", + # "tls_security_policy_id", "load_balancer_id", "tenant_id" ) @@ -53,18 +55,22 @@ class Policy(base.MVNABaseResource): 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') + # sorry_page_url = resource2.Body('sorry_page_url') #: Certificate ID of policy - certificate_id = resource2.Body('certificate_id') + # 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') - #: TLS security policy ID of policy - tls_security_policy_id = resource2.Body('tls_security_policy_id') #: Load balancer ID of policy load_balancer_id = resource2.Body('load_balancer_id') #: Tenant ID of policy From 7ec745d7b2bf83962d39f9757d167c5c554106ae Mon Sep 17 00:00:00 2001 From: NaoShark <49853899+NaoShark@users.noreply.github.com> Date: Wed, 7 Jul 2021 10:43:36 +0900 Subject: [PATCH 08/18] Delete database and object functions (#83) * Delete database and object sub-command * Delete related files --- ecl/database/__init__.py | 0 ecl/database/database_service.py | 24 -- ecl/database/exceptions.py | 13 - ecl/database/v1/__init__.py | 0 ecl/database/v1/_proxy.py | 332 ------------------ ecl/database/v1/database.py | 48 --- ecl/database/v1/datastore.py | 39 -- ecl/database/v1/flavor.py | 53 --- ecl/database/v1/instance.py | 141 -------- ecl/database/v1/user.py | 71 ---- ecl/database/version.py | 55 --- ecl/object_store/__init__.py | 0 ecl/object_store/object_store_service.py | 24 -- ecl/object_store/v1/__init__.py | 0 ecl/object_store/v1/_base.py | 86 ----- ecl/object_store/v1/_proxy.py | 323 ----------------- ecl/object_store/v1/account.py | 42 --- ecl/object_store/v1/container.py | 165 --------- ecl/object_store/v1/obj.py | 234 ------------ ecl/profile.py | 10 +- ecl/tests/functional/object_store/__init__.py | 0 .../functional/object_store/v1/__init__.py | 0 .../object_store/v1/test_account.py | 79 ----- .../object_store/v1/test_container.py | 134 ------- .../functional/object_store/v1/test_obj.py | 154 -------- .../functional/telemetry/v2/test_meter.py | 32 -- ecl/tests/unit/object_store/__init__.py | 0 .../object_store/test_object_store_service.py | 28 -- ecl/tests/unit/object_store/v1/__init__.py | 0 .../unit/object_store/v1/test_account.py | 56 --- .../unit/object_store/v1/test_container.py | 171 --------- ecl/tests/unit/object_store/v1/test_obj.py | 137 -------- ecl/tests/unit/object_store/v1/test_proxy.py | 277 --------------- 33 files changed, 1 insertion(+), 2727 deletions(-) delete mode 100755 ecl/database/__init__.py delete mode 100755 ecl/database/database_service.py delete mode 100755 ecl/database/exceptions.py delete mode 100755 ecl/database/v1/__init__.py delete mode 100755 ecl/database/v1/_proxy.py delete mode 100755 ecl/database/v1/database.py delete mode 100644 ecl/database/v1/datastore.py delete mode 100755 ecl/database/v1/flavor.py delete mode 100755 ecl/database/v1/instance.py delete mode 100755 ecl/database/v1/user.py delete mode 100755 ecl/database/version.py delete mode 100755 ecl/object_store/__init__.py delete mode 100755 ecl/object_store/object_store_service.py delete mode 100755 ecl/object_store/v1/__init__.py delete mode 100755 ecl/object_store/v1/_base.py delete mode 100755 ecl/object_store/v1/_proxy.py delete mode 100755 ecl/object_store/v1/account.py delete mode 100755 ecl/object_store/v1/container.py delete mode 100755 ecl/object_store/v1/obj.py delete mode 100755 ecl/tests/functional/object_store/__init__.py delete mode 100755 ecl/tests/functional/object_store/v1/__init__.py delete mode 100755 ecl/tests/functional/object_store/v1/test_account.py delete mode 100755 ecl/tests/functional/object_store/v1/test_container.py delete mode 100755 ecl/tests/functional/object_store/v1/test_obj.py delete mode 100755 ecl/tests/functional/telemetry/v2/test_meter.py delete mode 100755 ecl/tests/unit/object_store/__init__.py delete mode 100755 ecl/tests/unit/object_store/test_object_store_service.py delete mode 100755 ecl/tests/unit/object_store/v1/__init__.py delete mode 100755 ecl/tests/unit/object_store/v1/test_account.py delete mode 100755 ecl/tests/unit/object_store/v1/test_container.py delete mode 100755 ecl/tests/unit/object_store/v1/test_obj.py delete mode 100755 ecl/tests/unit/object_store/v1/test_proxy.py diff --git a/ecl/database/__init__.py b/ecl/database/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/ecl/database/database_service.py b/ecl/database/database_service.py deleted file mode 100755 index 3818dd1..0000000 --- a/ecl/database/database_service.py +++ /dev/null @@ -1,24 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from ecl import service_filter - - -class DatabaseService(service_filter.ServiceFilter): - """Database(Trove) service""" - - valid_versions = [service_filter.ValidVersion('v1')] - - def __init__(self, version=None): - """Create a Database(Trove) service""" - super(DatabaseService, self).__init__(service_type='rdb', - version=version) diff --git a/ecl/database/exceptions.py b/ecl/database/exceptions.py deleted file mode 100755 index 78d6906..0000000 --- a/ecl/database/exceptions.py +++ /dev/null @@ -1,13 +0,0 @@ -""" -Exception definitions for RDatabase. -""" -import json -from ecl import exceptions - - -class HttpException(exceptions.HttpException): - pass - - -class NotFoundException(HttpException): - pass diff --git a/ecl/database/v1/__init__.py b/ecl/database/v1/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/ecl/database/v1/_proxy.py b/ecl/database/v1/_proxy.py deleted file mode 100755 index 8c353ff..0000000 --- a/ecl/database/v1/_proxy.py +++ /dev/null @@ -1,332 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from ecl.database.v1 import instance as _instance -from ecl.database.v1 import user as _user -from ecl.database.v1 import database as _database -from ecl.database.v1 import flavor as _flavor -from ecl.database.v1 import datastore as _datastore - -from ecl import proxy2 -from ecl import resource2 - - -class Proxy(proxy2.BaseProxy): - - def instances(self, **query): - """Retrieve a list of instances - - :param kwargs \*\*query: Optional query parameters to be sent to limit - the instances being returned. - :returns: A list of database instances. - """ - instance = _instance.Instance - return list(self._list(instance, paginated=False, **query)) - - def create_instance(self, - name, - flavor_id, - volume, - datastore, - nics, - databases=None, - users=None, - availability_zone=None, - backup_window=None, - backup_retention_period=None, - restore_point=None, - maintenance_window=None, - **attrs): - """Create a new instance from attributes - - :param string name: Name of instance - :param string flavor_id: Flavor ID of server - :param dict volue: Volume configuration dict which has volume_size inside - :param databases: Database definition - list to initialize database on creating instance - :param users: List of users to connect to defined databases - :param dict datastore: Datastore name and version of instance - :param dict nics: Network difinition of instance - :param availability_zone: Availability zone for instance - :param backup_window: Backup window time range - :param backup_retention_period: Number of the day to retain backup - :param maintenance_window: Maintenance window time range by - the day of the week and from/to time - :param kwargs attrs: Keyword arguments which will be used to create - a :class:`~ecl.datagase.v1.instance.Instance`, - comprised of the properties on the Instance class. - - :returns: The results of instance creation - :rtype: :class:`~ecl.compute.v1.instance.Instance` - """ - attrs.update({"name": name}) - attrs.update({"flavorRef": flavor_id}) - attrs.update({"volume": volume}) - attrs.update({"datastore": datastore}) - attrs.update({"nics": nics}) - - if databases: - attrs.update({"databases": databases}) - if users: - attrs.update({"users": users}) - if availability_zone: - attrs.update({"availability_zone": availability_zone}) - if backup_window: - attrs.update({"backup_window": backup_window}) - if backup_retention_period or backup_retention_period == 0: - attrs.update({"backup_retention_period": backup_retention_period}) - if restore_point: - attrs.update({"restorePoint": restore_point}) - if maintenance_window: - attrs.update({"maintenance_window": maintenance_window}) - - return self._create(_instance.Instance, **attrs) - - def delete_instance(self, instance, ignore_missing=False): - """Delete a instance - - :param instance: The value can be either the ID of a server or a - :class:`~ecl.database.v1.instance.Instance` instance. - :param bool ignore_missing: When set to ``False`` - :class:`~ecl.exceptions.ResourceNotFound` will be - raised when the server does not exist. - When set to ``True``, no exception will be set when - attempting to delete a nonexistent instance - :param bool force: When set to ``True``, the instance deletion will be - forced immediatly. - - :returns: ``None`` - """ - self._delete(_instance.Instance, instance, ignore_missing=ignore_missing) - - def find_instance(self, name_or_id, ignore_missing=False): - """Find a single instance - - :param name_or_id: The name or ID of a server. - :param bool ignore_missing: When set to ``False`` - :class:`~ecl.exceptions.ResourceNotFound` will be - raised when the resource does not exist. - When set to ``True``, None will be returned when - attempting to find a nonexistent resource. - :returns: One :class:`~ecl.database.v1.instance.Instance` or None - """ - return self._find(_instance.Instance, name_or_id, - ignore_missing=ignore_missing) - - def get_instance(self, instance): - """Get a single instance - - :param instance: The value can be the ID of a instance or a - :class:`~ecl.database.v1.instance.Instance` instance. - - :returns: One :class:`~ecl.database.v1.instance.Instance` - :raises: :class:`~ecl.exceptions.ResourceNotFound` - when no resource can be found. - """ - return self._get(_instance.Instance, instance) - - def wait_for_server(self, instance, status='ACTIVE', failures=['ERROR'], - interval=2, wait=120): - return resource2.wait_for_status(self.session, instance, status, - failures, interval, wait) - - # def find_flavor(self, name_or_id, ignore_missing=False): - # """Find a single flavor - - # :param name_or_id: The name or ID of a flavor. - # :param bool ignore_missing: When set to ``False`` - # :class:`~ecl.exceptions.ResourceNotFound` will be - # raised when the resource does not exist. - # When set to ``True``, None will be returned when - # attempting to find a nonexistent resource. - # :returns: One :class:`~ecl.database.v1.flavor.Flavor` or None - # """ - # return self._find(_flavor.Flavor, name_or_id, - # ignore_missing=ignore_missing) - - # def get_flavor(self, flavor): - # """Get a single flavor - - # :param flavor: The value can be the ID of a flavor or a - # :class:`~ecl.database.v1.flavor.Flavor` instance. - - # :returns: One :class:`~ecl.database.v1.flavor.Flavor` - # :raises: :class:`~ecl.exceptions.ResourceNotFound` - # when no resource can be found. - # """ - # return self._get(_flavor.Flavor, flavor) - - def flavors(self): - """Return a list of flavors - :returns: A list of flavor objects - """ - return list(self._list(_flavor.Flavor, paginated=False)) - - def datastores(self): - """Return a list of datastores - :returns: A list of datastore objects - """ - return list(self._list(_datastore.Datastore, paginated=False)) - - def users(self, instance_id, **query): - """Retrieve a list of users assciated with instance - - :param instance_id: Instance id to find users - :param kwargs \*\*query: Optional query parameters to be sent to limit - the instances being returned. Available parameters include: - :returns: A list of database instances. - """ - user = _user.User - return list(self._list(user, paginated=False, instance_id=instance_id, **query)) - - def create_user(self, instance_id, name, password, databases=None): - """Create a new user from attributes - - :param string instance_id: ID of instance to assciate creating user - :param string name: Name of user - :param string password: Password of user - :param databases: Database list of user to grant - - :returns: ``None`` - """ - attrs = {"name": name, - "password": password} - if databases: - attrs.update({"databases": databases}) - user = _user.User() - return user.create(self.session, instance_id, **attrs) - - def delete_user(self, instance_id, user, ignore_missing=False): - """Delete a user - - :param instance_id: The value can be either the ID of a server or a - :class:`~ecl.database.v1.instance.Instance` instance. - :param string user: Name of user. - :param bool ignore_missing: When set to ``False`` - :class:`~ecl.exceptions.ResourceNotFound` will be - raised when the resource does not exist. - When set to ``True``, no exception will be set when - attempting to delete a nonexistent user - - :returns: ``None`` - """ - self._delete(_user.User, user, instance_id=instance_id, - ignore_missing=ignore_missing) - - def find_user(self, instance_id, name_or_id, ignore_missing=False): - """Find a single user - - :param name_or_id: The name or ID of a user. - :param bool ignore_missing: When set to ``False`` - :class:`~ecl.exceptions.ResourceNotFound` will be - raised when the resource does not exist. - When set to ``True``, None will be returned when - attempting to find a nonexistent resource. - :returns: One :class:`~ecl.database.v1.user.User` or None - """ - return self._find(_user.User, name_or_id, - instance_id=instance_id, - ignore_missing=ignore_missing) - - def get_user(self, instance_id, user): - """Show a user - - :param instance_id: The value can be either the ID of a server or a - :class:`~ecl.database.v1.instance.Instance` instance. - :param string user: Name of user. - :returns: One user. - :rtype: :class:`~ecl.compute.v1.user.User` - """ - return self._get(_user.User, user, instance_id=instance_id) - - def grant_user(self, instance_id, user_name, databases): - """Grants database access privilege to user in DB Instance. - - :param instance_id: The value can be either the ID of a server or a - :class:`~ecl.database.v1.instance.Instance` instance. - :param string user: Name of user. - :param array databases: Database names to grant access privilege. - :returns: ``None`` - """ - user = _user.User() - return user.grant(self.session, instance_id, user_name, databases) - - def revoke_user(self, instance_id, user_name, database): - """Revoke the access privilege of user from database in DB Instance. - - :param instance_id: The value can be either the ID of a server or a - :class:`~ecl.database.v1.instance.Instance` instance. - :param string user: Name of user. - :param string database: Database name to revoke access privilege. - :returns: ``None`` - """ - user = _user.User() - return user.revoke(self.session, instance_id, user_name, database) - - def databases(self, instance_id, **query): - """Retrieve a list of databases assciated with instance - - :param instance_id: Instance id to find databases - :param kwargs \*\*query: Optional query parameters to be sent to limit - the instances being returned. Available parameters include: - :returns: A list of database instances. - """ - database = _database.Database - return list(self._list(database, paginated=False, - instance_id=instance_id, **query)) - - def create_database(self, instance_id, name, charset=None, collate=None): - """Create a new database from attributes - - :param string instance_id: ID of instance to assciate creating database - :param string name: Name of database - - :returns: ``None`` - """ - attrs = {"name": name} - if charset: - attrs.update({"character_set": charset}) - if collate: - attrs.update({"collate": collate}) - database = _database.Database() - return database.create(self.session, instance_id, **attrs) - - def delete_database(self, instance_id, database, ignore_missing=False): - """Delete a database - - :param instance_id: The value can be either the ID of a server or a - :class:`~ecl.database.v1.instance.Instance` instance. - :param bool ignore_missing: When set to ``False`` - :class:`~ecl.exceptions.ResourceNotFound` will be - raised when the resource does not exist. - When set to ``True``, no exception will be set when - attempting to delete a nonexistent database - - :returns: ``None`` - """ - self._delete(_database.Database, database, instance_id=instance_id, - ignore_missing=ignore_missing) - - def find_database(self, instance_id, name_or_id, ignore_missing=False): - """Find a single database - - :param name_or_id: The name or ID of a database. - :param bool ignore_missing: When set to ``False`` - :class:`~ecl.exceptions.ResourceNotFound` will be - raised when the resource does not exist. - When set to ``True``, None will be returned when - attempting to find a nonexistent resource. - :returns: One :class:`~ecl.database.v1.database.Database` or None - """ - return self._find(_database.Database, name_or_id, - instance_id=instance_id, - ignore_missing=ignore_missing) diff --git a/ecl/database/v1/database.py b/ecl/database/v1/database.py deleted file mode 100755 index 026ff68..0000000 --- a/ecl/database/v1/database.py +++ /dev/null @@ -1,48 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from ecl.database import database_service -from ecl import resource2 -from ecl import exceptions - - -class Database(resource2.Resource): - resource_key = "database" - resources_key = "databases" - base_path = '/instances/%(instance_id)s/databases' - service = database_service.DatabaseService() - - # Capabilities - allow_create = True - allow_delete = True - allow_list = True - - allow_update = False - allow_get = False - - # Properties - #: Name of Database. - name = resource2.Body('name', alternate_id=True) - #: Character set of Database. - character_set = resource2.Body('character_set') - #: Collate of Database. - collate = resource2.Body('collate') - #: ID of instance associated with this database - instance_id = resource2.URI('instance_id') - - def create(self, session, instance_id, **attrs): - base = self.base_path % {"instance_id": instance_id} - body = {"databases": [attrs]} - resp = session.post(base, endpoint_filter=self.service, json=body, - headers={"Accept": "application/json"}) - self._translate_response(resp, has_body=False) - return self diff --git a/ecl/database/v1/datastore.py b/ecl/database/v1/datastore.py deleted file mode 100644 index 852eb58..0000000 --- a/ecl/database/v1/datastore.py +++ /dev/null @@ -1,39 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from ecl.database import database_service -from ecl import resource2 - - -class Datastore(resource2.Resource): - resource_key = None - resources_key = 'datastores' - base_path = '/datastores' - service = database_service.DatabaseService() - - # capabilities - allow_list = True - - _query_mapping = resource2.QueryParameters() - - # Properties - #: The ID of this datastore - id = resource2.Body('id') - #: The name of this datastore. - name = resource2.Body('name') - #: Size of the disk this datastore offers. *Type: int* - default_version = resource2.Body('default_version') - #: The amount of RAM (in MB) this datastore offers. *Type: int* - versions = resource2.Body('versions') - #: Links pertaining to this datastore. This is a list of dictionaries, - #: each including keys ``href`` and ``rel``. - links = resource2.Body('links') diff --git a/ecl/database/v1/flavor.py b/ecl/database/v1/flavor.py deleted file mode 100755 index c46b5f4..0000000 --- a/ecl/database/v1/flavor.py +++ /dev/null @@ -1,53 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from ecl.database import database_service -from ecl import resource2 - - -class Flavor(resource2.Resource): - resource_key = 'flavor' - resources_key = 'flavors' - base_path = '/flavors' - service = database_service.DatabaseService() - - # capabilities - allow_get = True - allow_list = True - - _query_mapping = resource2.QueryParameters() - - # Properties - #: Links pertaining to this flavor. This is a list of dictionaries, - #: each including keys ``href`` and ``rel``. - links = resource2.Body('links') - #: The name of this flavor. - name = resource2.Body('name') - #: Size of the disk this flavor offers. *Type: int* - disk = resource2.Body('disk', type=int) - #: ``True`` if this is a publicly visible flavor. ``False`` if this is - #: a private image. *Type: bool* - is_public = resource2.Body('os-flavor-access:is_public', type=bool) - #: The amount of RAM (in MB) this flavor offers. *Type: int* - ram = resource2.Body('ram', type=int) - #: The number of virtual CPUs this flavor offers. *Type: int* - vcpus = resource2.Body('vcpus', type=int) - #: Size of the swap partitions. - swap = resource2.Body('swap') - #: Size of the ephemeral data disk attached to this server. *Type: int* - ephemeral = resource2.Body('ephemeral', type=int) - #: ``True`` if this flavor is disabled, ``False`` if not. *Type: bool* - is_disabled = resource2.Body('OS-FLV-DISABLED:disabled', type=bool) - #: The bandwidth scaling factor this flavor receives on the network. - rxtx_factor = resource2.Body('rxtx_factor', type=float) - #: ID - str_id = resource2.Body('str_id', alternate_id=True) diff --git a/ecl/database/v1/instance.py b/ecl/database/v1/instance.py deleted file mode 100755 index be8d57d..0000000 --- a/ecl/database/v1/instance.py +++ /dev/null @@ -1,141 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from ecl.database import database_service - -from ecl import exceptions -from ecl import resource2 -from ecl import utils - - -class Instance(resource2.Resource): - resource_key = 'instance' - resources_key = 'instances' - base_path = '/instances' - service = database_service.DatabaseService() - - # capabilities - allow_create = True - allow_get = True - allow_delete = True - allow_list = True - - allow_update = False - - _query_mapping = resource2.QueryParameters() - - #: ID of the server - id = resource2.Body('id') - - #: Timestamp of when the instance was created. - created_at = resource2.Body('created') - - #: The datastore property returned as instence property. - datastore = resource2.Body('datastore', type=dict) - - #: The flavor property returned from instance. - flavor = resource2.Body('flavor', type=dict) - - #: The flavor reference, as a ID or full URL, - #: in case create instane. - flavor_id = resource2.Body('flavorRef') - - #: An ID representing the host of this instance. - hostname = resource2.Body('hostname') - - #: A list of dictionaries holding links relevant to this instance. - links = resource2.Body('links', type=list) - - #: Name of the instance - name = resource2.Body('name') - - #: Region of the instance - region = resource2.Body('region') - - #: The state this instance is in. - status = resource2.Body('status') - - #: Timestamp of when this instance was last updated. - updated_at = resource2.Body('updated') - - #: The volume property returned from instance. - volume = resource2.Body('volume', type=dict) - - #: A nic definition object. Required parameter when there are multiple - #: networks defined for the tenant. - nics = resource2.Body('nics', type=dict) - - #: Databases list of instance. - databases = resource2.Body('databases', type=list) - - #: Users list of instance. - users = resource2.Body('users', type=list) - - #: Backup window of instance. - backup_window = resource2.Body('backup_window') - - #: Maintenance window of instance. - maintenance_window = resource2.Body('maintenance_window') - - #: Backup retension period of this instance. - backup_retention_period = resource2.Body('backup_retention_period', - type=int) - - #: Restore Point - restore_point = resource2.Body('restorePoint', type=dict) - - #: Restoreable Time - restorable_time = resource2.Body('restorable_time') - - #: Endpoints - endpoints = resource2.Body('endpoints', type=list) - - #: Availability Zone - availability_zone = resource2.Body('availability_zone') - - @classmethod - def find(cls, session, name_or_id, ignore_missing=False, **params): - """Find a resource by its name or id. - - :param session: The session to use for making this request. - :type session: :class:`~ecl.session.Session` - :param name_or_id: This resource's identifier, if needed by - the request. The default is ``None``. - :param bool ignore_missing: When set to ``False`` - :class:`~ecl.exceptions.ResourceNotFound` will be - raised when the resource does not exist. - When set to ``True``, None will be returned when - attempting to find a nonexistent resource. - :param dict params: Any additional parameters to be passed into - underlying methods, such as to - :meth:`~ecl.resource2.Resource.existing` - in order to pass on URI parameters. - - :return: The :class:`Resource` object matching the given name or id - or None if nothing matches. - :raises: :class:`ecl.exceptions.DuplicateResource` if more - than one resource is found for this request. - :raises: :class:`ecl.exceptions.ResourceNotFound` if nothing - is found and ignore_missing is ``False``. - """ - # Try to short-circuit by looking directly for a matching ID. - - data = cls.list(session, **params) - - result = cls._get_one_match(name_or_id, data) - if result is not None: - return result - - if ignore_missing: - return None - raise exceptions.ResourceNotFound( - "No %s found for %s" % (cls.__name__, name_or_id)) diff --git a/ecl/database/v1/user.py b/ecl/database/v1/user.py deleted file mode 100755 index d1a8f23..0000000 --- a/ecl/database/v1/user.py +++ /dev/null @@ -1,71 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from ecl.database import database_service -from ecl import resource2 -from ecl import exceptions - - -class User(resource2.Resource): - resource_key = "user" - resources_key = "users" - base_path = '/instances/%(instance_id)s/users' - service = database_service.DatabaseService() - - # _query_mapping = resource2.QueryParameters() - - # Capabilities - allow_create = True - allow_delete = True - allow_list = True - allow_update = True - allow_get = True - - # Properties - #: User's name of Database instance. - name = resource2.Body('name', alternate_id=True) - - #: Allowed access host of user. - host = resource2.Body('host') - - #: Relevant database of this user. - databases = resource2.Body('databases', type=list) - - #: User's password of Database instance. - #: This parameter is only used in instance creation. - password = resource2.Body('password') - - #: ID of instance associated with this user - instance_id = resource2.URI('instance_id') - - def create(self, session, instance_id, **attrs): - base = self.base_path % {"instance_id": instance_id} - body = {"users": [attrs]} - resp = session.post(base, endpoint_filter=self.service, json=body, - headers={"Accept": "application/json"}) - self._translate_response(resp, has_body=False) - return self - - def grant(self, session, instance_id, user, databases): - base = self.base_path % {"instance_id": instance_id} - uri = "%s/%s/databases" % (base, user) - resp = session.put(uri, endpoint_filter=self.service, - json={"databases": databases}) - self._translate_response(resp, has_body=False) - return self - - def revoke(self, session, instance_id, user, database): - base = self.base_path % {"instance_id": instance_id} - uri = uri = "%s/%s/databases/%s" % (base, user, database) - resp = session.delete(uri, endpoint_filter=self.service) - self._translate_response(resp, has_body=False) - return self diff --git a/ecl/database/version.py b/ecl/database/version.py deleted file mode 100755 index 4ce2c51..0000000 --- a/ecl/database/version.py +++ /dev/null @@ -1,55 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from ecl.database import database_service -from ecl import resource2 - - -class Version(resource2.Resource): - resource_key = 'version' - resources_key = 'versions' - base_path = '' - service = database_service.DatabaseService( - version=database_service.DatabaseService.UNVERSIONED - ) - - # capabilities - allow_list = True - allow_get = True - - # Properties - #: Version identifier included in API URL. - id = resource2.Body('id') - #: List of API endpoint link. - links = resource2.Body('links') - #: Version support status. Valid values are CURRENT or SUPPORTED. - #: CURRENT is newest stable version. SUPPORTED is old supported version. - status = resource2.Body('status') - - def get_version(self, session): - url = self.base_path + '/v1.0' - resp = session.get( - url, headers={"Accept": "application/json"}, endpoint_filter=self.service - ) - self._translate_response(resp, has_body=True) - return self - - def list_version(self, session): - url = self.base_path - resp = session.get( - url, headers={"Accept": "application/json"}, endpoint_filter=self.service - ) - resp = resp.json()[self.resources_key] - - for data in resp: - version = self.existing(**data) - yield version \ No newline at end of file diff --git a/ecl/object_store/__init__.py b/ecl/object_store/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/ecl/object_store/object_store_service.py b/ecl/object_store/object_store_service.py deleted file mode 100755 index 14f272c..0000000 --- a/ecl/object_store/object_store_service.py +++ /dev/null @@ -1,24 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from ecl import service_filter - - -class ObjectStoreService(service_filter.ServiceFilter): - """The object store service.""" - - valid_versions = [service_filter.ValidVersion('v1')] - - def __init__(self, version=None): - """Create an object store service.""" - super(ObjectStoreService, self).__init__(service_type='object-store', - version=version) diff --git a/ecl/object_store/v1/__init__.py b/ecl/object_store/v1/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/ecl/object_store/v1/_base.py b/ecl/object_store/v1/_base.py deleted file mode 100755 index 57844ca..0000000 --- a/ecl/object_store/v1/_base.py +++ /dev/null @@ -1,86 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may - -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from ecl.object_store import object_store_service -from ecl import resource - - -class BaseResource(resource.Resource): - service = object_store_service.ObjectStoreService() - - #: Metadata stored for this resource. *Type: dict* - metadata = dict() - - _custom_metadata_prefix = None - _system_metadata = dict() - - def _calculate_headers(self, metadata): - headers = dict() - for key in metadata: - if key in self._system_metadata: - header = self._system_metadata[key] - else: - header = self._custom_metadata_prefix + key - headers[header] = metadata[key] - return headers - - def set_metadata(self, session, metadata): - url = self._get_url(self, self.id) - session.post(url, endpoint_filter=self.service, - headers=self._calculate_headers(metadata)) - - def delete_metadata(self, session, keys): - url = self._get_url(self, self.id) - headers = {key: '' for key in keys} - session.post(url, endpoint_filter=self.service, - headers=self._calculate_headers(headers)) - - def _set_metadata(self): - self.metadata = dict() - headers = self.get_headers() - - for header in headers: - if header.startswith(self._custom_metadata_prefix): - key = header[len(self._custom_metadata_prefix):].lower() - self.metadata[key] = headers[header] - - def get(self, session, include_headers=False, args=None): - super(BaseResource, self).get(session, include_headers, args) - self._set_metadata() - return self - - def head(self, session): - super(BaseResource, self).head(session) - self._set_metadata() - return self - - @classmethod - def update_by_id(cls, session, resource_id, attrs, path_args=None): - """Update a Resource with the given attributes. - - :param session: The session to use for making this request. - :type session: :class:`~ecl.session.Session` - :param resource_id: This resource's identifier, if needed by - the request. The default is ``None``. - :param dict attrs: The attributes to be sent in the body - of the request. - :param dict path_args: This parameter is sent by the base - class but is ignored for this method. - - :return: A ``dict`` representing the response headers. - """ - url = cls._get_url(None, resource_id) - headers = attrs.get(resource.HEADERS, dict()) - headers['Accept'] = '' - return session.post(url, endpoint_filter=cls.service, - headers=headers).headers diff --git a/ecl/object_store/v1/_proxy.py b/ecl/object_store/v1/_proxy.py deleted file mode 100755 index bd4addd..0000000 --- a/ecl/object_store/v1/_proxy.py +++ /dev/null @@ -1,323 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from ecl.object_store.v1 import account as _account -from ecl.object_store.v1 import container as _container -from ecl.object_store.v1 import obj as _obj -from ecl import proxy - - -class Proxy(proxy.BaseProxy): - - def get_account_metadata(self): - """Get metadata for this account. - - :rtype: - :class:`~ecl.object_store.v1.account.Account` - """ - return self._head(_account.Account) - - def set_account_metadata(self, **metadata): - """Set metadata for this account. - - :param kwargs metadata: Key/value pairs to be set as metadata - on the container. Custom metadata can be set. - Custom metadata are keys and values defined - by the user. - """ - account = self._get_resource(_account.Account, None) - account.set_metadata(self.session, metadata) - - def delete_account_metadata(self, keys): - """Delete metadata for this account. - - :param keys: The keys of metadata to be deleted. - """ - account = self._get_resource(_account.Account, None) - account.delete_metadata(self.session, keys) - - def containers(self, **query): - """Obtain Container objects for this account. - - :param kwargs query: Optional query parameters to be sent to limit - the resources being returned. - - :rtype: A generator of - :class:`~ecl.object_store.v1.container.Container` objects. - """ - return list(_container.Container.list(self.session, **query)) - - def create_container(self, **attrs): - """Create a new container from attributes - - :param dict attrs: Keyword arguments which will be used to create - a :class:`~ecl.object_store.v1.container.Container`, - comprised of the properties on the Container class. - - :returns: The results of container creation - :rtype: :class:`~ecl.object_store.v1.container.Container` - """ - return self._create(_container.Container, **attrs) - - def delete_container(self, container, ignore_missing=False): - """Delete a container - - :param container: The value can be either the name of a container or a - :class:`~ecl.object_store.v1.container.Container` - instance. - :param bool ignore_missing: When set to ``False`` - :class:`~ecl.exceptions.ResourceNotFound` will be - raised when the container does not exist. - When set to ``True``, no exception will be set when - attempting to delete a nonexistent server. - - :returns: ``None`` - """ - self._delete(_container.Container, container, - ignore_missing=ignore_missing) - - def get_container_metadata(self, container): - """Get metadata for a container - - :param container: The value can be the name of a container or a - :class:`~ecl.object_store.v1.container.Container` - instance. - - :returns: One :class:`~ecl.object_store.v1.container.Container` - :raises: :class:`~ecl.exceptions.ResourceNotFound` - when no resource can be found. - """ - container = self._head(_container.Container, container) - container.count = container.object_count - container.size = container.bytes_used - return container - - def set_container_metadata(self, container, **metadata): - """Set metadata for a container. - - :param container: The value can be the name of a container or a - :class:`~ecl.object_store.v1.container.Container` - instance. - :param kwargs metadata: Key/value pairs to be set as metadata - on the container. Both custom and system - metadata can be set. Custom metadata are keys - and values defined by the user. System - metadata are keys defined by the Object Store - and values defined by the user. The system - metadata keys are: - - - `content_type` - - `is_content_type_detected` - - `versions_location` - - `read_ACL` - - `write_ACL` - - `sync_to` - - `sync_key` - """ - res = self._get_resource(_container.Container, container) - res.set_metadata(self.session, metadata) - - def delete_container_metadata(self, container, keys): - """Delete metadata for a container. - - :param container: The value can be the ID of a container or a - :class:`~ecl.object_store.v1.container.Container` - instance. - :param keys: The keys of metadata to be deleted. - """ - res = self._get_resource(_container.Container, container) - res.delete_metadata(self.session, keys) - - def objects(self, container, **query): - """Return a generator that yields the Container's objects. - - :param container: A container object or the name of a container - that you want to retrieve objects from. - :type container: - :class:`~ecl.object_store.v1.container.Container` - :param kwargs \*\*query: Optional query parameters to be sent to limit - the resources being returned. - - :rtype: A generator of - :class:`~ecl.object_store.v1.obj.Object` objects. - """ - container = _container.Container.from_id(container) - - objs = _obj.Object.list(self.session, - path_args={"container": container.name}, - **query) - objs = list(objs) - for i in range(len(objs)): - objs[i].container = container.name - - return objs - - def _get_container_name(self, obj, container): - if isinstance(obj, _obj.Object): - if obj.container is not None: - return obj.container - if container is not None: - container = _container.Container.from_id(container) - return container.name - - raise ValueError("container must be specified") - - def get_object(self, obj, container=None): - """Get the data associated with an object - - :param obj: The value can be the name of an object or a - :class:`~ecl.object_store.v1.obj.Object` instance. - :param container: The value can be the name of a container or a - :class:`~ecl.object_store.v1.container.Container` - instance. - - :returns: The contents of the object. Use the - :func:`~get_object_metadata` - method if you want an object resource. - :raises: :class:`~ecl.exceptions.ResourceNotFound` - when no resource can be found. - """ - # TODO(briancurtin): call this download_object and make sure it's - # just returning the raw data, like download_image does - container_name = self._get_container_name(obj, container) - - return self._get(_obj.Object, obj, - path_args={"container": container_name}) - - def download_object(self, obj, container=None, path=None): - """Download the data contained inside an object to disk. - - :param obj: The value can be the name of an object or a - :class:`~ecl.object_store.v1.obj.Object` instance. - :param container: The value can be the name of a container or a - :class:`~ecl.object_store.v1.container.Container` - instance. - :param path str: Location to write the object contents. - - :raises: :class:`~ecl.exceptions.ResourceNotFound` - when no resource can be found. - """ - # TODO(briancurtin): download_object should really have the behavior - # of get_object, and this writing to a file should not exist. - # TODO(briancurtin): This method should probably offload the get - # operation into another thread or something of that nature. - with open(path, "w") as out: - out.write(self.get_object(obj, container)) - - def upload_object(self, **attrs): - """Upload a new object from attributes - - :param dict attrs: Keyword arguments which will be used to create - a :class:`~ecl.object_store.v1.obj.Object`, - comprised of the properties on the Object class. - **Required**: A `container` argument must be specified, - which is either the ID of a container or a - :class:`~ecl.object_store.v1.container.Container` - instance. - - :returns: The results of object creation - :rtype: :class:`~ecl.object_store.v1.container.Container` - """ - container = attrs.pop("container", None) - container_name = self._get_container_name(None, container) - - return self._create(_obj.Object, - path_args={"container": container_name}, **attrs) - - def copy_object(self): - """Copy an object.""" - raise NotImplementedError - - def delete_object(self, obj, ignore_missing=False, container=None): - """Delete an object - - :param obj: The value can be either the name of an object or a - :class:`~ecl.object_store.v1.container.Container` - instance. - :param container: The value can be the ID of a container or a - :class:`~ecl.object_store.v1.container.Container` - instance. - :param bool ignore_missing: When set to ``False`` - :class:`~ecl.exceptions.ResourceNotFound` will be - raised when the object does not exist. - When set to ``True``, no exception will be set when - attempting to delete a nonexistent server. - - :returns: ``None`` - """ - container_name = self._get_container_name(obj, container) - - self._delete(_obj.Object, obj, ignore_missing=ignore_missing, - path_args={"container": container_name}) - - def get_object_metadata(self, obj, container=None): - """Get metadata for an object. - - :param obj: The value can be the name of an object or a - :class:`~ecl.object_store.v1.obj.Object` instance. - :param container: The value can be the ID of a container or a - :class:`~ecl.object_store.v1.container.Container` - instance. - - :returns: One :class:`~ecl.object_store.v1.obj.Object` - :raises: :class:`~ecl.exceptions.ResourceNotFound` - when no resource can be found. - """ - container_name = self._get_container_name(obj, container) - - return self._head(_obj.Object, obj, - path_args={"container": container_name}) - - def set_object_metadata(self, obj, container=None, **metadata): - """Set metadata for an object. - - Note: This method will do an extra HEAD call. - - :param obj: The value can be the name of an object or a - :class:`~ecl.object_store.v1.obj.Object` instance. - :param container: The value can be the name of a container or a - :class:`~ecl.object_store.v1.container.Container` - instance. - :param kwargs metadata: Key/value pairs to be set as metadata - on the container. Both custom and system - metadata can be set. Custom metadata are keys - and values defined by the user. System - metadata are keys defined by the Object Store - and values defined by the user. The system - metadata keys are: - - - `content_type` - - `content_encoding` - - `content_disposition` - - `delete_after` - - `delete_at` - - `is_content_type_detected` - """ - container_name = self._get_container_name(obj, container) - res = self._get_resource(_obj.Object, obj, - path_args={"container": container_name}) - res.set_metadata(self.session, metadata) - - def delete_object_metadata(self, obj, container=None, keys=None): - """Delete metadata for an object. - - :param obj: The value can be the name of an object or a - :class:`~ecl.object_store.v1.obj.Object` instance. - :param container: The value can be the ID of a container or a - :class:`~ecl.object_store.v1.container.Container` - instance. - :param keys: The keys of metadata to be deleted. - """ - container_name = self._get_container_name(obj, container) - res = self._get_resource(_obj.Object, obj, - path_args={"container": container_name}) - res.delete_metadata(self.session, keys) diff --git a/ecl/object_store/v1/account.py b/ecl/object_store/v1/account.py deleted file mode 100755 index 88d5248..0000000 --- a/ecl/object_store/v1/account.py +++ /dev/null @@ -1,42 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may - -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from ecl.object_store.v1 import _base -from ecl import resource - - -class Account(_base.BaseResource): - _custom_metadata_prefix = "X-Account-Meta-" - - base_path = "/" - - allow_retrieve = True - allow_update = True - allow_head = True - - #: The total number of bytes that are stored in Object Storage for - #: the account. - account_bytes_used = resource.header("x-account-bytes-used", type=int) - #: The number of containers. - account_container_count = resource.header("x-account-container-count", - type=int) - #: The number of objects in the account. - account_object_count = resource.header("x-account-object-count", type=int) - #: The secret key value for temporary URLs. If not set, - #: this header is not returned by this operation. - meta_temp_url_key = resource.header("x-account-meta-temp-url-key") - #: A second secret key value for temporary URLs. If not set, - #: this header is not returned by this operation. - meta_temp_url_key_2 = resource.header("x-account-meta-temp-url-key-2") - #: The timestamp of the transaction. - timestamp = resource.header("x-timestamp") diff --git a/ecl/object_store/v1/container.py b/ecl/object_store/v1/container.py deleted file mode 100755 index 6f6842d..0000000 --- a/ecl/object_store/v1/container.py +++ /dev/null @@ -1,165 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may - -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from ecl.object_store.v1 import _base -from ecl import resource - - -class Container(_base.BaseResource): - _custom_metadata_prefix = "X-Container-Meta-" - _system_metadata = { - "content_type": "content-type", - "is_content_type_detected": "x-detect-content-type", - "versions_location": "x-versions-location", - "read_acl": "x-container-read", - "write_acl": "x-container-write", - "sync_to": "x-container-sync-to", - "sync_key": "x-container-sync-key", - "meta_name": "X-Container-Meta-name", - "meta_access_control_allow_origin": - "X-Container-Meta-Access-Control-Allow-Origin", - "meta_access_control_max_age": - "X-Container-Meta-Access-Control-Max-Age", - "meta_access_control_expose_headers": - "X-Container-Meta-Access-Control-Expose-Headers", - "meta_quota_bytes": "X-Container-Meta-Quota-Bytes", - "meta_quota_count": "X-Container-Meta-Quota-Count", - "meta_temp_url_key": "X-Container-Meta-Temp-URL-Key", - "meta_temp_url_key_2": "X-Container-Meta-Temp-URL-Key-2", - } - - base_path = "/" - id_attribute = "name" - - allow_create = True - allow_retrieve = True - allow_update = True - allow_delete = True - allow_list = True - allow_head = True - - # Container body data (when id=None) - #: The name of the container. - name = resource.prop("name") - #: The number of objects in the container. - count = resource.prop("count") - #: The total number of bytes that are stored in Object Storage - #: for the container. - bytes = resource.prop("bytes") - - # Container metadata (when id=name) - #: The number of objects. - object_count = resource.header("x-container-object-count", type=int) - #: The count of bytes used in total. - bytes_used = resource.header("x-container-bytes-used", type=int) - #: The timestamp of the transaction. (date created) - timestamp = resource.header("x-timestamp") - - # Request headers (when id=None) - #: If set to True, Object Storage queries all replicas to return the - #: most recent one. If you omit this header, Object Storage responds - #: faster after it finds one valid replica. Because setting this - #: header to True is more expensive for the back end, use it only - #: when it is absolutely needed. *Type: bool* - is_newest = resource.header("x-newest", type=bool) - - # Request headers (when id=name) - #: The ACL that grants read access. If not set, this header is not - #: returned by this operation. - read_acl = resource.header("x-container-read") - #: The ACL that grants write access. If not set, this header is not - #: returned by this operation. - write_acl = resource.header("x-container-write") - #: The destination for container synchronization. If not set, - #: this header is not returned by this operation. - sync_to = resource.header("x-container-sync-to") - #: The secret key for container synchronization. If not set, - #: this header is not returned by this operation. - sync_key = resource.header("x-container-sync-key") - #: Enables versioning on this container. The value is the name - #: of another container. You must UTF-8-encode and then URL-encode - #: the name before you include it in the header. To disable - #: versioning, set the header to an empty string. - versions_location = resource.header("x-versions-location") - #: The MIME type of the list of names. - content_type = resource.header("content-type") - #: If set to true, Object Storage guesses the content type based - #: on the file extension and ignores the value sent in the - #: Content-Type header, if present. *Type: bool* - is_content_type_detected = resource.header("x-detect-content-type", - type=bool) - #: In combination with Expect: 100-Continue, specify an - #: "If-None-Match: \*" header to query whether the server already - #: has a copy of the object before any data is sent. - if_none_match = resource.header("if-none-match") - #: The container metadata, where name is the name of metadata item. - #: You must specify an X-Container-Meta-name header for each metadata item - #: (for each name ) that you want to add or update. - meta_name = resource.header("X-Container-Meta-name") - #: Originating URLs allowed to make cross-origin requests (CORS), - #: separated by spaces. - meta_access_control_allow_origin = resource.header( - "X-Container-Meta-Access-Control-Allow-Origin") - #: Maximum time for the origin to hold the preflight results. - meta_access_control_max_age = resource.header( - "X-Container-Meta-Access-Control-Max-Age") - #: Headers the Object Storage service exposes to the browser (technically, - #: through the user-agent setting), - #: in the request response, separated by spaces. - #: By default the Object Storage service returns the following headers - meta_access_control_expose_headers = resource.header( - "X-Container-Meta-Access-Control-Expose-Headers") - #: Sets maximum size of the container, in bytes. - #: Typically these values are set by an administrator. - meta_quota_bytes = resource.header("X-Container-Meta-Quota-Bytes") - #: Sets maximum object count of the container. - #: Typically these values are set by an administrator. - meta_quota_count = resource.header("X-Container-Meta-Quota-Count") - #: The secret key value for temporary URLs. - meta_temp_url_key = resource.header("X-Container-Meta-Temp-URL-Key") - #: A second secret key value for temporary URLs. - #: The second key enables you to rotate keys by having two active keys - #: at the same time. - meta_temp_url_key_2 = resource.header("X-Container-Meta-Temp-URL-Key-2") - - @classmethod - def create_by_id(cls, session, attrs, resource_id=None): - """Create a Resource from its attributes. - - :param session: The session to use for making this request. - :type session: :class:`~ecl.session.Session` - :param dict attrs: The attributes to be sent in the body - of the request. - :param resource_id: This resource's identifier, if needed by - the request. The default is ``None``. - - :return: A ``dict`` representing the response headers. - """ - url = cls._get_url(None, resource_id) - headers = attrs.get(resource.HEADERS, dict()) - headers['Accept'] = '' - return session.put(url, endpoint_filter=cls.service, - headers=headers).headers - - def create(self, session): - """Create a Resource from this instance. - - :param session: The session to use for making this request. - :type session: :class:`~ecl.session.Session` - - :return: This instance. - """ - resp = self.create_by_id(session, self._attrs, self.id) - self.set_headers(resp) - self._reset_dirty() - return self diff --git a/ecl/object_store/v1/obj.py b/ecl/object_store/v1/obj.py deleted file mode 100755 index 847ac4e..0000000 --- a/ecl/object_store/v1/obj.py +++ /dev/null @@ -1,234 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may - -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy -import six - -from ecl.object_store import object_store_service -from ecl.object_store.v1 import _base -from ecl import resource - - -class Object(_base.BaseResource): - _custom_metadata_prefix = "X-Object-Meta-" - _system_metadata = { - "content_disposition": "content-disposition", - "content_encoding": "content-encoding", - "content_type": "content-type", - "delete_after": "x-delete-after", - "delete_at": "x-delete-at", - "is_content_type_detected": "x-detect-content-type", - } - - base_path = "/%(container)s" - service = object_store_service.ObjectStoreService() - id_attribute = "name" - - allow_create = True - allow_retrieve = True - allow_update = True - allow_delete = True - allow_list = True - allow_head = True - - # Data to be passed during a POST call to create an object on the server. - data = None - - # URL parameters - #: The unique name for the container. - container = resource.prop("container") - #: The unique name for the object. - name = resource.prop("name") - - # Object details - hash = resource.prop("hash") - bytes = resource.prop("bytes") - - # Headers for HEAD and GET requests - #: If set to True, Object Storage queries all replicas to return - #: the most recent one. If you omit this header, Object Storage - #: responds faster after it finds one valid replica. Because - #: setting this header to True is more expensive for the back end, - #: use it only when it is absolutely needed. *Type: bool* - is_newest = resource.header("x-newest", type=bool) - #: TODO(briancurtin) there's a lot of content here... - range = resource.header("range", type=dict) - #: See http://www.ietf.org/rfc/rfc2616.txt. - if_match = resource.header("if-match", type=dict) - #: In combination with Expect: 100-Continue, specify an - #: "If-None-Match: \*" header to query whether the server already - #: has a copy of the object before any data is sent. - if_none_match = resource.header("if-none-match", type=dict) - #: See http://www.ietf.org/rfc/rfc2616.txt. - if_modified_since = resource.header("if-modified-since", type=dict) - #: See http://www.ietf.org/rfc/rfc2616.txt. - if_unmodified_since = resource.header("if-unmodified-since", type=dict) - - # Query parameters - #: Used with temporary URLs to sign the request. For more - #: information about temporary URLs, see OpenStack Object Storage - #: API v1 Reference. - signature = resource.header("signature") - #: Used with temporary URLs to specify the expiry time of the - #: signature. For more information about temporary URLs, see - #: OpenStack Object Storage API v1 Reference. - expires_at = resource.header("expires") - #: If you include the multipart-manifest=get query parameter and - #: the object is a large object, the object contents are not - #: returned. Instead, the manifest is returned in the - #: X-Object-Manifest response header for dynamic large objects - #: or in the response body for static large objects. - multipart_manifest = resource.header("multipart-manifest") - - # Response headers from HEAD and GET - #: HEAD operations do not return content. However, in this - #: operation the value in the Content-Length header is not the - #: size of the response body. Instead it contains the size of - #: the object, in bytes. - content_length = resource.header("content-length") - #: The MIME type of the object. - content_type = resource.header("content-type") - #: The type of ranges that the object accepts. - accept_ranges = resource.header("accept-ranges") - #: For objects smaller than 5 GB, this value is the MD5 checksum - #: of the object content. The value is not quoted. - #: For manifest objects, this value is the MD5 checksum of the - #: concatenated string of MD5 checksums and ETags for each of - #: the segments in the manifest, and not the MD5 checksum of - #: the content that was downloaded. Also the value is enclosed - #: in double-quote characters. - #: You are strongly recommended to compute the MD5 checksum of - #: the response body as it is received and compare this value - #: with the one in the ETag header. If they differ, the content - #: was corrupted, so retry the operation. - etag = resource.header("etag") - #: Set to True if this object is a static large object manifest object. - #: *Type: bool* - is_static_large_object = resource.header("x-static-large-object", - type=bool) - #: If set, the value of the Content-Encoding metadata. - #: If not set, this header is not returned by this operation. - content_encoding = resource.header("content-encoding") - #: If set, specifies the override behavior for the browser. - #: For example, this header might specify that the browser use - #: a download program to save this file rather than show the file, - #: which is the default. - #: If not set, this header is not returned by this operation. - content_disposition = resource.header("content-disposition") - #: Specifies the number of seconds after which the object is - #: removed. Internally, the Object Storage system stores this - #: value in the X-Delete-At metadata item. - delete_after = resource.header("x-delete-after") - #: If set, the time when the object will be deleted by the system - #: in the format of a UNIX Epoch timestamp. - #: If not set, this header is not returned by this operation. - delete_at = resource.header("x-delete-at") - #: If set, to this is a dynamic large object manifest object. - #: The value is the container and object name prefix of the - #: segment objects in the form container/prefix. - object_manifest = resource.header("x-object-manifest") - #: The timestamp of the transaction. - timestamp = resource.header("x-timestamp") - #: The date and time that the object was created or the last - #: time that the metadata was changed. - last_modified_at = resource.header("last_modified", alias="last-modified") - - # Headers for PUT and POST requests - #: Set to chunked to enable chunked transfer encoding. If used, - #: do not set the Content-Length header to a non-zero value. - transfer_encoding = resource.header("transfer-encoding") - #: If set to true, Object Storage guesses the content type based - #: on the file extension and ignores the value sent in the - #: Content-Type header, if present. *Type: bool* - is_content_type_detected = resource.header("x-detect-content-type", - type=bool) - #: If set, this is the name of an object used to create the new - #: object by copying the X-Copy-From object. The value is in form - #: {container}/{object}. You must UTF-8-encode and then URL-encode - #: the names of the container and object before you include them - #: in the header. - #: Using PUT with X-Copy-From has the same effect as using the - #: COPY operation to copy an object. - copy_from = resource.header("x-copy-from") - - # The Object Store treats the metadata for its resources inconsistently so - # Object.set_metadata must override the BaseResource.set_metadata to - # account for it. - def set_metadata(self, session, metadata): - # Filter out items with empty values so the create metadata behaviour - # is the same as account and container - filtered_metadata = \ - {key: value for key, value in six.iteritems(metadata) if value} - - # Get a copy of the original metadata so it doesn't get erased on POST - # and update it with the new metadata values. - obj = self.head(session) - metadata2 = copy.deepcopy(obj.metadata) - metadata2.update(filtered_metadata) - - # Include any original system metadata so it doesn't get erased on POST - for key in self._system_metadata: - value = getattr(obj, key) - if value and key not in metadata2: - metadata2[key] = value - - super(Object, self).set_metadata(session, metadata2) - - # The Object Store treats the metadata for its resources inconsistently so - # Object.delete_metadata must override the BaseResource.delete_metadata to - # account for it. - def delete_metadata(self, session, keys): - # Get a copy of the original metadata so it doesn't get erased on POST - # and update it with the new metadata values. - obj = self.head(session) - metadata = copy.deepcopy(obj.metadata) - - # Include any original system metadata so it doesn't get erased on POST - for key in self._system_metadata: - value = getattr(obj, key) - if value: - metadata[key] = value - - # Remove the metadata - for key in keys: - if key == 'delete_after': - del(metadata['delete_at']) - else: - del(metadata[key]) - - url = self._get_url(self, self.id) - session.post(url, endpoint_filter=self.service, - headers=self._calculate_headers(metadata)) - - def get(self, session, include_headers=False, args=None): - url = self._get_url(self, self.id) - headers = {'Accept': 'bytes'} - resp = session.get(url, endpoint_filter=self.service, headers=headers) - resp = resp.content - self._set_metadata() - return resp - - def create(self, session): - url = self._get_url(self, self.id) - - headers = self.get_headers() - headers['Accept'] = '' - if self.data is not None: - resp = session.put(url, endpoint_filter=self.service, - data=self.data, - headers=headers).headers - else: - resp = session.post(url, endpoint_filter=self.service, data=None, - headers=headers).headers - self.set_headers(resp) - return self diff --git a/ecl/profile.py b/ecl/profile.py index 25ae6e9..abbe8d1 100755 --- a/ecl/profile.py +++ b/ecl/profile.py @@ -29,14 +29,13 @@ ~~~~~~~~~~~ A user's preferences are set based on the service type. Service type would -normally be something like 'compute', 'identity', 'object-store', etc.:: +normally be something like 'compute', 'identity', etc.:: from ecl import profile prof = profile.Profile() prof.set_name('compute', 'matrix') prof.set_region(prof.ALL, 'zion') prof.set_version('identity', 'v3') - prof.set_interface('object-store', 'internal') for service in prof.get_services(): print(prof.get_filter(service.service_type) @@ -44,11 +43,9 @@ service_type=compute,region=zion,service_name=matrix service_type=network,region=zion - service_type=database,region=zion service_type=image,region=zion service_type=metering,region=zion service_type=orchestration,region=zion - service_type=object-store,interface=internal,region=zion service_type=identity,region=zion,version=v3 """ @@ -66,7 +63,6 @@ from ecl.image import image_service from ecl import module_loader from ecl.network import network_service -from ecl.object_store import object_store_service from ecl.orchestration import orchestration_service from ecl.provider_connectivity import provider_connectivity_service from ecl.rca import rca_service @@ -79,7 +75,6 @@ ## end of the section from ecl.sss import sss_service from ecl.telemetry import telemetry_service -from ecl.database import database_service from ecl.dns import dns_service from ecl.virtual_network_appliance import virtual_network_appliance_service from ecl.mvna import mvna_service @@ -112,8 +107,6 @@ def __init__(self, plugins=None): self._add_service(image_service.ImageService(version="v2")) self._add_service(network_service.NetworkService(version="v2")) self._add_service(sss_service.SssService(version="v1")) - self._add_service( - object_store_service.ObjectStoreService(version="v1")) self._add_service( orchestration_service.OrchestrationService(version="v1")) self._add_service( @@ -137,7 +130,6 @@ def __init__(self, plugins=None): self._add_service( dedicated_hypervisor_service.DedicatedHypervisorService( version="v1")) - self._add_service(database_service.DatabaseService(version="v1")) self._add_service(dns_service.DnsService(version="v2")) self._add_service( virtual_network_appliance_service.VirtualNetworkApplianceService( diff --git a/ecl/tests/functional/object_store/__init__.py b/ecl/tests/functional/object_store/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/ecl/tests/functional/object_store/v1/__init__.py b/ecl/tests/functional/object_store/v1/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/ecl/tests/functional/object_store/v1/test_account.py b/ecl/tests/functional/object_store/v1/test_account.py deleted file mode 100755 index bd2b96a..0000000 --- a/ecl/tests/functional/object_store/v1/test_account.py +++ /dev/null @@ -1,79 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from ecl.tests.functional import base - - -class TestAccount(base.BaseFunctionalTest): - - @classmethod - def tearDownClass(cls): - super(TestAccount, cls).tearDownClass() - account = cls.conn.object_store.get_account_metadata() - cls.conn.object_store.delete_account_metadata(account.metadata.keys()) - - def test_system_metadata(self): - account = self.conn.object_store.get_account_metadata() - self.assertGreaterEqual(account.account_bytes_used, 0) - self.assertGreaterEqual(account.account_container_count, 0) - self.assertGreaterEqual(account.account_object_count, 0) - - def test_custom_metadata(self): - # get custom metadata - account = self.conn.object_store.get_account_metadata() - self.assertFalse(account.metadata) - - # set no custom metadata - self.conn.object_store.set_account_metadata() - account = self.conn.object_store.get_account_metadata() - self.assertFalse(account.metadata) - - # set empty custom metadata - self.conn.object_store.set_account_metadata(k0='') - account = self.conn.object_store.get_account_metadata() - self.assertFalse(account.metadata) - - # set custom metadata - self.conn.object_store.set_account_metadata(k1='v1') - account = self.conn.object_store.get_account_metadata() - self.assertTrue(account.metadata) - self.assertEqual(1, len(account.metadata)) - self.assertIn('k1', account.metadata) - self.assertEqual('v1', account.metadata['k1']) - - # set more custom metadata - self.conn.object_store.set_account_metadata(k2='v2') - account = self.conn.object_store.get_account_metadata() - self.assertTrue(account.metadata) - self.assertEqual(2, len(account.metadata)) - self.assertIn('k1', account.metadata) - self.assertEqual('v1', account.metadata['k1']) - self.assertIn('k2', account.metadata) - self.assertEqual('v2', account.metadata['k2']) - - # update custom metadata - self.conn.object_store.set_account_metadata(k1='v1.1') - account = self.conn.object_store.get_account_metadata() - self.assertTrue(account.metadata) - self.assertEqual(2, len(account.metadata)) - self.assertIn('k1', account.metadata) - self.assertEqual('v1.1', account.metadata['k1']) - self.assertIn('k2', account.metadata) - self.assertEqual('v2', account.metadata['k2']) - - # unset custom metadata - self.conn.object_store.delete_account_metadata(['k1']) - account = self.conn.object_store.get_account_metadata() - self.assertTrue(account.metadata) - self.assertEqual(1, len(account.metadata)) - self.assertIn('k2', account.metadata) - self.assertEqual('v2', account.metadata['k2']) diff --git a/ecl/tests/functional/object_store/v1/test_container.py b/ecl/tests/functional/object_store/v1/test_container.py deleted file mode 100755 index 7be3934..0000000 --- a/ecl/tests/functional/object_store/v1/test_container.py +++ /dev/null @@ -1,134 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from ecl.object_store.v1 import container as _container -from ecl.tests.functional import base - - -class TestContainer(base.BaseFunctionalTest): - - NAME = uuid.uuid4().hex - - @classmethod - def setUpClass(cls): - super(TestContainer, cls).setUpClass() - container = cls.conn.object_store.create_container(name=cls.NAME) - assert isinstance(container, _container.Container) - cls.assertIs(cls.NAME, container.name) - - @classmethod - def tearDownClass(cls): - result = cls.conn.object_store.delete_container(cls.NAME, - ignore_missing=True) - cls.assertIs(None, result) - - def test_list(self): - names = [o.name for o in self.conn.object_store.containers()] - self.assertIn(self.NAME, names) - - def test_system_metadata(self): - # get system metadata - container = self.conn.object_store.get_container_metadata(self.NAME) - self.assertEqual(0, container.object_count) - self.assertEqual(0, container.bytes_used) - - # set system metadata - container = self.conn.object_store.get_container_metadata(self.NAME) - self.assertIsNone(container.read_acl) - self.assertIsNone(container.write_acl) - self.conn.object_store.set_container_metadata( - container, read_acl='.r:*', write_acl='demo:demo') - container = self.conn.object_store.get_container_metadata(self.NAME) - self.assertEqual('.r:*', container.read_acl) - self.assertEqual('demo:demo', container.write_acl) - - # update system metadata - self.conn.object_store.set_container_metadata( - container, read_acl='.r:demo') - container = self.conn.object_store.get_container_metadata(self.NAME) - self.assertEqual('.r:demo', container.read_acl) - self.assertEqual('demo:demo', container.write_acl) - - # set system metadata and custom metadata - self.conn.object_store.set_container_metadata( - container, k0='v0', sync_key='1234') - container = self.conn.object_store.get_container_metadata(self.NAME) - self.assertTrue(container.metadata) - self.assertIn('k0', container.metadata) - self.assertEqual('v0', container.metadata['k0']) - self.assertEqual('.r:demo', container.read_acl) - self.assertEqual('demo:demo', container.write_acl) - self.assertEqual('1234', container.sync_key) - - # unset system metadata - self.conn.object_store.delete_container_metadata(container, - ['sync_key']) - container = self.conn.object_store.get_container_metadata(self.NAME) - self.assertTrue(container.metadata) - self.assertIn('k0', container.metadata) - self.assertEqual('v0', container.metadata['k0']) - self.assertEqual('.r:demo', container.read_acl) - self.assertEqual('demo:demo', container.write_acl) - self.assertIsNone(container.sync_key) - - def test_custom_metadata(self): - # get custom metadata - container = self.conn.object_store.get_container_metadata(self.NAME) - self.assertFalse(container.metadata) - - # set no custom metadata - self.conn.object_store.set_container_metadata(container) - container = self.conn.object_store.get_container_metadata(container) - self.assertFalse(container.metadata) - - # set empty custom metadata - self.conn.object_store.set_container_metadata(container, k0='') - container = self.conn.object_store.get_container_metadata(container) - self.assertFalse(container.metadata) - - # set custom metadata - self.conn.object_store.set_container_metadata(container, k1='v1') - container = self.conn.object_store.get_container_metadata(container) - self.assertTrue(container.metadata) - self.assertEqual(1, len(container.metadata)) - self.assertIn('k1', container.metadata) - self.assertEqual('v1', container.metadata['k1']) - - # set more custom metadata by named container - self.conn.object_store.set_container_metadata(self.NAME, k2='v2') - container = self.conn.object_store.get_container_metadata(container) - self.assertTrue(container.metadata) - self.assertEqual(2, len(container.metadata)) - self.assertIn('k1', container.metadata) - self.assertEqual('v1', container.metadata['k1']) - self.assertIn('k2', container.metadata) - self.assertEqual('v2', container.metadata['k2']) - - # update metadata - self.conn.object_store.set_container_metadata(container, k1='v1.1') - container = self.conn.object_store.get_container_metadata(self.NAME) - self.assertTrue(container.metadata) - self.assertEqual(2, len(container.metadata)) - self.assertIn('k1', container.metadata) - self.assertEqual('v1.1', container.metadata['k1']) - self.assertIn('k2', container.metadata) - self.assertEqual('v2', container.metadata['k2']) - - # delete metadata - self.conn.object_store.delete_container_metadata(container, ['k1']) - container = self.conn.object_store.get_container_metadata(self.NAME) - self.assertTrue(container.metadata) - self.assertEqual(1, len(container.metadata)) - self.assertIn('k2', container.metadata) - self.assertEqual('v2', container.metadata['k2']) diff --git a/ecl/tests/functional/object_store/v1/test_obj.py b/ecl/tests/functional/object_store/v1/test_obj.py deleted file mode 100755 index 3f36f0c..0000000 --- a/ecl/tests/functional/object_store/v1/test_obj.py +++ /dev/null @@ -1,154 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from ecl.tests.functional import base - - -class TestObject(base.BaseFunctionalTest): - - FOLDER = uuid.uuid4().hex - FILE = uuid.uuid4().hex - DATA = 'abc' - - @classmethod - def setUpClass(cls): - super(TestObject, cls).setUpClass() - cls.conn.object_store.create_container(name=cls.FOLDER) - cls.sot = cls.conn.object_store.upload_object( - container=cls.FOLDER, name=cls.FILE, data=cls.DATA) - - @classmethod - def tearDownClass(cls): - super(TestObject, cls).tearDownClass() - cls.conn.object_store.delete_object(cls.sot, ignore_missing=True) - cls.conn.object_store.delete_container(cls.FOLDER) - - def test_list(self): - names = [o.name for o - in self.conn.object_store.objects(container=self.FOLDER)] - self.assertIn(self.FILE, names) - - def test_get_object(self): - result = self.conn.object_store.get_object( - self.FILE, container=self.FOLDER) - self.assertEqual(self.DATA, result) - result = self.conn.object_store.get_object(self.sot) - self.assertEqual(self.DATA, result) - - def test_system_metadata(self): - # get system metadata - obj = self.conn.object_store.get_object_metadata( - self.FILE, container=self.FOLDER) - self.assertGreaterEqual(0, obj.bytes) - self.assertIsNotNone(obj.etag) - - # set system metadata - obj = self.conn.object_store.get_object_metadata( - self.FILE, container=self.FOLDER) - self.assertIsNone(obj.content_disposition) - self.assertIsNone(obj.content_encoding) - self.conn.object_store.set_object_metadata( - obj, content_disposition='attachment', content_encoding='gzip') - obj = self.conn.object_store.get_object_metadata(obj) - self.assertEqual('attachment', obj.content_disposition) - self.assertEqual('gzip', obj.content_encoding) - - # update system metadata - self.conn.object_store.set_object_metadata( - obj, content_encoding='deflate') - obj = self.conn.object_store.get_object_metadata(obj) - self.assertEqual('attachment', obj.content_disposition) - self.assertEqual('deflate', obj.content_encoding) - - # set system metadata and custom metadata - self.conn.object_store.set_object_metadata( - obj, k0='v0', delete_after='100') - obj = self.conn.object_store.get_object_metadata(obj) - self.assertIn('k0', obj.metadata) - self.assertEqual('v0', obj.metadata['k0']) - self.assertEqual('attachment', obj.content_disposition) - self.assertEqual('deflate', obj.content_encoding) - - # unset system metadata - self.conn.object_store.delete_object_metadata( - obj, keys=['delete_after']) - obj = self.conn.object_store.get_object_metadata(obj) - self.assertIn('k0', obj.metadata) - self.assertEqual('v0', obj.metadata['k0']) - self.assertEqual('attachment', obj.content_disposition) - self.assertEqual('deflate', obj.content_encoding) - self.assertIsNone(obj.delete_at) - - # unset more system metadata - self.conn.object_store.delete_object_metadata( - obj, keys=['content_disposition']) - obj = self.conn.object_store.get_object_metadata(obj) - self.assertIn('k0', obj.metadata) - self.assertEqual('v0', obj.metadata['k0']) - self.assertIsNone(obj.content_disposition) - self.assertEqual('deflate', obj.content_encoding) - self.assertIsNone(obj.delete_at) - - def test_custom_metadata(self): - # get custom metadata - obj = self.conn.object_store.get_object_metadata( - self.FILE, container=self.FOLDER) - self.assertFalse(obj.metadata) - - # set no custom metadata - self.conn.object_store.set_object_metadata(obj) - obj = self.conn.object_store.get_object_metadata(obj) - self.assertFalse(obj.metadata) - - # set empty custom metadata - self.conn.object_store.set_object_metadata(obj, k0='') - obj = self.conn.object_store.get_object_metadata(obj) - self.assertFalse(obj.metadata) - - # set custom metadata - self.conn.object_store.set_object_metadata(obj, k1='v1') - obj = self.conn.object_store.get_object_metadata(obj) - self.assertTrue(obj.metadata) - self.assertEqual(1, len(obj.metadata)) - self.assertIn('k1', obj.metadata) - self.assertEqual('v1', obj.metadata['k1']) - - # set more custom metadata by named object and container - self.conn.object_store.set_object_metadata(self.FILE, self.FOLDER, - k2='v2') - obj = self.conn.object_store.get_object_metadata(obj) - self.assertTrue(obj.metadata) - self.assertEqual(2, len(obj.metadata)) - self.assertIn('k1', obj.metadata) - self.assertEqual('v1', obj.metadata['k1']) - self.assertIn('k2', obj.metadata) - self.assertEqual('v2', obj.metadata['k2']) - - # update custom metadata - self.conn.object_store.set_object_metadata(obj, k1='v1.1') - obj = self.conn.object_store.get_object_metadata(obj) - self.assertTrue(obj.metadata) - self.assertEqual(2, len(obj.metadata)) - self.assertIn('k1', obj.metadata) - self.assertEqual('v1.1', obj.metadata['k1']) - self.assertIn('k2', obj.metadata) - self.assertEqual('v2', obj.metadata['k2']) - - # unset custom metadata - self.conn.object_store.delete_object_metadata(obj, keys=['k1']) - obj = self.conn.object_store.get_object_metadata(obj) - self.assertTrue(obj.metadata) - self.assertEqual(1, len(obj.metadata)) - self.assertIn('k2', obj.metadata) - self.assertEqual('v2', obj.metadata['k2']) diff --git a/ecl/tests/functional/telemetry/v2/test_meter.py b/ecl/tests/functional/telemetry/v2/test_meter.py deleted file mode 100755 index 536cfd8..0000000 --- a/ecl/tests/functional/telemetry/v2/test_meter.py +++ /dev/null @@ -1,32 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest -import uuid - -from ecl.tests.functional import base - - -@unittest.skipUnless(base.service_exists(service_type="metering"), - "Metering service does not exist") -class TestMeter(base.BaseFunctionalTest): - - def test_list(self): - # TODO(thowe): Remove this in favor of create_meter call. - # Since we do not have a create meter method at the moment - # make sure there is some data in there - name = uuid.uuid4().hex - tainer = self.conn.object_store.create_container(name=name) - self.conn.object_store.delete_container(tainer) - - names = set([o.name for o in self.conn.telemetry.meters()]) - self.assertIn('storage.objects.incoming.bytes', names) diff --git a/ecl/tests/unit/object_store/__init__.py b/ecl/tests/unit/object_store/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/ecl/tests/unit/object_store/test_object_store_service.py b/ecl/tests/unit/object_store/test_object_store_service.py deleted file mode 100755 index 5a02f2a..0000000 --- a/ecl/tests/unit/object_store/test_object_store_service.py +++ /dev/null @@ -1,28 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from ecl.object_store import object_store_service - - -class TestObjectStoreService(testtools.TestCase): - - def test_service(self): - sot = object_store_service.ObjectStoreService() - self.assertEqual('object-store', sot.service_type) - self.assertEqual('public', sot.interface) - self.assertIsNone(sot.region) - self.assertIsNone(sot.service_name) - self.assertEqual(1, len(sot.valid_versions)) - self.assertEqual('v1', sot.valid_versions[0].module) - self.assertEqual('v1', sot.valid_versions[0].path) diff --git a/ecl/tests/unit/object_store/v1/__init__.py b/ecl/tests/unit/object_store/v1/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/ecl/tests/unit/object_store/v1/test_account.py b/ecl/tests/unit/object_store/v1/test_account.py deleted file mode 100755 index a97b61d..0000000 --- a/ecl/tests/unit/object_store/v1/test_account.py +++ /dev/null @@ -1,56 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from ecl.object_store.v1 import account - - -CONTAINER_NAME = "mycontainer" - -ACCOUNT_EXAMPLE = { - 'content-length': '0', - 'accept-ranges': 'bytes', - 'date': 'Sat, 05 Jul 2014 19:17:40 GMT', - 'x-account-bytes-used': '12345', - 'x-account-container-count': '678', - 'content-type': 'text/plain; charset=utf-8', - 'x-account-object-count': '98765', - 'x-timestamp': '1453413555.88937' -} - - -class TestAccount(testtools.TestCase): - - def test_basic(self): - sot = account.Account.new(**ACCOUNT_EXAMPLE) - self.assertIsNone(sot.resources_key) - self.assertIsNone(sot.id) - self.assertEqual('/', sot.base_path) - self.assertEqual('object-store', sot.service.service_type) - self.assertTrue(sot.allow_update) - self.assertTrue(sot.allow_head) - self.assertTrue(sot.allow_retrieve) - self.assertFalse(sot.allow_delete) - self.assertFalse(sot.allow_list) - self.assertFalse(sot.allow_create) - - def test_make_it(self): - sot = account.Account.new(**{'headers': ACCOUNT_EXAMPLE}) - self.assertIsNone(sot.id) - self.assertEqual(int(ACCOUNT_EXAMPLE['x-account-bytes-used']), - sot.account_bytes_used) - self.assertEqual(int(ACCOUNT_EXAMPLE['x-account-container-count']), - sot.account_container_count) - self.assertEqual(int(ACCOUNT_EXAMPLE['x-account-object-count']), - sot.account_object_count) - self.assertEqual(ACCOUNT_EXAMPLE['x-timestamp'], sot.timestamp) diff --git a/ecl/tests/unit/object_store/v1/test_container.py b/ecl/tests/unit/object_store/v1/test_container.py deleted file mode 100755 index f81e0b3..0000000 --- a/ecl/tests/unit/object_store/v1/test_container.py +++ /dev/null @@ -1,171 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock -import testtools - -from ecl.object_store.v1 import container - - -CONTAINER_NAME = "mycontainer" - -CONT_EXAMPLE = { - "count": 999, - "bytes": 12345, - "name": CONTAINER_NAME -} - -HEAD_EXAMPLE = { - 'content-length': '346', - 'x-container-object-count': '2', - 'accept-ranges': 'bytes', - 'id': 'tx1878fdc50f9b4978a3fdc-0053c31462', - 'date': 'Sun, 13 Jul 2014 23:21:06 GMT', - 'x-container-read': 'read-settings', - 'x-container-write': 'write-settings', - 'x-container-sync-to': 'sync-to', - 'x-container-sync-key': 'sync-key', - 'x-container-bytes-used': '630666', - 'x-versions-location': 'versions-location', - 'content-type': 'application/json; charset=utf-8', - 'x-timestamp': '1453414055.48672' -} - -LIST_EXAMPLE = [ - { - "count": 999, - "bytes": 12345, - "name": "container1" - }, - { - "count": 888, - "bytes": 54321, - "name": "container2" - } -] - - -class TestContainer(testtools.TestCase): - - def setUp(self): - super(TestContainer, self).setUp() - self.resp = mock.Mock() - self.resp.body = {} - self.resp.json = mock.Mock(return_value=self.resp.body) - self.resp.headers = {"X-Trans-Id": "abcdef"} - self.sess = mock.Mock() - self.sess.put = mock.Mock(return_value=self.resp) - self.sess.post = mock.Mock(return_value=self.resp) - - def test_basic(self): - sot = container.Container.new(**CONT_EXAMPLE) - self.assertIsNone(sot.resources_key) - self.assertEqual('name', sot.id_attribute) - self.assertEqual('/', sot.base_path) - self.assertEqual('object-store', sot.service.service_type) - self.assertTrue(sot.allow_update) - self.assertTrue(sot.allow_create) - self.assertTrue(sot.allow_retrieve) - self.assertTrue(sot.allow_delete) - self.assertTrue(sot.allow_list) - self.assertTrue(sot.allow_head) - - def test_make_it(self): - sot = container.Container.new(**CONT_EXAMPLE) - self.assertEqual(CONT_EXAMPLE['name'], sot.id) - self.assertEqual(CONT_EXAMPLE['name'], sot.name) - self.assertEqual(CONT_EXAMPLE['count'], sot.count) - self.assertEqual(CONT_EXAMPLE['bytes'], sot.bytes) - - def test_create_and_head(self): - sot = container.Container(CONT_EXAMPLE) - - # Update container with HEAD data - sot._attrs.update({'headers': HEAD_EXAMPLE}) - - # Attributes from create - self.assertEqual(CONT_EXAMPLE['name'], sot.id) - self.assertEqual(CONT_EXAMPLE['name'], sot.name) - self.assertEqual(CONT_EXAMPLE['count'], sot.count) - self.assertEqual(CONT_EXAMPLE['bytes'], sot.bytes) - - # Attributes from header - self.assertEqual(int(HEAD_EXAMPLE['x-container-object-count']), - sot.object_count) - self.assertEqual(int(HEAD_EXAMPLE['x-container-bytes-used']), - sot.bytes_used) - self.assertEqual(HEAD_EXAMPLE['x-container-read'], - sot.read_ACL) - self.assertEqual(HEAD_EXAMPLE['x-container-write'], - sot.write_ACL) - self.assertEqual(HEAD_EXAMPLE['x-container-sync-to'], - sot.sync_to) - self.assertEqual(HEAD_EXAMPLE['x-container-sync-key'], - sot.sync_key) - self.assertEqual(HEAD_EXAMPLE['x-versions-location'], - sot.versions_location) - self.assertEqual(HEAD_EXAMPLE['x-timestamp'], sot.timestamp) - - @mock.patch("ecl.resource.Resource.list") - def test_list(self, fake_list): - fake_val = [container.Container.existing(**ex) for ex in LIST_EXAMPLE] - fake_list.return_value = fake_val - - # Since the list method is mocked out, just pass None for the session. - response = container.Container.list(None) - - self.assertEqual(len(LIST_EXAMPLE), len(response)) - for item in range(len(response)): - self.assertEqual(container.Container, type(response[item])) - self.assertEqual(LIST_EXAMPLE[item]["name"], response[item].name) - self.assertEqual(LIST_EXAMPLE[item]["count"], response[item].count) - self.assertEqual(LIST_EXAMPLE[item]["bytes"], response[item].bytes) - - def _test_create_update(self, sot, sot_call, sess_method): - sot.read_ACL = "some ACL" - sot.write_ACL = "another ACL" - sot.is_content_type_detected = True - headers = { - "x-container-read": "some ACL", - "x-container-write": "another ACL", - "x-detect-content-type": True, - "Accept": "", - } - sot_call(self.sess) - - url = "/%s" % CONTAINER_NAME - sess_method.assert_called_with(url, endpoint_filter=sot.service, - headers=headers) - - def test_create(self): - sot = container.Container.new(name=CONTAINER_NAME) - self._test_create_update(sot, sot.create, self.sess.put) - - def test_update(self): - sot = container.Container.new(name=CONTAINER_NAME) - self._test_create_update(sot, sot.update, self.sess.post) - - def _test_no_headers(self, sot, sot_call, sess_method): - sot = container.Container.new(name=CONTAINER_NAME) - sot.create(self.sess) - url = "/%s" % CONTAINER_NAME - headers = {'Accept': ''} - self.sess.put.assert_called_with(url, endpoint_filter=sot.service, - headers=headers) - - def test_create_no_headers(self): - sot = container.Container.new(name=CONTAINER_NAME) - self._test_no_headers(sot, sot.create, self.sess.put) - - def test_update_no_headers(self): - sot = container.Container.new(name=CONTAINER_NAME) - self._test_no_headers(sot, sot.update, self.sess.post) diff --git a/ecl/tests/unit/object_store/v1/test_obj.py b/ecl/tests/unit/object_store/v1/test_obj.py deleted file mode 100755 index 2f55798..0000000 --- a/ecl/tests/unit/object_store/v1/test_obj.py +++ /dev/null @@ -1,137 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock -import testtools - -from ecl.object_store.v1 import obj - - -CONTAINER_NAME = "mycontainer" -OBJECT_NAME = "myobject" - -# Object can receive both last-modified in headers and last_modified in -# the body. However, originally, only last-modified was handled as an -# expected prop but it was named last_modified. Under Python 3, creating -# an Object with the body value last_modified causes the _attrs dictionary -# size to change while iterating over its values as we have an attribute -# called `last_modified` and we attempt to grow an additional attribute -# called `last-modified`, which is the "name" of `last_modified`. -# The same is true of content_type and content-type, or any prop -# attribute which would follow the same pattern. -# This example should represent the body values returned by a GET, so the keys -# must be underscores. -OBJ_EXAMPLE = { - "hash": "243f87b91224d85722564a80fd3cb1f1", - "last_modified": "2014-07-13T18:41:03.319240", - "bytes": 252466, - "name": OBJECT_NAME, - "content_type": "application/octet-stream" -} - -DICT_EXAMPLE = { - 'container': CONTAINER_NAME, - 'name': OBJECT_NAME, - 'content_type': 'application/octet-stream', - 'headers': { - 'content-length': '252466', - 'accept-ranges': 'bytes', - 'last-modified': 'Sun, 13 Jul 2014 18:41:04 GMT', - 'etag': '243f87b91224d85722564a80fd3cb1f1', - 'x-timestamp': '1453414256.28112', - 'date': 'Thu, 28 Aug 2014 14:41:59 GMT', - 'id': 'tx5fb5ad4f4d0846c6b2bc7-0053ff3fb7', - 'x-delete-at': '1453416226.16744' - } -} - - -class TestObject(testtools.TestCase): - - def setUp(self): - super(TestObject, self).setUp() - self.resp = mock.Mock() - self.resp.content = "lol here's some content" - self.resp.headers = {"X-Trans-Id": "abcdef"} - self.sess = mock.Mock() - self.sess.get = mock.Mock(return_value=self.resp) - self.sess.put = mock.Mock(return_value=self.resp) - self.sess.post = mock.Mock(return_value=self.resp) - - def test_basic(self): - sot = obj.Object.new(**OBJ_EXAMPLE) - self.assertIsNone(sot.resources_key) - self.assertEqual("name", sot.id_attribute) - self.assertEqual('/%(container)s', sot.base_path) - self.assertEqual('object-store', sot.service.service_type) - self.assertTrue(sot.allow_update) - self.assertTrue(sot.allow_create) - self.assertTrue(sot.allow_retrieve) - self.assertTrue(sot.allow_delete) - self.assertTrue(sot.allow_list) - self.assertTrue(sot.allow_head) - - def test_new(self): - sot = obj.Object.new(container=CONTAINER_NAME, name=OBJECT_NAME) - self.assertEqual(OBJECT_NAME, sot.name) - self.assertEqual(CONTAINER_NAME, sot.container) - - def test_head(self): - sot = obj.Object.existing(**DICT_EXAMPLE) - - # Attributes from header - self.assertEqual(DICT_EXAMPLE['container'], sot.container) - headers = DICT_EXAMPLE['headers'] - self.assertEqual(headers['content-length'], sot.content_length) - self.assertEqual(headers['accept-ranges'], sot.accept_ranges) - self.assertEqual(headers['last-modified'], sot.last_modified_at) - self.assertEqual(headers['etag'], sot.etag) - self.assertEqual(headers['x-timestamp'], sot.timestamp) - self.assertEqual(headers['content-type'], sot.content_type) - self.assertEqual(headers['x-delete-at'], sot.delete_at) - - def test_get(self): - sot = obj.Object.new(container=CONTAINER_NAME, name=OBJECT_NAME) - sot.is_newest = True - sot.if_match = {"who": "what"} - - rv = sot.get(self.sess) - - url = "%s/%s" % (CONTAINER_NAME, OBJECT_NAME) - # TODO(thowe): Should allow filtering bug #1488269 - # headers = { - # "x-newest": True, - # "if-match": {"who": "what"} - # } - headers = {'Accept': 'bytes'} - self.sess.get.assert_called_with(url, endpoint_filter=sot.service, - headers=headers) - self.assertEqual(self.resp.content, rv) - - def _test_create(self, method, data, accept): - sot = obj.Object.new(container=CONTAINER_NAME, name=OBJECT_NAME, - data=data) - sot.is_newest = True - headers = {"x-newest": True, "Accept": ""} - - rv = sot.create(self.sess) - - url = "%s/%s" % (CONTAINER_NAME, OBJECT_NAME) - method.assert_called_with(url, endpoint_filter=sot.service, data=data, - headers=headers) - self.assertEqual(self.resp.headers, rv.get_headers()) - - def test_create_data(self): - self._test_create(self.sess.put, "data", "bytes") - - def test_create_no_data(self): - self._test_create(self.sess.post, None, None) diff --git a/ecl/tests/unit/object_store/v1/test_proxy.py b/ecl/tests/unit/object_store/v1/test_proxy.py deleted file mode 100755 index 85b216c..0000000 --- a/ecl/tests/unit/object_store/v1/test_proxy.py +++ /dev/null @@ -1,277 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock -import six - -from ecl.object_store.v1 import _proxy -from ecl.object_store.v1 import account -from ecl.object_store.v1 import container -from ecl.object_store.v1 import obj -from ecl.tests.unit import test_proxy_base - - -class TestObjectStoreProxy(test_proxy_base.TestProxyBase): - - def setUp(self): - super(TestObjectStoreProxy, self).setUp() - self.proxy = _proxy.Proxy(self.session) - - def test_account_metadata_get(self): - self.verify_head(self.proxy.get_account_metadata, account.Account) - - def test_container_metadata_get(self): - self.verify_head(self.proxy.get_container_metadata, - container.Container, value="container") - - def test_container_delete(self): - self.verify_delete(self.proxy.delete_container, - container.Container, False) - - def test_container_delete_ignore(self): - self.verify_delete(self.proxy.delete_container, - container.Container, True) - - def test_container_create_attrs(self): - self.verify_create(self.proxy.create_container, container.Container) - - def test_object_metadata_get(self): - self.verify_head(self.proxy.get_object_metadata, obj.Object, - value="object", container="container") - - def _test_object_delete(self, ignore): - expected_kwargs = {"path_args": {"container": "name"}} - expected_kwargs["ignore_missing"] = ignore - - self._verify2("ecl.proxy.BaseProxy._delete", - self.proxy.delete_object, - method_args=["resource"], - method_kwargs={"container": "name", - "ignore_missing": ignore}, - expected_args=[obj.Object, "resource"], - expected_kwargs=expected_kwargs) - - def test_object_delete(self): - self._test_object_delete(False) - - def test_object_delete_ignore(self): - self._test_object_delete(True) - - def test_object_create_attrs(self): - path_args = {"path_args": {"container": "name"}} - method_kwargs = {"name": "test", "data": "data", "container": "name"} - - expected_kwargs = path_args.copy() - expected_kwargs.update(method_kwargs) - expected_kwargs.pop("container") - - self._verify2("ecl.proxy.BaseProxy._create", - self.proxy.upload_object, - method_kwargs=method_kwargs, - expected_args=[obj.Object], - expected_kwargs=expected_kwargs) - - def test_object_create_no_container(self): - self.assertRaises(ValueError, self.proxy.upload_object) - - def test_object_get(self): - self.verify_get(self.proxy.get_object, obj.Object, - value=["object"], container="container") - - -class Test_containers(TestObjectStoreProxy): - - def setUp(self): - super(Test_containers, self).setUp() - self.proxy = _proxy.Proxy(self.session) - - self.containers_body = [] - for i in range(3): - self.containers_body.append({six.text_type("name"): - six.text_type("container%d" % i)}) - -# @httpretty.activate -# def test_all_containers(self): -# self.stub_url(httpretty.GET, -# path=[container.Container.base_path], -# responses=[httpretty.Response( -# body=json.dumps(self.containers_body), -# status=200, content_type="application/json"), -# httpretty.Response(body=json.dumps([]), -# status=200, content_type="application/json")]) -# -# count = 0 -# for actual, expected in zip(self.proxy.containers(), -# self.containers_body): -# self.assertEqual(expected, actual) -# count += 1 -# self.assertEqual(len(self.containers_body), count) - -# @httpretty.activate -# def test_containers_limited(self): -# limit = len(self.containers_body) + 1 -# limit_param = "?limit=%d" % limit -# -# self.stub_url(httpretty.GET, -# path=[container.Container.base_path + limit_param], -# json=self.containers_body) -# -# count = 0 -# for actual, expected in zip(self.proxy.containers(limit=limit), -# self.containers_body): -# self.assertEqual(actual, expected) -# count += 1 -# -# self.assertEqual(len(self.containers_body), count) -# # Since we've chosen a limit larger than the body, only one request -# # should be made, so it should be the last one. -# self.assertIn(limit_param, httpretty.last_request().path) - -# @httpretty.activate -# def test_containers_with_marker(self): -# marker = six.text_type("container2") -# marker_param = "marker=%s" % marker -# -# self.stub_url(httpretty.GET, -# path=[container.Container.base_path + "?" + -# marker_param], -# json=self.containers_body) -# -# count = 0 -# for actual, expected in zip(self.proxy.containers(marker=marker), -# self.containers_body): -# # Make sure the marker made it into the actual request. -# self.assertIn(marker_param, httpretty.last_request().path) -# self.assertEqual(expected, actual) -# count += 1 -# -# self.assertEqual(len(self.containers_body), count) -# -# # Since we have to make one request beyond the end, because no -# # limit was provided, make sure the last container appears as -# # the marker in this last request. -# self.assertIn(self.containers_body[-1]["name"], -# httpretty.last_request().path) - - -class Test_objects(TestObjectStoreProxy): - - def setUp(self): - super(Test_objects, self).setUp() - self.proxy = _proxy.Proxy(self.session) - - self.container_name = six.text_type("my_container") - - self.objects_body = [] - for i in range(3): - self.objects_body.append({six.text_type("name"): - six.text_type("object%d" % i)}) - - # Returned object bodies have their container inserted. - self.returned_objects = [] - for ob in self.objects_body: - ob[six.text_type("container")] = self.container_name - self.returned_objects.append(ob) - self.assertEqual(len(self.objects_body), len(self.returned_objects)) - -# @httpretty.activate -# def test_all_objects(self): -# self.stub_url(httpretty.GET, -# path=[obj.Object.base_path % -# {"container": self.container_name}], -# responses=[httpretty.Response( -# body=json.dumps(self.objects_body), -# status=200, content_type="application/json"), -# httpretty.Response(body=json.dumps([]), -# status=200, content_type="application/json")]) -# -# count = 0 -# for actual, expected in zip(self.proxy.objects(self.container_name), -# self.returned_objects): -# self.assertEqual(expected, actual) -# count += 1 -# self.assertEqual(len(self.returned_objects), count) - -# @httpretty.activate -# def test_objects_limited(self): -# limit = len(self.objects_body) + 1 -# limit_param = "?limit=%d" % limit -# -# self.stub_url(httpretty.GET, -# path=[obj.Object.base_path % -# {"container": self.container_name} + limit_param], -# json=self.objects_body) -# -# count = 0 -# for actual, expected in zip(self.proxy.objects(self.container_name, -# limit=limit), -# self.returned_objects): -# self.assertEqual(expected, actual) -# count += 1 -# -# self.assertEqual(len(self.returned_objects), count) -# # Since we've chosen a limit larger than the body, only one request -# # should be made, so it should be the last one. -# self.assertIn(limit_param, httpretty.last_request().path) - -# @httpretty.activate -# def test_objects_with_marker(self): -# marker = six.text_type("object2") -# # marker_param = "marker=%s" % marker -# -# self.stub_url(httpretty.GET, -# path=[obj.Object.base_path % -# {"container": self.container_name} + "?" + -# marker_param], -# json=self.objects_body) -# -# count = 0 -# for actual, expected in zip(self.proxy.objects(self.container_name, -# marker=marker), -# self.returned_objects): -# # Make sure the marker made it into the actual request. -# self.assertIn(marker_param, httpretty.last_request().path) -# self.assertEqual(expected, actual) -# count += 1 -# -# self.assertEqual(len(self.returned_objects), count) -# -# # Since we have to make one request beyond the end, because no -# # limit was provided, make sure the last container appears as -# # the marker in this last request. -# self.assertIn(self.returned_objects[-1]["name"], -# httpretty.last_request().path) - - -class Test_download_object(TestObjectStoreProxy): - - @mock.patch("ecl.object_store.v1._proxy.Proxy.get_object") - def test_download(self, mock_get): - the_data = "here's some data" - mock_get.return_value = the_data - ob = mock.Mock() - - fake_open = mock.mock_open() - file_path = "blarga/somefile" - with mock.patch("ecl.object_store.v1._proxy.open", - fake_open, create=True): - self.proxy.download_object(ob, container="tainer", path=file_path) - - fake_open.assert_called_once_with(file_path, "w") - fake_handle = fake_open() - fake_handle.write.assert_called_once_with(the_data) - - -class Test_copy_object(TestObjectStoreProxy): - - def test_copy_object(self): - self.assertRaises(NotImplementedError, self.proxy.copy_object) From c25d175ff06eb196e464c70c2020828f92557d8f Mon Sep 17 00:00:00 2001 From: Keiichi Hikita Date: Mon, 23 Aug 2021 16:23:53 +0900 Subject: [PATCH 09/18] Enable Update with blank parameter (#84) This PR enables update mvNA relevant objects with following parameters. - "" (blank string) - {} (blank object) Co-authored-by: Keiichi Hikita --- ecl/mvna/v1/_proxy.py | 135 +++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 81 deletions(-) diff --git a/ecl/mvna/v1/_proxy.py b/ecl/mvna/v1/_proxy.py index 04a107a..faf6c09 100644 --- a/ecl/mvna/v1/_proxy.py +++ b/ecl/mvna/v1/_proxy.py @@ -57,25 +57,20 @@ def get_load_balancer(self, load_balancer_id, changes=None): return load_balancer.get_resource(self.session, load_balancer_id, changes) - def update_load_balancer(self, load_balancer_id, - name=None, description=None, tags=None): + def update_load_balancer(self, load_balancer_id, **params): """Update Managed Load Balancer Attributes. :param string load_balancer_id: ID 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 + :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 """ - body = {} - if name: - body["name"] = name - if description: - body["description"] = description - if tags: - body["tags"] = tags return self._update(_load_balancer.LoadBalancer, load_balancer_id, - **body) + **params) def delete_load_balancer(self, load_balancer_id, x_mvna_request_id=None, ignore_missing=False): @@ -210,24 +205,20 @@ def get_target_group(self, target_group_id, changes=None): return target_group.get_resource(self.session, target_group_id, changes) - def update_target_group(self, target_group_id, - name=None, description=None, tags=None): + def update_target_group(self, target_group_id, **params): """Update Target Group Attributes. - :param string target_group_id: ID of Target Group - :param string name: Name of Target Group - :param string description: Description of Target Group - :param dict tags: Tags of Target Group + :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 """ - body = {} - if name: - body["name"] = name - if description: - body["description"] = description - if tags: - body["tags"] = tags - return self._update(_target_group.TargetGroup, target_group_id, **body) + return self._update(_target_group.TargetGroup, target_group_id, + **params) def delete_target_group(self, target_group_id, ignore_missing=False): """Delete Target Group. @@ -419,25 +410,20 @@ def get_listener(self, listener_id, changes=None): listener = _listener.Listener() return listener.get_resource(self.session, listener_id, changes) - def update_listener(self, listener_id, - name=None, description=None, tags=None): + def update_listener(self, listener_id, **params): """Update Listener Attributes. :param string listener_id: ID of Listener - :param string name: Name of Listener - :param string description: Description of Listener - :param dict tags: Tags 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 """ - body = {} - if name: - body["name"] = name - if description: - body["description"] = description - if tags: - body["tags"] = tags - return self._update(_listener.Listener, listener_id, - **body) + return self._update(_listener.Listener, listener_id, **params) def delete_listener(self, listener_id, ignore_missing=False): """Delete Listener. @@ -606,25 +592,20 @@ def get_health_monitor(self, health_monitor_id, changes=None): return health_monitor.get_resource(self.session, health_monitor_id, changes) - def update_health_monitor(self, health_monitor_id, - name=None, description=None, tags=None): + def update_health_monitor(self, health_monitor_id, **params): """Update Health Monitor Attributes. :param string health_monitor_id: ID of Health Monitor - :param string name: Name of Health Monitor - :param string description: Description of Health Monitor - :param dict tags: Tags 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 """ - body = {} - if name: - body["name"] = name - if description: - body["description"] = description - if tags: - body["tags"] = tags return self._update(_health_monitor.HealthMonitor, health_monitor_id, - **body) + **params) def delete_health_monitor(self, health_monitor_id, ignore_missing=False): """Delete Health Monitor. @@ -647,7 +628,7 @@ def create_staged_health_monitor_configuration( 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 @@ -696,7 +677,7 @@ def update_staged_health_monitor_configuration( 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 @@ -803,23 +784,19 @@ def get_policy(self, policy_id, changes=None): policy = _policy.Policy() return policy.get_resource(self.session, policy_id, changes) - def update_policy(self, policy_id, name=None, description=None, tags=None): + def update_policy(self, policy_id, **params): """Update Policy Attributes. :param string policy_id: ID of Policy - :param string name: Name of Policy - :param string description: Description of Policy - :param dict tags: Tags 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 """ - body = {} - if name: - body["name"] = name - if description: - body["description"] = description - if tags: - body["tags"] = tags - return self._update(_policy.Policy, policy_id, **body) + return self._update(_policy.Policy, policy_id, **params) def delete_policy(self, policy_id, ignore_missing=False): """Delete Policy. @@ -890,6 +867,7 @@ def get_staged_policy_configuration(self, 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, @@ -984,24 +962,19 @@ def get_route(self, route_id, changes=None): route = _route.Route() return route.get_resource(self.session, route_id, changes) - def update_route(self, route_id, - name=None, description=None, tags=None): + def update_route(self, route_id, **params): """Update Route Attributes. :param string route_id: ID of Route - :param string name: Name of Route - :param string description: Description of Route - :param dict tags: Tags 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 """ - body = {} - if name: - body["name"] = name - if description: - body["description"] = description - if tags: - body["tags"] = tags - return self._update(_route.Route, route_id, **body) + return self._update(_route.Route, route_id, **params) def delete_route(self, route_id, ignore_missing=False): """Delete Route. From 05e8832bbcd2100b91570599ea951e55fb70136b Mon Sep 17 00:00:00 2001 From: shiso Date: Tue, 24 Aug 2021 17:01:58 +0900 Subject: [PATCH 10/18] IF-6142 fix operator of health monitor (#85) * IF-6142 fix operator of health monitor * IF-6142 fix description of param * Update ecl/mvna/v1/_proxy.py Co-authored-by: ysssasaki <64194789+ysssasaki@users.noreply.github.com> * IF-6142 refix operator Co-authored-by: ysssasaki <64194789+ysssasaki@users.noreply.github.com> --- ecl/mvna/v1/_proxy.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ecl/mvna/v1/_proxy.py b/ecl/mvna/v1/_proxy.py index faf6c09..bf0536d 100644 --- a/ecl/mvna/v1/_proxy.py +++ b/ecl/mvna/v1/_proxy.py @@ -632,7 +632,7 @@ def create_staged_health_monitor_configuration( """Create Staged Health Monitor Configuration. :param string health_monitor_id: ID of Health Monitor - :param string port: Port 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 @@ -642,7 +642,7 @@ def create_staged_health_monitor_configuration( :return: Health Monitor """ body = {} - if port: + if port is not None: body["port"] = port if protocol: body["protocol"] = protocol @@ -681,7 +681,7 @@ def update_staged_health_monitor_configuration( """Update Staged Health Monitor Configuration. :param string health_monitor_id: ID of Health Monitor - :param string port: Port 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 @@ -691,7 +691,7 @@ def update_staged_health_monitor_configuration( :return: Health Monitor """ body = {} - if port: + if port is not None: body["port"] = port if protocol: body["protocol"] = protocol From ed4b903c3948dbb97deb00b49fd3faefeffa3c9d Mon Sep 17 00:00:00 2001 From: a-oi-xon <91597807+a-oi-xon@users.noreply.github.com> Date: Tue, 9 Nov 2021 17:10:28 +0900 Subject: [PATCH 11/18] :sparkles: add bto baremetals api (#86) * :sparkles: IF-5903 add bto baremetals api * :sparkles: IF-5903 add bto baremetals api * :sparkles: IF-5903 add bto baremetals api Co-authored-by: oizaki.atsushi --- ecl/baremetal/v2/_proxy.py | 65 ++++++++++-- ecl/baremetal/v2/chassis.py | 64 ++++++++++++ ecl/baremetal/v2/server.py | 11 +++ .../functional/baremetal/test_chassis.py | 83 ++++++++++++++++ ecl/tests/functional/baremetal/test_server.py | 9 ++ ecl/tests/unit/baremetal/v2/test_charssis.py | 99 +++++++++++++++++++ 6 files changed, 325 insertions(+), 6 deletions(-) create mode 100644 ecl/baremetal/v2/chassis.py create mode 100644 ecl/tests/functional/baremetal/test_chassis.py create mode 100644 ecl/tests/unit/baremetal/v2/test_charssis.py diff --git a/ecl/baremetal/v2/_proxy.py b/ecl/baremetal/v2/_proxy.py index 89b1d87..dfba9d1 100755 --- a/ecl/baremetal/v2/_proxy.py +++ b/ecl/baremetal/v2/_proxy.py @@ -21,6 +21,7 @@ from ecl.baremetal.v2 import stock as _stock from ecl.baremetal.v2 import nic_physical_port as _port from ecl.baremetal.v2 import server as _server +from ecl.baremetal.v2 import chassis as _chassis from ecl.baremetal import version as _version from ecl import proxy2 from ecl import session @@ -286,9 +287,9 @@ def find_server(self, name_or_id, ignore_missing=False): """ return self._find(_server.Server, name_or_id, ignore_missing=ignore_missing) - def create_server(self, name, networks, flavor, admin_pass=None, - image=None, key_name=None, availability_zone=None, - user_data=None, raid_arrays=None, + def create_server(self, name, networks, admin_pass=None, image=None, + flavor=None, chassis_id=None, key_name=None, + availability_zone=None, user_data=None, raid_arrays=None, lvm_volume_groups=None, filesystems=None, metadata=None, personality=None): """This API create additional Baremetal server. @@ -297,11 +298,13 @@ def create_server(self, name, networks, flavor, admin_pass=None, :param array networks: Network Array. If it is specified greater than two, default gateway is first network. - :param string flavor: The flavor reference for the desired flavor for your - Baremetal server. :param string admin_pass: Password for the administrator. :param string image: The image reference for the desired image for your Baremetal server. + :param string flavor: The flavor reference for the desired flavor for your + Baremetal server. You can specify either flavor or chassis_id. + :param string chassis_id: The ID of chassis which you use to deploy + Baremetal server. You can specify either flavor or chassis_id. :param string key_name: SSH Keypair name you created on KeyPairs API. :param string availability_zone: The availability zone name in which to launch the server. @@ -318,11 +321,15 @@ def create_server(self, name, networks, flavor, admin_pass=None, esxi. :return: :class:`~ecl.baremetal.v2.server.Server` """ - attrs = {"name": name, "networks": networks, "flavorRef": flavor} + attrs = {"name": name, "networks": networks} if admin_pass: attrs["adminPass"] = admin_pass if image: attrs["imageRef"] = image + if flavor: + attrs["flavorRef"] = flavor + if chassis_id: + attrs["chassis_id"] = chassis_id if key_name: attrs["key_name"] = key_name if availability_zone: @@ -350,6 +357,17 @@ def delete_server(self, server_id): """ return self._delete(_server.Server, server_id) + def update_server(self, server_id, name): + """ This API updates the editable attributes of the specified baremetal server. + + :param string server_id: ID for the specified server. + :param string name: Name of your baremetal server as a string. + :return: :class:`~ecl.baremetal.v2.server.Server` + """ + attrs = {"name": name} + server = _server.Server() + return server.update(self.session, server_id, **attrs) + def start_server(self, server_id): """Power on the Baremetal Server associated with server_id. This request will be accepted only when the task_state is None. @@ -509,3 +527,38 @@ def update_metadata(self, server_id, key, **attr): """ metadata = _metadata.Metadata() return metadata.update(self.session, server_id, key, **attr) + + def chassis(self, details=True): + """Lists all Chassis or ChassisDetail. + + A chassis represents base object of baremetal server. + Each chassis is assigned an unique id and has dedicated disk spaces, + memory capacities and cpu resources. You can create baremetal server + upon this object. + + :param bool details: When set to ``False`` + :class:`~ecl.baremetal.v2.chassis.Chassis` instance + will be returned. The default, ``True``, will cause + :class:`~ecl.baremetal.v2.chassis.ChassisDetail` + instances to be returned. + + :return: A List of :class:`~ecl.baremetal.v2.chassis.Chassis` or + :class:`~ecl.baremetal.v2.chassis.ChassisDetail` + """ + chassis = _chassis.ChassisDetail if details else _chassis.Chassis + return list(self._list(chassis)) + + def get_chassis(self, chassis_id): + """Gets details for a ChassisDetail associated with chassis_id. + + A chassis represents base object of baremetal server. + Each chassis is assigned an unique id and has dedicated disk spaces, + memory capacities and cpu resources. You can create baremetal server + upon this object. + + :param string chassis_id: ID for the chassis. + :return: :class:`~ecl.baremetal.v2.chassis.Chassis` + """ + # Use "Chassis" instead of "ChassisDetail". + # Because "detail" is not included to the request path. + return self._get(_chassis.Chassis, chassis_id) diff --git a/ecl/baremetal/v2/chassis.py b/ecl/baremetal/v2/chassis.py new file mode 100644 index 0000000..713c61d --- /dev/null +++ b/ecl/baremetal/v2/chassis.py @@ -0,0 +1,64 @@ +# 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.baremetal import baremetal_service +from ecl import resource2 + + +class Chassis(resource2.Resource): + """Chassis Resource""" + + resource_key = 'chassis' + resources_key = 'chassis' + base_path = '/chassis' + service = baremetal_service.BaremetalService() + + # Capabilities + allow_get = True + allow_list = True + + # Properties + #: The ID for the chassis, which is a unique integer value. + id = resource2.Body('id') + #: The name of availability zone where chassis exists. + availability_zone = resource2.Body('availability_zone') + #: The name of flavor of chassis. + flavor_name = resource2.Body('flavor_name') + #: The object of summarized hardware spec. That has cpus, disks and rams. + hardware_summary = resource2.Body('hardware_summary', type=dict) + #: The status of chassis. + status = resource2.Body('status') + #: The ID of server attached to chassis. If no server is attached to chassis, the value is null. + server_id = resource2.Body('server_id') + #: The name of server attached to chassis. If no server is attached to chassis, the value is null. + server_name = resource2.Body('server_name') + #: The minimum contract period of your chassis. + contract_year = resource2.Body('contract_year', type=int) + #: The date that you start to use the chassis. + start_time = resource2.Body('start_time') + + # Properties (for Detail) + #: The spec of all cpus installed in chassis. + cpus = resource2.Body('cpus', type=list) + #: The spec of all disks installed in chassis. + disks = resource2.Body('disks', type=list) + #: The spec of all rams installed in chassis. + rams = resource2.Body('rams', type=list) + + +class ChassisDetail(Chassis): + """ChassisDetail Resource""" + + base_path = '/chassis/detail' + + # Capabilities + allow_get = False diff --git a/ecl/baremetal/v2/server.py b/ecl/baremetal/v2/server.py index 56b2316..77381de 100755 --- a/ecl/baremetal/v2/server.py +++ b/ecl/baremetal/v2/server.py @@ -26,6 +26,7 @@ class Server(resource2.Resource): allow_list = True allow_create = True allow_delete = True + allow_update = True # Properties #: UUID of the Baremetal server. @@ -115,6 +116,16 @@ def create(self, session, **attrs): self._translate_response(resp, has_body=True) return self + def update(self, session, server_id, **attrs): + url = "%s/%s" % (self.base_path, server_id) + body = {"server": attrs} + resp = session.put(url, + endpoint_filter=self.service, + json=body, + headers={"Accept": "application/json"}) + self._translate_response(resp, has_body=True) + return self + class ServerDetail(Server): base_path = '/servers/detail' diff --git a/ecl/tests/functional/baremetal/test_chassis.py b/ecl/tests/functional/baremetal/test_chassis.py new file mode 100644 index 0000000..69d8472 --- /dev/null +++ b/ecl/tests/functional/baremetal/test_chassis.py @@ -0,0 +1,83 @@ +# 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 six + +from ecl.tests.functional import base + + +class TestChassis(base.BaseFunctionalTest): + + def test_chassis(self): + chassis_list = list(self.conn.baremetal.chassis(details=False)) + self.assertGreater(len(chassis_list), 0) + + for chassis in chassis_list: + print(chassis) + self.assertIsInstance(chassis.id, six.string_types) + self.assertIsInstance(chassis.availability_zone, six.string_types) + self.assertIsInstance(chassis.flavor_name, six.string_types) + self.assertIsInstance(chassis.hardware_summary, dict) + self.assertIsInstance(chassis.status, six.string_types) + self.assertIsInstance(chassis.server_id, + (six.string_types, type(None))) + self.assertIsInstance(chassis.server_name, + (six.string_types, type(None))) + self.assertIsInstance(chassis.contract_year, int) + self.assertIsInstance(chassis.start_time, six.string_types) + + def test_chassis_detail(self): + chassis_list = list(self.conn.baremetal.chassis(details=True)) + self.assertGreater(len(chassis_list), 0) + + for chassis in chassis_list: + print(chassis) + self.assertIsInstance(chassis.id, six.string_types) + self.assertIsInstance(chassis.availability_zone, six.string_types) + self.assertIsInstance(chassis.flavor_name, six.string_types) + self.assertIsInstance(chassis.hardware_summary, dict) + self.assertIsInstance(chassis.status, six.string_types) + self.assertIsInstance(chassis.server_id, + (six.string_types, type(None))) + self.assertIsInstance(chassis.server_name, + (six.string_types, type(None))) + self.assertIsInstance(chassis.contract_year, int) + self.assertIsInstance(chassis.start_time, six.string_types) + + self.assertIsInstance(chassis.cpus, list) + self.assertIsInstance(chassis.disks, list) + self.assertIsInstance(chassis.rams, list) + + def test_get_chassis(self): + # ChassisIDはMock Serverに合わせて変更する + chassis_id = '31e7a0c4-f49e-19e6-2192-c9f9cc6f5a74' + + chassis = self.conn.baremetal.get_chassis(chassis_id) + print(chassis) + # Mock Serverを使用するとランダムなUUIDが返却されるのでパスパラメータを一致しない + # self.assertEqual(chassis.id, chassis_id) + + self.assertIsInstance(chassis.availability_zone, six.string_types) + self.assertIsInstance(chassis.flavor_name, six.string_types) + self.assertIsInstance(chassis.hardware_summary, dict) + self.assertIsInstance(chassis.status, six.string_types) + self.assertIsInstance(chassis.server_id, + (six.string_types, type(None))) + self.assertIsInstance(chassis.server_name, + (six.string_types, type(None))) + self.assertIsInstance(chassis.contract_year, int) + self.assertIsInstance(chassis.start_time, six.string_types) + + self.assertIsInstance(chassis.cpus, list) + self.assertIsInstance(chassis.disks, list) + self.assertIsInstance(chassis.rams, list) + \ No newline at end of file diff --git a/ecl/tests/functional/baremetal/test_server.py b/ecl/tests/functional/baremetal/test_server.py index d8a7271..e2e011f 100755 --- a/ecl/tests/functional/baremetal/test_server.py +++ b/ecl/tests/functional/baremetal/test_server.py @@ -72,3 +72,12 @@ def test_04_show_server(self): def test_05_delete_server(self): server = self.conn.baremetal.delete_server("752aac2e-4b82-4d47-a7c7-xx") assert False + + def test_06_update_server(self): + # ServerIDはMock Serverに合わせて変更する + server_id = "3072a550-2ff4-a9d6-438b-0ce8b650eaa5" + name = "hoge" + + server = self.conn.baremetal.update_server(server_id, name) + print(server) + self.assertIsInstance(server.id, six.string_types) diff --git a/ecl/tests/unit/baremetal/v2/test_charssis.py b/ecl/tests/unit/baremetal/v2/test_charssis.py new file mode 100644 index 0000000..95e123d --- /dev/null +++ b/ecl/tests/unit/baremetal/v2/test_charssis.py @@ -0,0 +1,99 @@ +# 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.baremetal.v2 import chassis + +IDENTIFIER = 'IDENTIFIER' +CHASSIS_EXAMPLE = { + 'id': IDENTIFIER, + 'availability_zone': '2', + 'flavor_name': '3', + 'hardware_summary': {'4': 4}, + 'status': '5', + 'server_id': '6', + 'server_name': '7', + 'contract_year': 8, + 'start_time': '9', +} + +CHASSIS_DETAIL_EXAMPLE = { + 'id': IDENTIFIER, + 'availability_zone': '2', + 'flavor_name': '3', + 'hardware_summary': {'4': 4}, + 'status': '5', + 'server_id': '6', + 'server_name': '7', + 'contract_year': 8, + 'start_time': '9', + 'cpus': [{'10': 10},], + 'disks': [{'11': 11},], + 'rams': [{'12': 12},], +} +from unittest.mock import patch + +class TestChassis(testtools.TestCase): + + def test_basic(self): + sot = chassis.Chassis() + self.assertEqual('chassis', sot.resource_key) + self.assertEqual('chassis', sot.resources_key) + self.assertEqual('/chassis', sot.base_path) + self.assertEqual('baremetal-server', sot.service.service_type) + self.assertTrue(sot.allow_get) + self.assertTrue(sot.allow_list) + self.assertFalse(sot.allow_create) + self.assertFalse(sot.allow_delete) + self.assertFalse(sot.allow_update) + self.assertFalse(sot.allow_head) + + def test_make_basic(self): + sot = chassis.Chassis(**CHASSIS_EXAMPLE) + self.assertEqual(CHASSIS_EXAMPLE['id'], sot.id) + self.assertEqual(CHASSIS_EXAMPLE['availability_zone'], sot.availability_zone) + self.assertEqual(CHASSIS_EXAMPLE['flavor_name'], sot.flavor_name) + self.assertEqual(CHASSIS_EXAMPLE['hardware_summary'], sot.hardware_summary) + self.assertEqual(CHASSIS_EXAMPLE['status'], sot.status) + self.assertEqual(CHASSIS_EXAMPLE['server_id'], sot.server_id) + self.assertEqual(CHASSIS_EXAMPLE['server_name'], sot.server_name) + self.assertEqual(CHASSIS_EXAMPLE['contract_year'], sot.contract_year) + self.assertEqual(CHASSIS_EXAMPLE['start_time'], sot.start_time) + + def test_detail(self): + sot = chassis.ChassisDetail() + self.assertEqual('chassis', sot.resource_key) + self.assertEqual('chassis', sot.resources_key) + self.assertEqual('/chassis/detail', sot.base_path) + self.assertEqual('baremetal-server', sot.service.service_type) + self.assertFalse(sot.allow_get) + self.assertTrue(sot.allow_list) + self.assertFalse(sot.allow_create) + self.assertFalse(sot.allow_delete) + self.assertFalse(sot.allow_update) + self.assertFalse(sot.allow_head) + + def test_make_detail(self): + sot = chassis.ChassisDetail(**CHASSIS_DETAIL_EXAMPLE) + self.assertEqual(CHASSIS_DETAIL_EXAMPLE['id'], sot.id) + self.assertEqual(CHASSIS_DETAIL_EXAMPLE['availability_zone'], sot.availability_zone) + self.assertEqual(CHASSIS_DETAIL_EXAMPLE['flavor_name'], sot.flavor_name) + self.assertEqual(CHASSIS_DETAIL_EXAMPLE['hardware_summary'], sot.hardware_summary) + self.assertEqual(CHASSIS_DETAIL_EXAMPLE['status'], sot.status) + self.assertEqual(CHASSIS_DETAIL_EXAMPLE['server_id'], sot.server_id) + self.assertEqual(CHASSIS_DETAIL_EXAMPLE['server_name'], sot.server_name) + self.assertEqual(CHASSIS_DETAIL_EXAMPLE['contract_year'], sot.contract_year) + self.assertEqual(CHASSIS_DETAIL_EXAMPLE['start_time'], sot.start_time) + self.assertEqual(CHASSIS_DETAIL_EXAMPLE['cpus'], sot.cpus) + self.assertEqual(CHASSIS_DETAIL_EXAMPLE['disks'], sot.disks) + self.assertEqual(CHASSIS_DETAIL_EXAMPLE['rams'], sot.rams) From eb587cbbc05c06c8f3b1acc2b75614fb7acf0e74 Mon Sep 17 00:00:00 2001 From: a-oi-xon <91597807+a-oi-xon@users.noreply.github.com> Date: Mon, 29 Nov 2021 16:45:54 +0900 Subject: [PATCH 12/18] Revert ":sparkles: add bto baremetals api (#86)" (#87) This reverts commit ed4b903c3948dbb97deb00b49fd3faefeffa3c9d. --- ecl/baremetal/v2/_proxy.py | 65 ++---------- ecl/baremetal/v2/chassis.py | 64 ------------ ecl/baremetal/v2/server.py | 11 --- .../functional/baremetal/test_chassis.py | 83 ---------------- ecl/tests/functional/baremetal/test_server.py | 9 -- ecl/tests/unit/baremetal/v2/test_charssis.py | 99 ------------------- 6 files changed, 6 insertions(+), 325 deletions(-) delete mode 100644 ecl/baremetal/v2/chassis.py delete mode 100644 ecl/tests/functional/baremetal/test_chassis.py delete mode 100644 ecl/tests/unit/baremetal/v2/test_charssis.py diff --git a/ecl/baremetal/v2/_proxy.py b/ecl/baremetal/v2/_proxy.py index dfba9d1..89b1d87 100755 --- a/ecl/baremetal/v2/_proxy.py +++ b/ecl/baremetal/v2/_proxy.py @@ -21,7 +21,6 @@ from ecl.baremetal.v2 import stock as _stock from ecl.baremetal.v2 import nic_physical_port as _port from ecl.baremetal.v2 import server as _server -from ecl.baremetal.v2 import chassis as _chassis from ecl.baremetal import version as _version from ecl import proxy2 from ecl import session @@ -287,9 +286,9 @@ def find_server(self, name_or_id, ignore_missing=False): """ return self._find(_server.Server, name_or_id, ignore_missing=ignore_missing) - def create_server(self, name, networks, admin_pass=None, image=None, - flavor=None, chassis_id=None, key_name=None, - availability_zone=None, user_data=None, raid_arrays=None, + def create_server(self, name, networks, flavor, admin_pass=None, + image=None, key_name=None, availability_zone=None, + user_data=None, raid_arrays=None, lvm_volume_groups=None, filesystems=None, metadata=None, personality=None): """This API create additional Baremetal server. @@ -298,13 +297,11 @@ def create_server(self, name, networks, admin_pass=None, image=None, :param array networks: Network Array. If it is specified greater than two, default gateway is first network. + :param string flavor: The flavor reference for the desired flavor for your + Baremetal server. :param string admin_pass: Password for the administrator. :param string image: The image reference for the desired image for your Baremetal server. - :param string flavor: The flavor reference for the desired flavor for your - Baremetal server. You can specify either flavor or chassis_id. - :param string chassis_id: The ID of chassis which you use to deploy - Baremetal server. You can specify either flavor or chassis_id. :param string key_name: SSH Keypair name you created on KeyPairs API. :param string availability_zone: The availability zone name in which to launch the server. @@ -321,15 +318,11 @@ def create_server(self, name, networks, admin_pass=None, image=None, esxi. :return: :class:`~ecl.baremetal.v2.server.Server` """ - attrs = {"name": name, "networks": networks} + attrs = {"name": name, "networks": networks, "flavorRef": flavor} if admin_pass: attrs["adminPass"] = admin_pass if image: attrs["imageRef"] = image - if flavor: - attrs["flavorRef"] = flavor - if chassis_id: - attrs["chassis_id"] = chassis_id if key_name: attrs["key_name"] = key_name if availability_zone: @@ -357,17 +350,6 @@ def delete_server(self, server_id): """ return self._delete(_server.Server, server_id) - def update_server(self, server_id, name): - """ This API updates the editable attributes of the specified baremetal server. - - :param string server_id: ID for the specified server. - :param string name: Name of your baremetal server as a string. - :return: :class:`~ecl.baremetal.v2.server.Server` - """ - attrs = {"name": name} - server = _server.Server() - return server.update(self.session, server_id, **attrs) - def start_server(self, server_id): """Power on the Baremetal Server associated with server_id. This request will be accepted only when the task_state is None. @@ -527,38 +509,3 @@ def update_metadata(self, server_id, key, **attr): """ metadata = _metadata.Metadata() return metadata.update(self.session, server_id, key, **attr) - - def chassis(self, details=True): - """Lists all Chassis or ChassisDetail. - - A chassis represents base object of baremetal server. - Each chassis is assigned an unique id and has dedicated disk spaces, - memory capacities and cpu resources. You can create baremetal server - upon this object. - - :param bool details: When set to ``False`` - :class:`~ecl.baremetal.v2.chassis.Chassis` instance - will be returned. The default, ``True``, will cause - :class:`~ecl.baremetal.v2.chassis.ChassisDetail` - instances to be returned. - - :return: A List of :class:`~ecl.baremetal.v2.chassis.Chassis` or - :class:`~ecl.baremetal.v2.chassis.ChassisDetail` - """ - chassis = _chassis.ChassisDetail if details else _chassis.Chassis - return list(self._list(chassis)) - - def get_chassis(self, chassis_id): - """Gets details for a ChassisDetail associated with chassis_id. - - A chassis represents base object of baremetal server. - Each chassis is assigned an unique id and has dedicated disk spaces, - memory capacities and cpu resources. You can create baremetal server - upon this object. - - :param string chassis_id: ID for the chassis. - :return: :class:`~ecl.baremetal.v2.chassis.Chassis` - """ - # Use "Chassis" instead of "ChassisDetail". - # Because "detail" is not included to the request path. - return self._get(_chassis.Chassis, chassis_id) diff --git a/ecl/baremetal/v2/chassis.py b/ecl/baremetal/v2/chassis.py deleted file mode 100644 index 713c61d..0000000 --- a/ecl/baremetal/v2/chassis.py +++ /dev/null @@ -1,64 +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.baremetal import baremetal_service -from ecl import resource2 - - -class Chassis(resource2.Resource): - """Chassis Resource""" - - resource_key = 'chassis' - resources_key = 'chassis' - base_path = '/chassis' - service = baremetal_service.BaremetalService() - - # Capabilities - allow_get = True - allow_list = True - - # Properties - #: The ID for the chassis, which is a unique integer value. - id = resource2.Body('id') - #: The name of availability zone where chassis exists. - availability_zone = resource2.Body('availability_zone') - #: The name of flavor of chassis. - flavor_name = resource2.Body('flavor_name') - #: The object of summarized hardware spec. That has cpus, disks and rams. - hardware_summary = resource2.Body('hardware_summary', type=dict) - #: The status of chassis. - status = resource2.Body('status') - #: The ID of server attached to chassis. If no server is attached to chassis, the value is null. - server_id = resource2.Body('server_id') - #: The name of server attached to chassis. If no server is attached to chassis, the value is null. - server_name = resource2.Body('server_name') - #: The minimum contract period of your chassis. - contract_year = resource2.Body('contract_year', type=int) - #: The date that you start to use the chassis. - start_time = resource2.Body('start_time') - - # Properties (for Detail) - #: The spec of all cpus installed in chassis. - cpus = resource2.Body('cpus', type=list) - #: The spec of all disks installed in chassis. - disks = resource2.Body('disks', type=list) - #: The spec of all rams installed in chassis. - rams = resource2.Body('rams', type=list) - - -class ChassisDetail(Chassis): - """ChassisDetail Resource""" - - base_path = '/chassis/detail' - - # Capabilities - allow_get = False diff --git a/ecl/baremetal/v2/server.py b/ecl/baremetal/v2/server.py index 77381de..56b2316 100755 --- a/ecl/baremetal/v2/server.py +++ b/ecl/baremetal/v2/server.py @@ -26,7 +26,6 @@ class Server(resource2.Resource): allow_list = True allow_create = True allow_delete = True - allow_update = True # Properties #: UUID of the Baremetal server. @@ -116,16 +115,6 @@ def create(self, session, **attrs): self._translate_response(resp, has_body=True) return self - def update(self, session, server_id, **attrs): - url = "%s/%s" % (self.base_path, server_id) - body = {"server": attrs} - resp = session.put(url, - endpoint_filter=self.service, - json=body, - headers={"Accept": "application/json"}) - self._translate_response(resp, has_body=True) - return self - class ServerDetail(Server): base_path = '/servers/detail' diff --git a/ecl/tests/functional/baremetal/test_chassis.py b/ecl/tests/functional/baremetal/test_chassis.py deleted file mode 100644 index 69d8472..0000000 --- a/ecl/tests/functional/baremetal/test_chassis.py +++ /dev/null @@ -1,83 +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 six - -from ecl.tests.functional import base - - -class TestChassis(base.BaseFunctionalTest): - - def test_chassis(self): - chassis_list = list(self.conn.baremetal.chassis(details=False)) - self.assertGreater(len(chassis_list), 0) - - for chassis in chassis_list: - print(chassis) - self.assertIsInstance(chassis.id, six.string_types) - self.assertIsInstance(chassis.availability_zone, six.string_types) - self.assertIsInstance(chassis.flavor_name, six.string_types) - self.assertIsInstance(chassis.hardware_summary, dict) - self.assertIsInstance(chassis.status, six.string_types) - self.assertIsInstance(chassis.server_id, - (six.string_types, type(None))) - self.assertIsInstance(chassis.server_name, - (six.string_types, type(None))) - self.assertIsInstance(chassis.contract_year, int) - self.assertIsInstance(chassis.start_time, six.string_types) - - def test_chassis_detail(self): - chassis_list = list(self.conn.baremetal.chassis(details=True)) - self.assertGreater(len(chassis_list), 0) - - for chassis in chassis_list: - print(chassis) - self.assertIsInstance(chassis.id, six.string_types) - self.assertIsInstance(chassis.availability_zone, six.string_types) - self.assertIsInstance(chassis.flavor_name, six.string_types) - self.assertIsInstance(chassis.hardware_summary, dict) - self.assertIsInstance(chassis.status, six.string_types) - self.assertIsInstance(chassis.server_id, - (six.string_types, type(None))) - self.assertIsInstance(chassis.server_name, - (six.string_types, type(None))) - self.assertIsInstance(chassis.contract_year, int) - self.assertIsInstance(chassis.start_time, six.string_types) - - self.assertIsInstance(chassis.cpus, list) - self.assertIsInstance(chassis.disks, list) - self.assertIsInstance(chassis.rams, list) - - def test_get_chassis(self): - # ChassisIDはMock Serverに合わせて変更する - chassis_id = '31e7a0c4-f49e-19e6-2192-c9f9cc6f5a74' - - chassis = self.conn.baremetal.get_chassis(chassis_id) - print(chassis) - # Mock Serverを使用するとランダムなUUIDが返却されるのでパスパラメータを一致しない - # self.assertEqual(chassis.id, chassis_id) - - self.assertIsInstance(chassis.availability_zone, six.string_types) - self.assertIsInstance(chassis.flavor_name, six.string_types) - self.assertIsInstance(chassis.hardware_summary, dict) - self.assertIsInstance(chassis.status, six.string_types) - self.assertIsInstance(chassis.server_id, - (six.string_types, type(None))) - self.assertIsInstance(chassis.server_name, - (six.string_types, type(None))) - self.assertIsInstance(chassis.contract_year, int) - self.assertIsInstance(chassis.start_time, six.string_types) - - self.assertIsInstance(chassis.cpus, list) - self.assertIsInstance(chassis.disks, list) - self.assertIsInstance(chassis.rams, list) - \ No newline at end of file diff --git a/ecl/tests/functional/baremetal/test_server.py b/ecl/tests/functional/baremetal/test_server.py index e2e011f..d8a7271 100755 --- a/ecl/tests/functional/baremetal/test_server.py +++ b/ecl/tests/functional/baremetal/test_server.py @@ -72,12 +72,3 @@ def test_04_show_server(self): def test_05_delete_server(self): server = self.conn.baremetal.delete_server("752aac2e-4b82-4d47-a7c7-xx") assert False - - def test_06_update_server(self): - # ServerIDはMock Serverに合わせて変更する - server_id = "3072a550-2ff4-a9d6-438b-0ce8b650eaa5" - name = "hoge" - - server = self.conn.baremetal.update_server(server_id, name) - print(server) - self.assertIsInstance(server.id, six.string_types) diff --git a/ecl/tests/unit/baremetal/v2/test_charssis.py b/ecl/tests/unit/baremetal/v2/test_charssis.py deleted file mode 100644 index 95e123d..0000000 --- a/ecl/tests/unit/baremetal/v2/test_charssis.py +++ /dev/null @@ -1,99 +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.baremetal.v2 import chassis - -IDENTIFIER = 'IDENTIFIER' -CHASSIS_EXAMPLE = { - 'id': IDENTIFIER, - 'availability_zone': '2', - 'flavor_name': '3', - 'hardware_summary': {'4': 4}, - 'status': '5', - 'server_id': '6', - 'server_name': '7', - 'contract_year': 8, - 'start_time': '9', -} - -CHASSIS_DETAIL_EXAMPLE = { - 'id': IDENTIFIER, - 'availability_zone': '2', - 'flavor_name': '3', - 'hardware_summary': {'4': 4}, - 'status': '5', - 'server_id': '6', - 'server_name': '7', - 'contract_year': 8, - 'start_time': '9', - 'cpus': [{'10': 10},], - 'disks': [{'11': 11},], - 'rams': [{'12': 12},], -} -from unittest.mock import patch - -class TestChassis(testtools.TestCase): - - def test_basic(self): - sot = chassis.Chassis() - self.assertEqual('chassis', sot.resource_key) - self.assertEqual('chassis', sot.resources_key) - self.assertEqual('/chassis', sot.base_path) - self.assertEqual('baremetal-server', sot.service.service_type) - self.assertTrue(sot.allow_get) - self.assertTrue(sot.allow_list) - self.assertFalse(sot.allow_create) - self.assertFalse(sot.allow_delete) - self.assertFalse(sot.allow_update) - self.assertFalse(sot.allow_head) - - def test_make_basic(self): - sot = chassis.Chassis(**CHASSIS_EXAMPLE) - self.assertEqual(CHASSIS_EXAMPLE['id'], sot.id) - self.assertEqual(CHASSIS_EXAMPLE['availability_zone'], sot.availability_zone) - self.assertEqual(CHASSIS_EXAMPLE['flavor_name'], sot.flavor_name) - self.assertEqual(CHASSIS_EXAMPLE['hardware_summary'], sot.hardware_summary) - self.assertEqual(CHASSIS_EXAMPLE['status'], sot.status) - self.assertEqual(CHASSIS_EXAMPLE['server_id'], sot.server_id) - self.assertEqual(CHASSIS_EXAMPLE['server_name'], sot.server_name) - self.assertEqual(CHASSIS_EXAMPLE['contract_year'], sot.contract_year) - self.assertEqual(CHASSIS_EXAMPLE['start_time'], sot.start_time) - - def test_detail(self): - sot = chassis.ChassisDetail() - self.assertEqual('chassis', sot.resource_key) - self.assertEqual('chassis', sot.resources_key) - self.assertEqual('/chassis/detail', sot.base_path) - self.assertEqual('baremetal-server', sot.service.service_type) - self.assertFalse(sot.allow_get) - self.assertTrue(sot.allow_list) - self.assertFalse(sot.allow_create) - self.assertFalse(sot.allow_delete) - self.assertFalse(sot.allow_update) - self.assertFalse(sot.allow_head) - - def test_make_detail(self): - sot = chassis.ChassisDetail(**CHASSIS_DETAIL_EXAMPLE) - self.assertEqual(CHASSIS_DETAIL_EXAMPLE['id'], sot.id) - self.assertEqual(CHASSIS_DETAIL_EXAMPLE['availability_zone'], sot.availability_zone) - self.assertEqual(CHASSIS_DETAIL_EXAMPLE['flavor_name'], sot.flavor_name) - self.assertEqual(CHASSIS_DETAIL_EXAMPLE['hardware_summary'], sot.hardware_summary) - self.assertEqual(CHASSIS_DETAIL_EXAMPLE['status'], sot.status) - self.assertEqual(CHASSIS_DETAIL_EXAMPLE['server_id'], sot.server_id) - self.assertEqual(CHASSIS_DETAIL_EXAMPLE['server_name'], sot.server_name) - self.assertEqual(CHASSIS_DETAIL_EXAMPLE['contract_year'], sot.contract_year) - self.assertEqual(CHASSIS_DETAIL_EXAMPLE['start_time'], sot.start_time) - self.assertEqual(CHASSIS_DETAIL_EXAMPLE['cpus'], sot.cpus) - self.assertEqual(CHASSIS_DETAIL_EXAMPLE['disks'], sot.disks) - self.assertEqual(CHASSIS_DETAIL_EXAMPLE['rams'], sot.rams) From 2c268d351d1ae95ccc126778aec82fb67640fabe Mon Sep 17 00:00:00 2001 From: "yamazaki.tomoka" Date: Wed, 1 Dec 2021 10:32:15 +0900 Subject: [PATCH 13/18] :sparkles: IF-6595 fix sss api to v2 --- ecl/profile.py | 2 +- ecl/sss/sss_service.py | 2 +- ecl/sss/v2/__init__.py | 0 ecl/sss/v2/_proxy.py | 602 ++++++++++++++++++++++++++++++++++++++++ ecl/sss/v2/api_key.py | 39 +++ ecl/sss/v2/channel.py | 50 ++++ ecl/sss/v2/contract.py | 140 ++++++++++ ecl/sss/v2/iam_group.py | 96 +++++++ ecl/sss/v2/iam_role.py | 46 +++ ecl/sss/v2/tenant.py | 79 ++++++ ecl/sss/v2/user.py | 117 ++++++++ ecl/sss/v2/workspace.py | 55 ++++ 12 files changed, 1226 insertions(+), 2 deletions(-) create mode 100644 ecl/sss/v2/__init__.py create mode 100644 ecl/sss/v2/_proxy.py create mode 100644 ecl/sss/v2/api_key.py create mode 100644 ecl/sss/v2/channel.py create mode 100644 ecl/sss/v2/contract.py create mode 100644 ecl/sss/v2/iam_group.py create mode 100644 ecl/sss/v2/iam_role.py create mode 100644 ecl/sss/v2/tenant.py create mode 100644 ecl/sss/v2/user.py create mode 100644 ecl/sss/v2/workspace.py diff --git a/ecl/profile.py b/ecl/profile.py index abbe8d1..683c087 100755 --- a/ecl/profile.py +++ b/ecl/profile.py @@ -106,7 +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(sss_service.SssService(version="v2")) self._add_service( orchestration_service.OrchestrationService(version="v1")) self._add_service( diff --git a/ecl/sss/sss_service.py b/ecl/sss/sss_service.py index e25fbf6..3c24235 100755 --- a/ecl/sss/sss_service.py +++ b/ecl/sss/sss_service.py @@ -16,7 +16,7 @@ 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.""" diff --git a/ecl/sss/v2/__init__.py b/ecl/sss/v2/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ecl/sss/v2/_proxy.py b/ecl/sss/v2/_proxy.py new file mode 100644 index 0000000..956e919 --- /dev/null +++ b/ecl/sss/v2/_proxy.py @@ -0,0 +1,602 @@ +# 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 role as _role +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 delete_tenant(self, tenant, ignore_missing = True): + """ + Delete tenant. Only supser user (contract owner user) allowed. + + :param tenant: Delete target tenant's tenant 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(_tenant.Tenant, tenant, ignore_missing=ignore_missing) + ''' + + ''' + def create_role(self, user_id, tenant_id): + """ + Create role between a user and a tenant. With role, users can access + to the tenants. + + :param user_id: User which have new role. + :param tenant_id: Tenant which the user have role. + :return: :class:`~ecl.sss.v2.role.Role` + """ + body = {} + body["user_id"] = user_id + body["tenant_id"] = tenant_id + return self._create(_role.Role, **body) + ''' + + ''' + def delete_role(self, tenant_id, user_id): + """ + Delete role between user and tenant. Contract owner user always have + role to all tenants in the contract. Only supser user + (contract owner user) allowed. + + :param tenant_id: Delete target tenant's tenant id. + :param user_id: User's id of the role + :return: ``None`` + """ + role = _role.Role() + return role.delete(session=self.session, + tenant_id=tenant_id, user_id=user_id) + ''' + + 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_billing_info(self, channel_id, target_month): + """ + Get billing statement of designated month. + + :param channel_id: Billing statement owner contract. + :param target_month: Target billing month with YYYY-MM format + :return: One :class:`~ecl.sss.v2.contract.Contract` + """ + bill_info = _contract.Contract() + return bill_info.get_billing_info( + session=self.session, channel_id=channel_id, + target_month=target_month + ) + ''' + + 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): + """ + Get information about a workspace. + + :return: One :class:`~ecl.sss.v2.workspace.Workspace` + """ + return self._get(_workspace.Workspace) + + def workspaces(self, contract_id=None): + """ + 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` + """ + return list(self._list(_workspace.Workspace, paginated=False, contract_id=None)) + + 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 + return self._create(_workspace.Workspace, **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 = _workspace.Workspace() + return workspace.delete(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..16895a4 --- /dev/null +++ b/ecl/sss/v2/contract.py @@ -0,0 +1,140 @@ +# 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_billing_info(self, session, channel_id, target_month): + """Get billing information by channel id and target month""" + + url = self.base_path + '/%s/billing/%s' % ( + channel_id, target_month) + 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..48e3ccc --- /dev/null +++ b/ecl/sss/v2/tenant.py @@ -0,0 +1,79 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from 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_get = 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..31e698c --- /dev/null +++ b/ecl/sss/v2/workspace.py @@ -0,0 +1,55 @@ +# 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 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 + + # Properties + #: Contract which owns these workspaces. + contract_id = resource2.Body('contract_id') + #: ID of the workspace + workspace_id = resource2.Body('workspace_id') + #: 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') + #: Array of region information where tenants can be created. + regions = resource2.Body('regions') + #: Region which the workspace belongs to. + regions.region_name = resource2.Body('regions.region_name ') + #: The tenant ID that the tenant belongs. + regions.tenant_id = resource2.Body('regions.tenant_id') + #: An array of user information that has a workspace role in the workspace. + workspaces = resource2.Body('workspaces') + #: User list. + users = resource2.Body('users') + #: ID of the users who have access to this workspace. + users.user_id = resource2.Body('users.user_id') + #: Contract which owns the workspace. + users.contract_id = resource2.Body('users.contract_id') + #: This user is contract owner / or not. + users.contract_owner = resource2.Body('users.contract_owner') From cd6a5df1a7f25a57f2bf1fd6f9f33ce93bdc9b3d Mon Sep 17 00:00:00 2001 From: "yamazaki.tomoka" Date: Thu, 2 Dec 2021 17:48:09 +0900 Subject: [PATCH 14/18] :sparkles: IF-6595 fix sss api to v2 --- ecl/sss/v2/_proxy.py | 85 ++++++----------------------------------- ecl/sss/v2/contract.py | 13 ------- ecl/sss/v2/workspace.py | 26 ++++++++----- 3 files changed, 28 insertions(+), 96 deletions(-) diff --git a/ecl/sss/v2/_proxy.py b/ecl/sss/v2/_proxy.py index 956e919..cfd7e83 100644 --- a/ecl/sss/v2/_proxy.py +++ b/ecl/sss/v2/_proxy.py @@ -12,7 +12,6 @@ from ecl.sss.v2 import user as _user from ecl.sss.v2 import tenant as _tenant -# from ecl.sss.v2 import role as _role 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 @@ -152,54 +151,6 @@ def create_tenant(self, **attrs): """ return self._create(_tenant.Tenant, **attrs) - ''' - def delete_tenant(self, tenant, ignore_missing = True): - """ - Delete tenant. Only supser user (contract owner user) allowed. - - :param tenant: Delete target tenant's tenant 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(_tenant.Tenant, tenant, ignore_missing=ignore_missing) - ''' - - ''' - def create_role(self, user_id, tenant_id): - """ - Create role between a user and a tenant. With role, users can access - to the tenants. - - :param user_id: User which have new role. - :param tenant_id: Tenant which the user have role. - :return: :class:`~ecl.sss.v2.role.Role` - """ - body = {} - body["user_id"] = user_id - body["tenant_id"] = tenant_id - return self._create(_role.Role, **body) - ''' - - ''' - def delete_role(self, tenant_id, user_id): - """ - Delete role between user and tenant. Contract owner user always have - role to all tenants in the contract. Only supser user - (contract owner user) allowed. - - :param tenant_id: Delete target tenant's tenant id. - :param user_id: User's id of the role - :return: ``None`` - """ - role = _role.Role() - return role.delete(session=self.session, - tenant_id=tenant_id, user_id=user_id) - ''' - def update_api_key(self, user_id): """ Update API key pair of target user. @@ -300,22 +251,6 @@ def get_contract(self, contract_id): """ return self._get(_contract.Contract, contract_id) - ''' - def get_billing_info(self, channel_id, target_month): - """ - Get billing statement of designated month. - - :param channel_id: Billing statement owner contract. - :param target_month: Target billing month with YYYY-MM format - :return: One :class:`~ecl.sss.v2.contract.Contract` - """ - bill_info = _contract.Contract() - return bill_info.get_billing_info( - session=self.session, channel_id=channel_id, - target_month=target_month - ) - ''' - def get_monthly_billing_of_each_contract(self, contract_id, target_month, target_contract_id): """ @@ -521,13 +456,14 @@ def create_workspace(self, workspace_name, description=None, contract_id=None): body["contract_id"] = contract_id return self._create(_workspace.Workspace, **body) - def get_workspace(self): + 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) + return self._get(_workspace.Workspace, workspace_id) def workspaces(self, contract_id=None): """ @@ -569,8 +505,7 @@ def update_workspace(self, workspace_id, description): """ body = {} body["description"] = description - workspace = _workspace.Workspace() - return workspace.update(self.session, workspace_id, **body) + return self._update(_workspace.Workspace, workspace_id, **body) def add_workspace_role_assignment(self, user_id, workspace_id): """ @@ -585,7 +520,10 @@ def add_workspace_role_assignment(self, user_id, workspace_id): body = {} body["user_id"] = user_id body["workspace_id"] = workspace_id - return self._create(_workspace.Workspace, **body) + 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): """ @@ -597,6 +535,7 @@ def delete_workspace_role_assignment(self, workspace_id, user_id): :param user_id: User's id of the role. :return: ``None`` """ - workspace = _workspace.Workspace() - return workspace.delete(session=self.session, - workspace_id=workspace_id, user_id=user_id) + 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/contract.py b/ecl/sss/v2/contract.py index 16895a4..fd47938 100644 --- a/ecl/sss/v2/contract.py +++ b/ecl/sss/v2/contract.py @@ -114,19 +114,6 @@ def list(self, session, channel_id, include_deleted): self._translate_response(resp, has_body=True) return self - ''' - def get_billing_info(self, session, channel_id, target_month): - """Get billing information by channel id and target month""" - - url = self.base_path + '/%s/billing/%s' % ( - channel_id, target_month) - 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 ): diff --git a/ecl/sss/v2/workspace.py b/ecl/sss/v2/workspace.py index 31e698c..7fbee9e 100644 --- a/ecl/sss/v2/workspace.py +++ b/ecl/sss/v2/workspace.py @@ -39,17 +39,23 @@ class Workspace(resource2.Resource): start_time = resource2.Body('start_time') #: Array of region information where tenants can be created. regions = resource2.Body('regions') - #: Region which the workspace belongs to. - regions.region_name = resource2.Body('regions.region_name ') - #: The tenant ID that the tenant belongs. - regions.tenant_id = resource2.Body('regions.tenant_id') #: An array of user information that has a workspace role in the workspace. workspaces = resource2.Body('workspaces') #: User list. users = resource2.Body('users') - #: ID of the users who have access to this workspace. - users.user_id = resource2.Body('users.user_id') - #: Contract which owns the workspace. - users.contract_id = resource2.Body('users.contract_id') - #: This user is contract owner / or not. - users.contract_owner = resource2.Body('users.contract_owner') + + 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) + 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 From 81057665f0e6d0dc22aa7904a99c59af9b9ee5ee Mon Sep 17 00:00:00 2001 From: "yamazaki.tomoka" Date: Fri, 3 Dec 2021 16:26:53 +0900 Subject: [PATCH 15/18] :sparkles: IF-6595 fix workspace api --- ecl/sss/v2/workspace.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ecl/sss/v2/workspace.py b/ecl/sss/v2/workspace.py index 7fbee9e..2726b88 100644 --- a/ecl/sss/v2/workspace.py +++ b/ecl/sss/v2/workspace.py @@ -43,6 +43,8 @@ class Workspace(resource2.Resource): workspaces = resource2.Body('workspaces') #: User list. users = resource2.Body('users') + #: User's id of the role. + user_id = resource2.Body('user_id') def add_workspace_role_assignment(self, session, user_id, workspace_id): """Add role between user and workspace.""" From ef9d79b85ded47e15767a787b00ed321bd47381b Mon Sep 17 00:00:00 2001 From: "yamazaki.tomoka" Date: Tue, 4 Jan 2022 16:19:52 +0900 Subject: [PATCH 16/18] :sparkles: IF-6595 fix sss api to v2 --- ecl/sss/sss_service.py | 2 +- ecl/sss/v2/tenant.py | 1 - ecl/sss/v2/workspace.py | 4 ---- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/ecl/sss/sss_service.py b/ecl/sss/sss_service.py index 3c24235..dcbb0f9 100755 --- a/ecl/sss/sss_service.py +++ b/ecl/sss/sss_service.py @@ -20,5 +20,5 @@ class SssService(service_filter.ServiceFilter): 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/sss/v2/tenant.py b/ecl/sss/v2/tenant.py index 48e3ccc..7f4d8b8 100644 --- a/ecl/sss/v2/tenant.py +++ b/ecl/sss/v2/tenant.py @@ -22,7 +22,6 @@ class Tenant(resource2.Resource): # Capabilities allow_create = True - allow_get = True allow_list = True put_create = False diff --git a/ecl/sss/v2/workspace.py b/ecl/sss/v2/workspace.py index 2726b88..1cdb53d 100644 --- a/ecl/sss/v2/workspace.py +++ b/ecl/sss/v2/workspace.py @@ -39,12 +39,8 @@ class Workspace(resource2.Resource): start_time = resource2.Body('start_time') #: Array of region information where tenants can be created. regions = resource2.Body('regions') - #: An array of user information that has a workspace role in the workspace. - workspaces = resource2.Body('workspaces') #: User list. users = resource2.Body('users') - #: User's id of the role. - user_id = resource2.Body('user_id') def add_workspace_role_assignment(self, session, user_id, workspace_id): """Add role between user and workspace.""" From ca24a8e44a27cddb7be1f5c659312521961691af Mon Sep 17 00:00:00 2001 From: "yamazaki.tomoka" Date: Thu, 13 Jan 2022 17:01:13 +0900 Subject: [PATCH 17/18] :sparkles: IF-6595 fix sss api to v2 --- ecl/sss/v2/_proxy.py | 8 +++++--- ecl/sss/v2/workspace.py | 30 ++++++++++++++++++++++++++---- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/ecl/sss/v2/_proxy.py b/ecl/sss/v2/_proxy.py index cfd7e83..4bc5f01 100644 --- a/ecl/sss/v2/_proxy.py +++ b/ecl/sss/v2/_proxy.py @@ -465,7 +465,7 @@ def get_workspace(self, workspace_id): """ return self._get(_workspace.Workspace, workspace_id) - def workspaces(self, contract_id=None): + def workspaces(self, contract_id): """ Get list of workspace. Only workspaces for which the user has access rights are output. @@ -475,7 +475,8 @@ def workspaces(self, contract_id=None): :return: A generator of workspace instances. :rtype: :class:`~ecl.sss.v2.workspace.Workspace` """ - return list(self._list(_workspace.Workspace, paginated=False, contract_id=None)) + workspace = _workspace.Workspace() + return workspace.list(self.session, contract_id) def delete_workspace(self, workspace_id, ignore_missing=False): """ @@ -505,7 +506,8 @@ def update_workspace(self, workspace_id, description): """ body = {} body["description"] = description - return self._update(_workspace.Workspace, workspace_id, **body) + workspace = _workspace.Workspace() + return workspace.update(self.session, workspace_id, **body) def add_workspace_role_assignment(self, user_id, workspace_id): """ diff --git a/ecl/sss/v2/workspace.py b/ecl/sss/v2/workspace.py index 1cdb53d..f26b178 100644 --- a/ecl/sss/v2/workspace.py +++ b/ecl/sss/v2/workspace.py @@ -12,6 +12,7 @@ from ecl.sss import sss_service from ecl import resource2 +from ecl import utils class Workspace(resource2.Resource): resource_key = None @@ -27,9 +28,9 @@ class Workspace(resource2.Resource): allow_update = True # Properties - #: Contract which owns these workspaces. + #: ID of the contract. contract_id = resource2.Body('contract_id') - #: ID of the workspace + #: ID of the workspace. workspace_id = resource2.Body('workspace_id') #: Name of the workspace. Workspace name is also a unique identifier of workspaces. workspace_name = resource2.Body('workspace_name') @@ -37,16 +38,37 @@ class Workspace(resource2.Resource): 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') - #: User list. + #: ID of the user. + user_id = resource2.Body('user_id') + #: list of user. users = resource2.Body('users') + def list(self, session, contract_id): + """Get list of workspace.""" + + 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 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) + 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 From 6dd31923c38849f901510040693358e0de536b99 Mon Sep 17 00:00:00 2001 From: "yamazaki.tomoka" Date: Mon, 17 Jan 2022 09:37:06 +0900 Subject: [PATCH 18/18] :sparkles: IF-6595 fix sss api to v2 --- ecl/sss/v2/_proxy.py | 6 ++++-- ecl/sss/v2/workspace.py | 12 +++--------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/ecl/sss/v2/_proxy.py b/ecl/sss/v2/_proxy.py index 4bc5f01..b723370 100644 --- a/ecl/sss/v2/_proxy.py +++ b/ecl/sss/v2/_proxy.py @@ -475,8 +475,10 @@ def workspaces(self, contract_id): :return: A generator of workspace instances. :rtype: :class:`~ecl.sss.v2.workspace.Workspace` """ - workspace = _workspace.Workspace() - return workspace.list(self.session, contract_id) + 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): """ diff --git a/ecl/sss/v2/workspace.py b/ecl/sss/v2/workspace.py index f26b178..8163990 100644 --- a/ecl/sss/v2/workspace.py +++ b/ecl/sss/v2/workspace.py @@ -27,11 +27,13 @@ class Workspace(resource2.Resource): 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') + 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. @@ -47,14 +49,6 @@ class Workspace(resource2.Resource): #: list of user. users = resource2.Body('users') - def list(self, session, contract_id): - """Get list of workspace.""" - - 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 update(self, session, workspace_id, **attrs): """Updates the description for the designated workspace."""