From b8429f004613e4256ac1c41271342874ec51dde5 Mon Sep 17 00:00:00 2001 From: Marian Ganisin Date: Thu, 2 Dec 2021 02:57:21 -0500 Subject: [PATCH] Refactor tenant readiness check Move the check to ThreeScaleClient as there it is available for all cases (e.g. when client is used without dealing with tenants). Original wait_tenant_ready kept available. Collected all the used checks of availability and added short sleep as the checks are still insufficient --- threescale_api/client.py | 32 +++++++++++++++++++++++++++++++- threescale_api/resources.py | 14 ++++---------- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/threescale_api/client.py b/threescale_api/client.py index e0f41d6..2a8ada6 100644 --- a/threescale_api/client.py +++ b/threescale_api/client.py @@ -1,6 +1,8 @@ import logging +import time from urllib.parse import urljoin +import backoff import requests from threescale_api import errors, resources @@ -9,13 +11,15 @@ class ThreeScaleClient: - def __init__(self, url: str, token: str, throws: bool = True, ssl_verify: bool = True): + def __init__(self, url: str, token: str, + throws: bool = True, ssl_verify: bool = True, wait: bool = False): """Creates instance of the 3scale client Args: url: 3scale instance url token: Access token throws: Whether it should throw an error ssl_verify: Whether to verify ssl + wait: Whether to do extra checks of 3scale availability """ self._rest = RestApiClient(url=url, token=token, throws=throws, ssl_verify=ssl_verify) self._services = resources.Services(self, instance_klass=resources.Service) @@ -46,6 +50,32 @@ def __init__(self, url: str, token: str, throws: bool = True, ssl_verify: bool = self._fields_definitions =\ resources.FieldsDefinitions(self, instance_klass=resources.FieldsDefinition) + if wait: + self.wait_for_tenant() + # TODO: all the implemented checks aren't enough yet + # 3scale can still return 404/409 error, therefore slight artificial sleep + # here to mitigate the problem. This requires proper fix in checks + time.sleep(16) + + @backoff.on_predicate(backoff.fibo, lambda ready: not ready, max_tries=8, jitter=None) + def wait_for_tenant(self) -> bool: + """ + When True is returned, there is some chance the tenant is actually ready. + """ + # TODO: checks below were collected from various sources to craft + # ultimate readiness check. There might be duplicates though, so + # worth to review it one day + try: + return self.account_plans.exists() \ + and len(self.account_plans.fetch()["plans"]) >= 1 \ + and len(self.account_plans.list()) >= 1 \ + and self.accounts.exists() \ + and len(self.accounts.list()) >= 1 \ + and self.services.exists() \ + and len(self.services.list()) >= 1 + except Exception: + return False + @property def rest(self) -> 'RestApiClient': """Get REST api client instance diff --git a/threescale_api/resources.py b/threescale_api/resources.py index c8316fe..79e8ea9 100644 --- a/threescale_api/resources.py +++ b/threescale_api/resources.py @@ -8,7 +8,6 @@ from threescale_api.defaults import DefaultClient, DefaultPlanClient, DefaultPlanResource, \ DefaultResource, DefaultStateClient, DefaultUserResource, DefaultStateResource from threescale_api import client -import backoff log = logging.getLogger(__name__) @@ -1114,24 +1113,19 @@ def __init__(self, entity_name='system_name', **kwargs): def entity_id(self) -> int: return self.entity["signup"]["account"]["id"] - @backoff.on_predicate(backoff.fibo, lambda ready: not ready, max_tries=8, jitter=None) def wait_tenant_ready(self) -> bool: """ When True is returned, there is some chance the tenant is actually ready. """ - api = self.admin_api() - return api.account_plans.exists() and len(api.account_plans.list()) >= 1 and\ - api.accounts.exists() and len(api.accounts.list()) >= 1 + return self.admin_api().wait_for_tenant() - def admin_api(self, wait=False) -> 'client.ThreeScaleClient': + def admin_api(self, ssl_verify=True, wait=False) -> 'client.ThreeScaleClient': """ Returns admin api client for tenant. Its strongly recommended to call this with wait=True """ - if wait: - self.wait_tenant_ready() - ssl_verify = self.threescale_client.rest._ssl_verify - return client.ThreeScaleClient(self.admin_base_url, self.admin_token, ssl_verify=ssl_verify) + return client.ThreeScaleClient( + self.admin_base_url, self.admin_token, ssl_verify=ssl_verify, wait=wait) def trigger_billing(self, date: str): """Trigger billing for whole tenant