1- import base64
21import logging
32import requests
43import urllib .parse
1110logger = logging .getLogger (__name__ )
1211
1312
14- class ManagerAPI (object ):
15-
16- def __init__ (self , timeout = 3 ):
17- self .timeout = timeout
18- token = base64 .b85encode (b"%s:%s" % (
19- settings .SOCIAL_AUTH_DRYCC_KEY .encode ("utf8" ),
20- settings .SOCIAL_AUTH_DRYCC_SECRET .encode ("utf8" ),
21- )).decode ("utf8" )
22- self .headers = {
23- 'Content-Type' : 'application/json' ,
24- 'Authorization' : 'token %s' % token ,
25- 'User-Agent' : user_agent ('Drycc Controller ' , drycc_version )
26- }
27-
28- def request (self , method , url , ** kwargs ):
29- headers = kwargs .get ("headers" , {})
30- headers .update (self .headers )
31- kwargs ["headers" ] = headers
32- kwargs ["timeout" ] = self .timeout
33- return requests .request (method , url , ** kwargs )
34-
35- def get (self , url , params = None , ** kwargs ):
36- return self .request ('get' , url , params = params , ** kwargs )
37-
38- def options (self , url , ** kwargs ):
39- return self .request ('options' , url , ** kwargs )
40-
41- def head (self , url , ** kwargs ):
42- kwargs .setdefault ('allow_redirects' , False )
43- return self .request ('head' , url , ** kwargs )
44-
45- def post (self , url , data = None , json = None , ** kwargs ):
46- return self .request ('post' , url , data = data , json = json , ** kwargs )
47-
48- def put (self , url , data = None , ** kwargs ):
49- return self .request ('put' , url , data = data , ** kwargs )
50-
51- def patch (self , url , data = None , ** kwargs ):
52- return self .request ('patch' , url , data = data , ** kwargs )
53-
54- def delete (self , url , ** kwargs ):
55- return self .request ('delete' , url , ** kwargs )
56-
57-
58- class WorkspaceAPI (ManagerAPI ):
59-
60- def get_status (self , workspace_id ):
61- """
62- {
63- "is_active": False,
64- "message": "The user is in arrears"
65- }
66- """
67- key = f"workspace:status:{ workspace_id } "
68- status = cache .get (key )
69- if not status :
70- url = f"{ settings .WORKFLOW_MANAGER_URL } /workspaces/{ workspace_id } /status/"
71- try :
72- status = self .get (url = url , timeout = self .timeout ).json ()
73- except requests .exceptions .Timeout as ex :
74- msg = f"request workspace { workspace_id } timeout, skipping verification."
75- status = {"is_active" : True , "message" : msg }
76- logger .error (msg )
77- logger .exception (ex )
78- cache .set (key , status , timeout = settings .DRYCC_CACHE_USER_TIME )
79- return status
80-
81-
82- class UserAPI (WorkspaceAPI ):
83- """Backward-compatible alias for legacy call sites."""
84-
85-
86- class UsageAPI (ManagerAPI ):
87-
88- def post (self , usage : List [Dict [str , str ]]):
89- """
90- [
91- {
92- "app_id": "test",
93- "workspace": "test",
94- "name": "web",
95- "type": "limits",
96- "unit": "std1.large.c1m1",
97- "usage": "2",
98- "timestamp": "1609231998.9103732"
99- }
100- ]
101- """
102- url = "%s/usage/" % settings .WORKFLOW_MANAGER_URL
103- return super ().post (url = url , json = usage )
104-
105-
10613class PassportAPI (object ):
10714 """Service-to-service client for Drycc Passport using OAuth2 client_credentials."""
10815
@@ -113,7 +20,8 @@ def __init__(self, timeout=10):
11320 self .timeout = timeout
11421 self .base_url = settings .DRYCC_PASSPORT_URL .rstrip ("/" )
11522
116- def _get_token (self ) -> str :
23+ @property
24+ def headers (self ) -> str :
11725 token = cache .get (self .TOKEN_CACHE_KEY )
11826 if token and self .get_scopes (token ) == set (settings .DRYCC_PASSPORT_SCOPES .split ()):
11927 return token
@@ -132,9 +40,14 @@ def _get_token(self) -> str:
13240 token = body ["access_token" ]
13341 ttl = max (int (body .get ("expires_in" , 3600 )) - self .TOKEN_REFRESH_LEEWAY , 60 )
13442 cache .set (self .TOKEN_CACHE_KEY , token , timeout = ttl )
135- return token
43+ return {
44+ "Authorization" : f"Bearer { token } " ,
45+ "Content-Type" : "application/json" ,
46+ "User-Agent" : user_agent ("Drycc Controller" , drycc_version ),
47+ }
13648
137- def get_scopes (self , token ):
49+ @staticmethod
50+ def get_scopes (token ):
13851 def _get_scopes ():
13952 endpoint = getattr (settings , 'SOCIAL_AUTH_DRYCC_OIDC_ENDPOINT' , None )
14053 if not endpoint :
@@ -156,17 +69,54 @@ def _get_scopes():
15669 f"drycc_oauth_scopes_v2_{ token } " , _get_scopes , settings .DRYCC_CACHE_USER_TIME )
15770
15871 def send_message (self , username : str , message : Dict ) -> None :
159- token = self ._get_token ()
160- headers = {
161- "Authorization" : f"Bearer { token } " ,
162- "Content-Type" : "application/json" ,
163- "User-Agent" : user_agent ("Drycc Controller" , drycc_version ),
164- }
16572 body = {** message , "username" : username }
16673 resp = requests .post (
16774 f"{ self .base_url } /messages/" ,
16875 json = body ,
169- headers = headers ,
76+ headers = self . headers ,
17077 timeout = self .timeout ,
17178 )
17279 resp .raise_for_status ()
80+
81+
82+ class ManagerAPI (object ):
83+
84+ def __init__ (self , timeout = 10 ):
85+ self .timeout = timeout
86+ self .headers = PassportAPI (timeout = timeout ).headers if self .enabled else None
87+ self .base_url = settings .WORKFLOW_MANAGER_URL .rstrip ("/" ) if self .enabled else None
88+
89+ @property
90+ def enabled (self ):
91+ return settings .WORKFLOW_MANAGER_URL is not None
92+
93+ def send_usage (self , usage : List [Dict [str , str ]]):
94+ if not self .enabled :
95+ logger .info ("WORKFLOW_MANAGER_URL is not set, skipping send_usage" )
96+ return
97+ url = f"{ self .base_url } /usage/"
98+ return requests .post (url = url , json = usage , headers = self .headers , timeout = self .timeout )
99+
100+ def get_status (self , resource_type : str , resource_id : str ):
101+ if not self .enabled :
102+ logger .info ("WORKFLOW_MANAGER_URL is not set, skipping get_status" )
103+ return True , None
104+ key = f"{ resource_type } :status:{ resource_id } "
105+ status = cache .get (key )
106+ if not status :
107+ url = f"{ self .base_url } /{ resource_type } s/{ resource_id } /status/"
108+ try :
109+ status = requests .get (url = url , headers = self .headers , timeout = self .timeout ).json ()
110+ except requests .exceptions .Timeout as ex :
111+ msg = f"request { resource_type } { resource_id } timeout, skipping verification."
112+ status = {"is_active" : True , "message" : msg }
113+ logger .error (msg )
114+ logger .exception (ex )
115+ cache .set (key , status , timeout = settings .DRYCC_CACHE_USER_TIME )
116+ return status .get ("is_active" , True ), status .get ("message" , None )
117+
118+ def get_app_status (self , app_id ):
119+ return self .get_status ("app" , app_id )
120+
121+ def get_user_status (self , user_id ):
122+ return self .get_status ("user" , user_id )
0 commit comments