Repository: taskcluster/tc-admin (language: python)

Issue:
Add support for customizing root URL in tc-admin.py
This will support both the simple, common case of a single default root
URL, and more complex cases involving async operations and
command-line-option-based determination of the appropriate root URL.


Discussion / hints:

Fix patch:
diff --git a/tcadmin/apply.py b/tcadmin/apply.py
index c74c7544..1928a945 100644
--- a/tcadmin/apply.py
+++ b/tcadmin/apply.py
@@ -31,5 +31,5 @@ async def apply_changes(generated, current, grep):
             resources=(r for r in current.resources if reg.search(r.id)),
         )
 
-    updater = Updater()
+    updater = await Updater()
     await updater.update(generated, current)
diff --git a/tcadmin/current/clients.py b/tcadmin/current/clients.py
index 214b4fec..b6b6bfbe 100644
--- a/tcadmin/current/clients.py
+++ b/tcadmin/current/clients.py
@@ -8,11 +8,11 @@
 
 from ..resources import Client
 from ..util.sessions import aiohttp_session
-from ..util.taskcluster import optionsFromEnvironment
+from ..util.taskcluster import tcClientOptions
 
 
 async def fetch_clients(resources):
-    auth = Auth(optionsFromEnvironment(), session=aiohttp_session())
+    auth = Auth(await tcClientOptions(), session=aiohttp_session())
     query = {}
     while True:
         res = await auth.listClients(query=query)
diff --git a/tcadmin/current/hooks.py b/tcadmin/current/hooks.py
index 66348a9e..9b235ad8 100644
--- a/tcadmin/current/hooks.py
+++ b/tcadmin/current/hooks.py
@@ -8,11 +8,11 @@
 
 from ..resources import Hook
 from ..util.sessions import aiohttp_session
-from ..util.taskcluster import optionsFromEnvironment
+from ..util.taskcluster import tcClientOptions
 
 
 async def fetch_hooks(resources):
-    hooks = Hooks(optionsFromEnvironment(), session=aiohttp_session())
+    hooks = Hooks(await tcClientOptions(), session=aiohttp_session())
     for hookGroupId in (await hooks.listHookGroups())["groups"]:
         idPrefix = "Hook={}/".format(hookGroupId)
         # if no hook with this hookGroupId is managed, skip it
diff --git a/tcadmin/current/roles.py b/tcadmin/current/roles.py
index 3ce4ef9a..3d6ee2ec 100644
--- a/tcadmin/current/roles.py
+++ b/tcadmin/current/roles.py
@@ -8,11 +8,11 @@
 
 from ..resources import Role
 from ..util.sessions import aiohttp_session
-from ..util.taskcluster import optionsFromEnvironment
+from ..util.taskcluster import tcClientOptions
 
 
 async def fetch_roles(resources):
-    auth = Auth(optionsFromEnvironment(), session=aiohttp_session())
+    auth = Auth(await tcClientOptions(), session=aiohttp_session())
     for role in await auth.listRoles():
         role = Role.from_api(role)
         if resources.is_managed(role.id):
diff --git a/tcadmin/current/secrets.py b/tcadmin/current/secrets.py
index 55714d0b..06bfeb5c 100644
--- a/tcadmin/current/secrets.py
+++ b/tcadmin/current/secrets.py
@@ -9,12 +9,12 @@
 from ..options import with_options
 from ..resources import Secret
 from ..util.sessions import aiohttp_session
-from ..util.taskcluster import optionsFromEnvironment
+from ..util.taskcluster import tcClientOptions
 
 
 @with_options("with_secrets")
 async def fetch_secrets(resources, with_secrets):
-    api = Secrets(optionsFromEnvironment(), session=aiohttp_session())
+    api = Secrets(await tcClientOptions(), session=aiohttp_session())
     query = {}
     while True:
         res = await api.list(query=query)
diff --git a/tcadmin/current/worker_pools.py b/tcadmin/current/worker_pools.py
index 716e038f..7e6fbda8 100644
--- a/tcadmin/current/worker_pools.py
+++ b/tcadmin/current/worker_pools.py
@@ -8,11 +8,11 @@
 
 from ..resources import WorkerPool
 from ..util.sessions import aiohttp_session
-from ..util.taskcluster import optionsFromEnvironment
+from ..util.taskcluster import tcClientOptions
 
 
 async def fetch_worker_pools(resources):
-    worker_manager = WorkerManager(optionsFromEnvironment(), session=aiohttp_session())
+    worker_manager = WorkerManager(await tcClientOptions(), session=aiohttp_session())
     query = {}
     while True:
         res = await worker_manager.listWorkerPools(query=query)
diff --git a/tcadmin/update.py b/tcadmin/update.py
index dfc20add..68c62feb 100644
--- a/tcadmin/update.py
+++ b/tcadmin/update.py
@@ -9,7 +9,7 @@
 from .appconfig import AppConfig
 from .util.ansi import strip_ansi
 from .util.sessions import aiohttp_session
