1010
1111from kubespawner import KubeSpawner # noqa: E402
1212
13+ # conda-store default page size
14+ DEFAULT_PAGE_SIZE_LIMIT = 100
15+
1316
1417@gen .coroutine
1518def get_username_hook (spawner ):
@@ -23,25 +26,69 @@ def get_username_hook(spawner):
2326 )
2427
2528
29+ def get_total_records (url : str , token : str ) -> int :
30+ import urllib3
31+
32+ http = urllib3 .PoolManager ()
33+ response = http .request ("GET" , url , headers = {"Authorization" : f"Bearer { token } " })
34+ decoded_response = json .loads (response .data .decode ("UTF-8" ))
35+ return decoded_response .get ("count" , 0 )
36+
37+
38+ def generate_paged_urls (base_url : str , total_records : int , page_size : int ) -> list [str ]:
39+ import math
40+
41+ urls = []
42+ # pages starts at 1
43+ for page in range (1 , math .ceil (total_records / page_size ) + 1 ):
44+ urls .append (f"{ base_url } ?size={ page_size } &page={ page } " )
45+
46+ return urls
47+
48+
49+ # TODO: this should get unit tests. Currently, since this is not a python module,
50+ # adding tests in a traditional sense is not possible. See https://github.com/soapy1/nebari/tree/try-unit-test-spawner
51+ # for a demo on one approach to adding test.
2652def get_conda_store_environments (user_info : dict ):
53+ import os
54+
2755 import urllib3
28- import yarl
56+
57+ # Check for the environment variable `CONDA_STORE_API_PAGE_SIZE_LIMIT`. Fall
58+ # back to using the default page size limit if not set.
59+ page_size = os .environ .get (
60+ "CONDA_STORE_API_PAGE_SIZE_LIMIT" , DEFAULT_PAGE_SIZE_LIMIT
61+ )
2962
3063 external_url = z2jh .get_config ("custom.conda-store-service-name" )
3164 token = z2jh .get_config ("custom.conda-store-jhub-apps-token" )
3265 endpoint = "conda-store/api/v1/environment"
3366
34- url = yarl .URL (f"http://{ external_url } /{ endpoint } /" )
35-
67+ base_url = f"http://{ external_url } /{ endpoint } /"
3668 http = urllib3 .PoolManager ()
37- response = http .request (
38- "GET" , str (url ), headers = {"Authorization" : f"Bearer { token } " }
39- )
4069
41- # parse response
42- j = json .loads (response .data .decode ("UTF-8" ))
70+ # get total number of records from the endpoint
71+ total_records = get_total_records (base_url , token )
72+
73+ # will contain all the environment info returned from the api
74+ env_data = []
75+
76+ # If there are more records than the specified size limit, then
77+ # will need to page through to get all the available envs
78+ if total_records > page_size :
79+ # generate a list of urls to hit to build the response
80+ urls = generate_paged_urls (base_url , total_records , page_size )
81+
82+ # get content from urls
83+ for url in urls :
84+ response = http .request (
85+ "GET" , url , headers = {"Authorization" : f"Bearer { token } " }
86+ )
87+ decoded_response = json .loads (response .data .decode ("UTF-8" ))
88+ env_data += decoded_response .get ("data" , [])
89+
4390 # Filter and return conda environments for the user
44- return [f"{ env ['namespace' ]['name' ]} -{ env ['name' ]} " for env in j . get ( "data" , []) ]
91+ return [f"{ env ['namespace' ]['name' ]} -{ env ['name' ]} " for env in env_data ]
4592
4693
4794c .Spawner .pre_spawn_hook = get_username_hook
0 commit comments