16
16
Flask ,
17
17
Response ,
18
18
abort ,
19
- redirect ,
20
19
render_template ,
21
20
request ,
22
21
send_from_directory ,
23
- session ,
24
22
)
25
23
26
- from flask_oauthlib .client import OAuth
27
- from functools import wraps
28
24
from gevent import sleep , spawn
29
25
from gevent .pywsgi import WSGIServer
30
26
from jq import jq
34
30
from re import X , compile
35
31
from requests .exceptions import RequestException
36
32
from signal import SIGTERM , signal
37
- from urllib .parse import urljoin
38
33
39
34
from . import __version__
40
35
from .cluster_discovery import DEFAULT_CLUSTERS , StaticClusterDiscoverer
41
- from .oauth import OAuthRemoteAppWithRefresh
42
36
43
37
from .spiloutils import (
44
38
apply_postgresql ,
71
65
SERVER_STATUS = {'shutdown' : False }
72
66
73
67
APP_URL = getenv ('APP_URL' )
74
- AUTHORIZE_URL = getenv ('AUTHORIZE_URL' )
75
68
SPILO_S3_BACKUP_BUCKET = getenv ('SPILO_S3_BACKUP_BUCKET' )
76
69
TEAM_SERVICE_URL = getenv ('TEAM_SERVICE_URL' )
77
- ACCESS_TOKEN_URL = getenv ('ACCESS_TOKEN_URL' )
78
- TOKENINFO_URL = getenv ('OAUTH2_TOKEN_INFO_URL' )
79
70
80
71
OPERATOR_API_URL = getenv ('OPERATOR_API_URL' , 'http://postgres-operator' )
81
72
OPERATOR_CLUSTER_NAME_LABEL = getenv ('OPERATOR_CLUSTER_NAME_LABEL' , 'cluster-name' )
@@ -184,38 +175,6 @@ def __call__(self, environ, start_response):
184
175
return self .app (environ , start_response )
185
176
186
177
187
- oauth = OAuth (app )
188
-
189
- auth = OAuthRemoteAppWithRefresh (
190
- oauth ,
191
- 'auth' ,
192
- request_token_url = None ,
193
- access_token_method = 'POST' ,
194
- access_token_url = ACCESS_TOKEN_URL ,
195
- authorize_url = AUTHORIZE_URL ,
196
- )
197
- oauth .remote_apps ['auth' ] = auth
198
-
199
-
200
- def verify_token (token ):
201
- if not token :
202
- return False
203
-
204
- r = requests .get (TOKENINFO_URL , headers = {'Authorization' : token })
205
-
206
- return r .status_code == 200
207
-
208
-
209
- def authorize (f ):
210
- @wraps (f )
211
- def wrapper (* args , ** kwargs ):
212
- if AUTHORIZE_URL and 'auth_token' not in session :
213
- return redirect (urljoin (APP_URL , '/login' ))
214
- return f (* args , ** kwargs )
215
-
216
- return wrapper
217
-
218
-
219
178
def ok (body = {}, status = 200 ):
220
179
return (
221
180
Response (
@@ -297,19 +256,16 @@ def health():
297
256
298
257
299
258
@app .route ('/css/<path:path>' )
300
- @authorize
301
259
def send_css (path ):
302
260
return send_from_directory ('static/' , path ), 200 , STATIC_HEADERS
303
261
304
262
305
263
@app .route ('/js/<path:path>' )
306
- @authorize
307
264
def send_js (path ):
308
265
return send_from_directory ('static/' , path ), 200 , STATIC_HEADERS
309
266
310
267
311
268
@app .route ('/' )
312
- @authorize
313
269
def index ():
314
270
return render_template ('index.html' , google_analytics = GOOGLE_ANALYTICS )
315
271
@@ -345,7 +301,6 @@ def index():
345
301
346
302
347
303
@app .route ('/config' )
348
- @authorize
349
304
def get_config ():
350
305
config = DEFAULT_UI_CONFIG .copy ()
351
306
config .update (OPERATOR_UI_CONFIG )
@@ -407,17 +362,15 @@ def get_teams_for_user(user_name):
407
362
408
363
409
364
@app .route ('/teams' )
410
- @authorize
411
365
def get_teams ():
412
366
return ok (
413
367
get_teams_for_user (
414
- session . get ('user_name ' , '' ),
368
+ request . headers . get ('X-Uid ' , '' ),
415
369
)
416
370
)
417
371
418
372
419
373
@app .route ('/services/<namespace>/<cluster>' )
420
- @authorize
421
374
def get_service (namespace : str , cluster : str ):
422
375
423
376
if TARGET_NAMESPACE not in ['' , '*' , namespace ]:
@@ -433,7 +386,6 @@ def get_service(namespace: str, cluster: str):
433
386
434
387
435
388
@app .route ('/pooler/<namespace>/<cluster>' )
436
- @authorize
437
389
def get_list_poolers (namespace : str , cluster : str ):
438
390
439
391
if TARGET_NAMESPACE not in ['' , '*' , namespace ]:
@@ -449,7 +401,6 @@ def get_list_poolers(namespace: str, cluster: str):
449
401
450
402
451
403
@app .route ('/statefulsets/<namespace>/<cluster>' )
452
- @authorize
453
404
def get_list_clusters (namespace : str , cluster : str ):
454
405
455
406
if TARGET_NAMESPACE not in ['' , '*' , namespace ]:
@@ -465,7 +416,6 @@ def get_list_clusters(namespace: str, cluster: str):
465
416
466
417
467
418
@app .route ('/statefulsets/<namespace>/<cluster>/pods' )
468
- @authorize
469
419
def get_list_members (namespace : str , cluster : str ):
470
420
471
421
if TARGET_NAMESPACE not in ['' , '*' , namespace ]:
@@ -485,7 +435,6 @@ def get_list_members(namespace: str, cluster: str):
485
435
486
436
487
437
@app .route ('/namespaces' )
488
- @authorize
489
438
def get_namespaces ():
490
439
491
440
if TARGET_NAMESPACE not in ['' , '*' ]:
@@ -503,7 +452,6 @@ def get_namespaces():
503
452
504
453
505
454
@app .route ('/postgresqls' )
506
- @authorize
507
455
def get_postgresqls ():
508
456
postgresqls = [
509
457
{
@@ -602,7 +550,6 @@ def run(*args, **kwargs):
602
550
603
551
604
552
@app .route ('/postgresqls/<namespace>/<cluster>' , methods = ['POST' ])
605
- @authorize
606
553
@namespaced
607
554
def update_postgresql (namespace : str , cluster : str ):
608
555
if READ_ONLY_MODE :
@@ -614,8 +561,8 @@ def update_postgresql(namespace: str, cluster: str):
614
561
615
562
postgresql = request .get_json (force = True )
616
563
617
- teams = get_teams_for_user (session . get ('user_name ' , '' ))
618
- logger .info (f'Changes to: { cluster } by { session . get ("user_name " , "local-user" )} /{ teams } { postgresql } ' ) # noqa
564
+ teams = get_teams_for_user (request . headers . get ('X-Uid ' , '' ))
565
+ logger .info (f'Changes to: { cluster } by { request . headers . get ("X-Uid " , "local-user" )} /{ teams } { postgresql } ' ) # noqa
619
566
620
567
if SUPERUSER_TEAM and SUPERUSER_TEAM in teams :
621
568
logger .info (f'Allowing edit due to membership in superuser team { SUPERUSER_TEAM } ' ) # noqa
@@ -810,7 +757,6 @@ def update_postgresql(namespace: str, cluster: str):
810
757
811
758
812
759
@app .route ('/postgresqls/<namespace>/<cluster>' , methods = ['GET' ])
813
- @authorize
814
760
def get_postgresql (namespace : str , cluster : str ):
815
761
816
762
if TARGET_NAMESPACE not in ['' , '*' , namespace ]:
@@ -826,7 +772,6 @@ def get_postgresql(namespace: str, cluster: str):
826
772
827
773
828
774
@app .route ('/stored_clusters' )
829
- @authorize
830
775
def get_stored_clusters ():
831
776
return respond (
832
777
read_stored_clusters (
@@ -837,7 +782,6 @@ def get_stored_clusters():
837
782
838
783
839
784
@app .route ('/stored_clusters/<pg_cluster>' , methods = ['GET' ])
840
- @authorize
841
785
def get_versions (pg_cluster : str ):
842
786
return respond (
843
787
read_versions (
@@ -850,9 +794,7 @@ def get_versions(pg_cluster: str):
850
794
)
851
795
852
796
853
-
854
797
@app .route ('/stored_clusters/<pg_cluster>/<uid>' , methods = ['GET' ])
855
- @authorize
856
798
def get_basebackups (pg_cluster : str , uid : str ):
857
799
return respond (
858
800
read_basebackups (
@@ -867,7 +809,6 @@ def get_basebackups(pg_cluster: str, uid: str):
867
809
868
810
869
811
@app .route ('/create-cluster' , methods = ['POST' ])
870
- @authorize
871
812
def create_new_cluster ():
872
813
873
814
if READ_ONLY_MODE :
@@ -885,8 +826,8 @@ def create_new_cluster():
885
826
if TARGET_NAMESPACE not in ['' , '*' , namespace ]:
886
827
return wrong_namespace ()
887
828
888
- teams = get_teams_for_user (session . get ('user_name ' , '' ))
889
- logger .info (f'Create cluster by { session . get ("user_name " , "local-user" )} /{ teams } { postgresql } ' ) # noqa
829
+ teams = get_teams_for_user (request . headers . get ('X-Uid ' , '' ))
830
+ logger .info (f'Create cluster by { request . headers . get ("X-Uid " , "local-user" )} /{ teams } { postgresql } ' ) # noqa
890
831
891
832
if SUPERUSER_TEAM and SUPERUSER_TEAM in teams :
892
833
logger .info (f'Allowing create due to membership in superuser team { SUPERUSER_TEAM } ' ) # noqa
@@ -898,7 +839,6 @@ def create_new_cluster():
898
839
899
840
900
841
@app .route ('/postgresqls/<namespace>/<cluster>' , methods = ['DELETE' ])
901
- @authorize
902
842
def delete_postgresql (namespace : str , cluster : str ):
903
843
if TARGET_NAMESPACE not in ['' , '*' , namespace ]:
904
844
return wrong_namespace ()
@@ -910,9 +850,9 @@ def delete_postgresql(namespace: str, cluster: str):
910
850
if postgresql is None :
911
851
return not_found ()
912
852
913
- teams = get_teams_for_user (session . get ('user_name ' , '' ))
853
+ teams = get_teams_for_user (request . headers . get ('X-Uid ' , '' ))
914
854
915
- logger .info (f'Delete cluster: { cluster } by { session . get ("user_name " , "local-user" )} /{ teams } ' ) # noqa
855
+ logger .info (f'Delete cluster: { cluster } by { request . headers . get ("X-Uid " , "local-user" )} /{ teams } ' ) # noqa
916
856
917
857
if SUPERUSER_TEAM and SUPERUSER_TEAM in teams :
918
858
logger .info (f'Allowing delete due to membership in superuser team { SUPERUSER_TEAM } ' ) # noqa
@@ -936,78 +876,30 @@ def proxy_operator(url: str):
936
876
937
877
938
878
@app .route ('/operator/status' )
939
- @authorize
940
879
def get_operator_status ():
941
880
return proxy_operator ('/status/' )
942
881
943
882
944
883
@app .route ('/operator/workers/<worker>/queue' )
945
- @authorize
946
884
def get_operator_get_queue (worker : int ):
947
885
return proxy_operator (f'/workers/{ worker } /queue' )
948
886
949
887
950
888
@app .route ('/operator/workers/<worker>/logs' )
951
- @authorize
952
889
def get_operator_get_logs (worker : int ):
953
890
return proxy_operator (f'/workers/{ worker } /logs' )
954
891
955
892
956
893
@app .route ('/operator/clusters/<namespace>/<cluster>/logs' )
957
- @authorize
958
894
def get_operator_get_logs_per_cluster (namespace : str , cluster : str ):
959
895
return proxy_operator (f'/clusters/{ namespace } /{ cluster } /logs/' )
960
896
961
897
962
- @app .route ('/login' )
963
- def login ():
964
- redirect = request .args .get ('redirect' , False )
965
- if not redirect :
966
- return render_template ('login-deeplink.html' )
967
-
968
- redirect_uri = urljoin (APP_URL , '/login/authorized' )
969
- return auth .authorize (callback = redirect_uri )
970
-
971
-
972
- @app .route ('/logout' )
973
- def logout ():
974
- session .pop ('auth_token' , None )
975
- return redirect (urljoin (APP_URL , '/' ))
976
-
977
-
978
898
@app .route ('/favicon.png' )
979
899
def favicon ():
980
900
return send_from_directory ('static/' , 'favicon-96x96.png' ), 200
981
901
982
902
983
- @app .route ('/login/authorized' )
984
- def authorized ():
985
- resp = auth .authorized_response ()
986
- if resp is None :
987
- return 'Access denied: reason=%s error=%s' % (
988
- request .args ['error' ],
989
- request .args ['error_description' ]
990
- )
991
-
992
- if not isinstance (resp , dict ):
993
- return 'Invalid auth response'
994
-
995
- session ['auth_token' ] = (resp ['access_token' ], '' )
996
-
997
- r = requests .get (
998
- TOKENINFO_URL ,
999
- headers = {
1000
- 'Authorization' : f'Bearer { session ["auth_token" ][0 ]} ' ,
1001
- },
1002
- )
1003
- session ['user_name' ] = r .json ().get ('uid' )
1004
-
1005
- logger .info (f'Login from: { session ["user_name" ]} ' )
1006
-
1007
- # return redirect(urljoin(APP_URL, '/'))
1008
- return render_template ('login-resolve-deeplink.html' )
1009
-
1010
-
1011
903
def shutdown ():
1012
904
# just wait some time to give Kubernetes time to update endpoints
1013
905
# this requires changing the readinessProbe's
@@ -1083,28 +975,20 @@ def init_cluster():
1083
975
help = 'Verbose logging' ,
1084
976
is_flag = True ,
1085
977
)
1086
- @option (
1087
- '--secret-key' ,
1088
- default = 'development' ,
1089
- envvar = 'SECRET_KEY' ,
1090
- help = 'Secret key for session cookies' ,
1091
- )
1092
978
@option (
1093
979
'--clusters' ,
1094
980
envvar = 'CLUSTERS' ,
1095
981
help = f'Comma separated list of Kubernetes API server URLs (default: { DEFAULT_CLUSTERS } )' , # noqa
1096
982
type = CommaSeparatedValues (),
1097
983
)
1098
- def main (port , secret_key , debug , clusters : list ):
984
+ def main (port , debug , clusters : list ):
1099
985
global TARGET_NAMESPACE
1100
986
1101
987
basicConfig (stream = sys .stdout , level = (DEBUG if debug else INFO ), format = '%(asctime)s %(levelname)s: %(message)s' ,)
1102
988
1103
989
init_cluster ()
1104
990
1105
- logger .info (f'Access token URL: { ACCESS_TOKEN_URL } ' )
1106
991
logger .info (f'App URL: { APP_URL } ' )
1107
- logger .info (f'Authorize URL: { AUTHORIZE_URL } ' )
1108
992
logger .info (f'Operator API URL: { OPERATOR_API_URL } ' )
1109
993
logger .info (f'Operator cluster name label: { OPERATOR_CLUSTER_NAME_LABEL } ' )
1110
994
logger .info (f'Readonly mode: { "enabled" if READ_ONLY_MODE else "disabled" } ' ) # noqa
@@ -1113,7 +997,6 @@ def main(port, secret_key, debug, clusters: list):
1113
997
logger .info (f'Superuser team: { SUPERUSER_TEAM } ' )
1114
998
logger .info (f'Target namespace: { TARGET_NAMESPACE } ' )
1115
999
logger .info (f'Teamservice URL: { TEAM_SERVICE_URL } ' )
1116
- logger .info (f'Tokeninfo URL: { TOKENINFO_URL } ' )
1117
1000
logger .info (f'Use AWS instance_profile: { USE_AWS_INSTANCE_PROFILE } ' )
1118
1001
logger .info (f'WAL-E S3 endpoint: { WALE_S3_ENDPOINT } ' )
1119
1002
logger .info (f'AWS S3 endpoint: { AWS_ENDPOINT } ' )
@@ -1136,7 +1019,6 @@ def get_target_namespace():
1136
1019
logger .info (f'Target namespace set to: { TARGET_NAMESPACE or "*" } ' )
1137
1020
1138
1021
app .debug = debug
1139
- app .secret_key = secret_key
1140
1022
1141
1023
signal (SIGTERM , exit_gracefully )
1142
1024
0 commit comments