-from .util.taskcluster import optionsFromEnvironment
+from .util.taskcluster import tcClientOptions
 from .constants import (
     ACTION_CREATE,
     ACTION_UPDATE,
@@ -29,12 +29,12 @@ class Updater:
     A simple one-instance class to encapsulate shared Taskcluster API clients.
     """
 
-    def __init__(self):
-        self.auth = Auth(optionsFromEnvironment(), session=aiohttp_session())
-        self.secrets = Secrets(optionsFromEnvironment(), session=aiohttp_session())
-        self.hooks = Hooks(optionsFromEnvironment(), session=aiohttp_session())
+    async def __init__(self):
+        self.auth = Auth(await tcClientOptions(), session=aiohttp_session())
+        self.secrets = Secrets(await tcClientOptions(), session=aiohttp_session())
+        self.hooks = Hooks(await tcClientOptions(), session=aiohttp_session())
         self.worker_manager = WorkerManager(
-            optionsFromEnvironment(), session=aiohttp_session()
+            await tcClientOptions(), session=aiohttp_session()
         )
 
     async def create_role(self, role):
diff --git a/tcadmin/util/taskcluster.py b/tcadmin/util/taskcluster.py
index c554f311..17fd06d2 100644
--- a/tcadmin/util/taskcluster.py
+++ b/tcadmin/util/taskcluster.py
@@ -4,13 +4,18 @@
 # v. 2.0. If a copy of the MPL was not distributed with this file, You can
 # obtain one at http://mozilla.org/MPL/2.0/.
 
-from taskcluster import optionsFromEnvironment as originalOptions
+from taskcluster import optionsFromEnvironment
 import os
 
+from .root_url import root_url
 
-def optionsFromEnvironment():
-    """Build Taskcluster options, supporting proxy"""
+
+async def tcClientOptions():
+    """Build Taskcluster client options, supporting proxy and getting root_url
+    from the appconfig"""
     if "TASKCLUSTER_PROXY_URL" in os.environ:
         return {"rootUrl": os.environ["TASKCLUSTER_PROXY_URL"]}
     else:
-        return originalOptions()
+        options = optionsFromEnvironment()
+        options["rootUrl"] = await root_url()
+        return options


Test patch:
diff --git a/tcadmin/tests/conftest.py b/tcadmin/tests/conftest.py
index 7e3ebfae..85623ac0 100644
--- a/tcadmin/tests/conftest.py
+++ b/tcadmin/tests/conftest.py
@@ -31,3 +31,12 @@ def appconfig():
     appconfig = AppConfig()
     with AppConfig._as_current(appconfig):
         yield appconfig
+
+
+@pytest.fixture(scope="module")
+def fake_root_url():
+    import tcadmin.util.root_url
+    fake_root_url = "https://tc-testing.example.com"
+    tcadmin.util.root_url._root_url = fake_root_url
+    yield fake_root_url
+    tcadmin.util.root_url._root_url = None
diff --git a/tcadmin/tests/test_current_clients.py b/tcadmin/tests/test_current_clients.py
index 0392a25e..78892d0d 100644
--- a/tcadmin/tests/test_current_clients.py
+++ b/tcadmin/tests/test_current_clients.py
@@ -10,7 +10,7 @@
 from tcadmin.current.clients import fetch_clients
 
 
-pytestmark = pytest.mark.usefixtures("appconfig")
+pytestmark = pytest.mark.usefixtures("appconfig", "fake_root_url")
 
 
 @pytest.fixture
diff --git a/tcadmin/tests/test_current_hooks.py b/tcadmin/tests/test_current_hooks.py
index 28071d69..82583cbe 100644
--- a/tcadmin/tests/test_current_hooks.py
+++ b/tcadmin/tests/test_current_hooks.py
@@ -10,7 +10,7 @@
 from tcadmin.current.hooks import fetch_hooks
 
 
-pytestmark = pytest.mark.usefixtures("appconfig")
+pytestmark = pytest.mark.usefixtures("appconfig", "fake_root_url")
 
 
 @pytest.fixture
diff --git a/tcadmin/tests/test_current_roles.py b/tcadmin/tests/test_current_roles.py
index 9e084a22..dd20f963 100644
--- a/tcadmin/tests/test_current_roles.py
+++ b/tcadmin/tests/test_current_roles.py
@@ -10,7 +10,7 @@
 from tcadmin.current.roles import fetch_roles
 
 
-pytestmark = pytest.mark.usefixtures("appconfig")
+pytestmark = pytest.mark.usefixtures("appconfig", "fake_root_url")
 
 
 @pytest.fixture
diff --git a/tcadmin/tests/test_current_secrets.py b/tcadmin/tests/test_current_secrets.py
index 5c5e2a65..4b0cab4c 100644
--- a/tcadmin/tests/test_current_secrets.py
+++ b/tcadmin/tests/test_current_secrets.py
@@ -11,6 +11,9 @@
 from tcadmin.current.secrets import fetch_secrets
 
 
+pytestmark = pytest.mark.usefixtures("fake_root_url")
+
+
 @pytest.fixture
 def Secrets(mocker):
     """
diff --git a/tcadmin/tests/test_current_worker_pools.py b/tcadmin/tests/test_current_worker_pools.py
index a4f64111..e5d56f55 100644
--- a/tcadmin/tests/test_current_worker_pools.py
+++ b/tcadmin/tests/test_current_worker_pools.py
@@ -10,7 +10,7 @@
 from tcadmin.current.worker_pools import fetch_worker_pools
 
 
-pytestmark = pytest.mark.usefixtures("appconfig")
+pytestmark = pytest.mark.usefixtures("appconfig", "fake_root_url")
 
 
 @pytest.fixture
diff --git a/tcadmin/tests/test_util_scopes.py b/tcadmin/tests/test_util_scopes.py
index 9c96192d..4aee1d4d 100644
--- a/tcadmin/tests/test_util_scopes.py
+++ b/tcadmin/tests/test_util_scopes.py
@@ -9,7 +9,6 @@
 import os
 
 from tcadmin.util.scopes import Resolver, satisfies
-from tcadmin.util.taskcluster import optionsFromEnvironment
 from tcadmin.resources import Role, Resources
 
 
@@ -238,7 +237,8 @@ def auth():
             pytest.fail(msg)
         else:
             pytest.skip(msg)
-    return taskcluster.Auth(optionsFromEnvironment())
+        return
+    return taskcluster.Auth({"rootUrl": os.environ["TASKCLUSTER_ROOT_URL"]})
 
 
 @pytest.fixture(scope="module")