1
1
from gql import Client , gql
2
2
from gql .transport .requests import RequestsHTTPTransport
3
+ from gql .transport .exceptions import TransportQueryError
3
4
import os
4
5
import logging
5
6
import time
12
13
13
14
# Wait and Rollback options
14
15
WAIT_HEALTHY = True if os .getenv ('WAIT_HEALTHY' , "false" ).lower () == "true" else False
15
- INTERVAL = int (os .getenv ('INTERVAL' ))
16
- MAX_CHECKS = int (os .getenv ('MAX_CHECKS' ))
16
+ INTERVAL = int (os .getenv ('INTERVAL' ))
17
+ MAX_CHECKS = int (os .getenv ('MAX_CHECKS' ))
17
18
18
19
WAIT_ROLLBACK = True if os .getenv ('WAIT_ROLLBACK' , "false" ).lower () == "true" else False
19
- ROLLBACK = True if os .getenv ('ROLLBACK' , "false" ).lower () == "true" else False
20
+ ROLLBACK = True if os .getenv ('ROLLBACK' , "false" ).lower () == "true" else False
20
21
if WAIT_ROLLBACK : ROLLBACK = True
21
22
22
- CF_URL = os .getenv ('CF_URL' , 'https://g.codefresh.io' )
23
- CF_API_KEY = os .getenv ('CF_API_KEY' )
24
- CF_STEP_NAME = os .getenv ('CF_STEP_NAME' , 'STEP_NAME' )
25
- LOG_LEVEL = os .getenv ('LOG_LEVEL' , "error" )
23
+ CF_URL = os .getenv ('CF_URL' , 'https://g.codefresh.io' )
24
+ CF_API_KEY = os .getenv ('CF_API_KEY' )
25
+ CF_STEP_NAME = os .getenv ('CF_STEP_NAME' , 'STEP_NAME' )
26
+ LOG_LEVEL = os .getenv ('LOG_LEVEL' , "error" )
26
27
27
28
# Check the certificate or not accessing the API endpoint
28
29
VERIFY = True if os .getenv ('INSECURE' , "False" ).lower () == "false" else False
@@ -47,41 +48,51 @@ def main():
47
48
logging .debug ("VERIFY: %s" , VERIFY )
48
49
logging .debug ("BUNDLE: %s" , CA_BUNDLE )
49
50
51
+ ## Generating link to the Apps Dashboard
52
+ CF_OUTPUT_URL_VAR = CF_STEP_NAME + '_CF_OUTPUT_URL'
53
+ link_to_app = get_link_to_apps_dashboard ()
54
+ export_variable (CF_OUTPUT_URL_VAR , link_to_app )
55
+
50
56
ingress_host = get_runtime_ingress_host ()
51
57
execute_argocd_sync (ingress_host )
52
- namespace = get_runtime_ns ()
53
- status = get_app_status (ingress_host )
58
+ namespace = get_runtime_ns ()
59
+ health , sync = get_app_status (ingress_host )
54
60
55
61
if WAIT_HEALTHY :
56
- status = waitHealthy (ingress_host )
62
+ health , sync = waitHealthy (ingress_host )
57
63
58
64
# if Wait failed, it's time for rollback
59
- if status != "HEALTHY" and ROLLBACK :
65
+ # Failed: Not healthy or out of sync
66
+ if ((health != "HEALTHY" ) or (sync == 'OUT_OF_SYNC' )) and ROLLBACK :
60
67
logging .info ("Application '%s' did not sync properly. Initiating rollback " , APPLICATION )
61
68
revision = getRevision (namespace )
62
69
logging .info ("Latest healthy revision is %d" , revision )
63
70
64
71
rollback (ingress_host , namespace , revision )
65
- logging . info ( "Waiting for rollback to happen" )
72
+
66
73
if WAIT_ROLLBACK :
67
- status = waitHealthy (ingress_host )
74
+ logging .info ("Waiting for rollback to happen" )
75
+ health , sync = waitHealthy (ingress_host )
68
76
else :
69
77
time .sleep (INTERVAL )
70
- status = get_app_status (ingress_host )
78
+ health , sync = get_app_status (ingress_host )
71
79
else :
72
80
export_variable ('ROLLBACK_EXECUTED' , "false" )
81
+
82
+ #
83
+ # We care about those only if we want a HEALTH app
84
+ #
85
+ if health != "HEALTHY" :
86
+ logging .error ("Health Status is not HEALTHY. Exiting with error." )
87
+ sys .exit (1 )
88
+ if sync == 'OUT_OF_SYNC' :
89
+ logging .error ("Sync Status is OUT OF SYNC. Exiting with error." )
90
+ sys .exit (1 )
73
91
else :
74
92
export_variable ('ROLLBACK_EXECUTED' , "false" )
75
93
76
- export_variable ('HEALTH_STATUS' , status )
94
+ export_variable ('HEALTH_STATUS' , health )
77
95
78
- ## Generating link to the Apps Dashboard
79
- CF_OUTPUT_URL_VAR = CF_STEP_NAME + '_CF_OUTPUT_URL'
80
- link_to_app = get_link_to_apps_dashboard ()
81
- export_variable (CF_OUTPUT_URL_VAR , link_to_app )
82
- if status != "HEALTHY" :
83
- logging .debug ("Status is not HEALTHY. Exiting with error." )
84
- sys .exit (1 )
85
96
86
97
#######################################################################
87
98
@@ -128,19 +139,20 @@ def getRevision(namespace):
128
139
sys .exit (1 )
129
140
130
141
def waitHealthy (ingress_host ):
131
- logging .debug ("Entering waitHealthy (ns : %s)" , ingress_host )
142
+ logging .debug ("Entering waitHealthy (host : %s)" , ingress_host )
132
143
133
144
time .sleep (INTERVAL )
134
- status = get_app_status (ingress_host )
135
- logging .info ("App status is %s" , status )
145
+ health , sync = get_app_status (ingress_host )
146
+ logging .info ("App health: %s and sync: %s" , health , sync )
136
147
loop = 0
137
- while status != "HEALTHY" and loop < MAX_CHECKS :
138
- status = get_app_status ( ingress_host )
148
+ while (( health != "HEALTHY" ) or ( sync == 'OUT_OF_SYNC' )) and loop < MAX_CHECKS :
149
+ logging . info ( "App health: %s and sync: %s after %d checks" , health , sync , loop )
139
150
time .sleep (INTERVAL )
140
- logging . info ( "App status is %s after %d checks" , status , loop )
151
+ health , sync = get_app_status ( ingress_host )
141
152
loop += 1
142
- logging .debug ("Returning waitHealthy with '%s'" , status )
143
- return status
153
+
154
+ logging .debug ("Returning waitHealthy with health: '%s' and sync: '%s'" , health , sync )
155
+ return health , sync
144
156
145
157
def rollback (ingress_host , namespace , revision ):
146
158
logging .debug ("Entering rollback(%s, %s, %s)" , ingress_host , namespace , revision )
@@ -167,7 +179,10 @@ def rollback(ingress_host, namespace, revision):
167
179
168
180
169
181
def get_app_status (ingress_host ):
170
- ## Get the health status of the app
182
+ ## Get the health and sync status of the app
183
+ # Health: HEALTHY, PROGRESSING
184
+ # Sync: OUT_OF_SYNC, SYNCED
185
+
171
186
gql_api_endpoint = ingress_host + '/app-proxy/api/graphql'
172
187
transport = RequestsHTTPTransport (
173
188
url = gql_api_endpoint ,
@@ -184,7 +199,8 @@ def get_app_status(ingress_host):
184
199
185
200
logging .debug ("App Status result: %s" , result )
186
201
health = result ['applicationProxyQuery' ]['status' ]['health' ]['status' ]
187
- return health
202
+ sync = result ['applicationProxyQuery' ]['status' ]['sync' ]['status' ]
203
+ return health , sync
188
204
189
205
def get_query (query_name ):
190
206
## To do: get query content from a variable, failback to a file
@@ -244,8 +260,28 @@ def execute_argocd_sync(ingress_host):
244
260
"prune" : True
245
261
}
246
262
}
247
- result = client .execute (query , variable_values = variables )
248
- logging .debug ("Syncing App result: %s" , result )
263
+ try :
264
+ result = client .execute (query , variable_values = variables )
265
+ except TransportQueryError as err :
266
+ if "NOT_FOUND_ERROR" in str (err ):
267
+ print (f"ERROR: Application { APPLICATION } does not exist" )
268
+ else :
269
+ print (f"ERROR: cannot sync Application { APPLICATION } " )
270
+ logging .debug ("Syncing App result: %s" , err )
271
+ sys .exit (2 )
272
+ except Exception as err :
273
+ print (f"ERROR: cannot sync Application { APPLICATION } " )
274
+ logging .debug ("Syncing App result: %s" , err )
275
+ sys .exit (1 )
276
+ # finally:
277
+ # print("finally block")
278
+ # logging.debug("Syncing App result: %s", result)
279
+ # if result.errors[0].message.contains("NOT_FOUND_ERROR"):
280
+ # printf("Application %s does not exit")
281
+ #
282
+ # else:
283
+ # # Application sync'ed properly
284
+ # logging.debug("Syncing App result: %s", result)
249
285
250
286
251
287
def export_variable (var_name , var_value ):
0 commit comments