@@ -79,6 +79,102 @@ def build_malfunction_row(
7979 ]
8080
8181
82+ def insert_cluster_status_lists (
83+ credentials , status_list , project_name , cluster_name , location , now_utc
84+ ):
85+ """Insert both cluster + nodepool status into list"""
86+ try :
87+ # Cannot query cluster info without location
88+ if not location :
89+ raise NotFound (
90+ "The requested resource can not be found on the server without location."
91+ )
92+ info = get_cluster_status (credentials , project_name , location , cluster_name )
93+ cluster_status = info ["status" ]
94+ cluster_status_message = info ["status_message" ]
95+ mal_node_pools = [
96+ node_pool
97+ for node_pool in info ["node_pools" ]
98+ if node_pool ["status" ]
99+ not in [
100+ Status .RUNNING .value ,
101+ Status .PROVISIONING .value ,
102+ Status .STOPPING .value ,
103+ ]
104+ ]
105+ is_cluster_malfunction = (
106+ cluster_status != Status .RUNNING .value
107+ and cluster_status != Status .RECONCILING .value
108+ )
109+ malfunction_node_pools_exist = len (mal_node_pools ) > 0
110+
111+ if is_cluster_malfunction and malfunction_node_pools_exist :
112+ status_list .append (
113+ build_malfunction_row (
114+ issue_type = IssueType .CLUSTER_AND_NODE_POOL ,
115+ proj = project_name ,
116+ cluster_name = cluster_name ,
117+ cluster_location = location ,
118+ cluster_status = cluster_status ,
119+ cluster_status_message = cluster_status_message ,
120+ node_pools = mal_node_pools ,
121+ now_utc = now_utc ,
122+ )
123+ )
124+ elif is_cluster_malfunction :
125+ status_list .append (
126+ build_malfunction_row (
127+ issue_type = IssueType .CLUSTER ,
128+ proj = project_name ,
129+ cluster_location = location ,
130+ cluster_name = cluster_name ,
131+ cluster_status = cluster_status ,
132+ cluster_status_message = cluster_status_message ,
133+ now_utc = now_utc ,
134+ )
135+ )
136+ elif malfunction_node_pools_exist :
137+ status_list .append (
138+ build_malfunction_row (
139+ issue_type = IssueType .NODE_POOL ,
140+ proj = project_name ,
141+ cluster_name = cluster_name ,
142+ cluster_location = location ,
143+ cluster_status = cluster_status ,
144+ cluster_status_message = cluster_status_message ,
145+ node_pools = mal_node_pools ,
146+ now_utc = now_utc ,
147+ )
148+ )
149+ except NotFound :
150+ status_list .append (
151+ build_malfunction_row (
152+ issue_type = IssueType .CLUSTER ,
153+ proj = project_name ,
154+ cluster_name = cluster_name ,
155+ cluster_location = UNKNOW_LOCATION ,
156+ cluster_status = Status .NOT_EXIST .value ,
157+ cluster_status_message = NOT_FOUND_MSG ,
158+ now_utc = now_utc ,
159+ )
160+ )
161+ except Exception as e :
162+ logging .info (
163+ f"Error fetching details for { project_name } /{ cluster_name } : { e } "
164+ )
165+ status_list .append (
166+ build_malfunction_row (
167+ issue_type = IssueType .CLUSTER ,
168+ proj = project_name ,
169+ cluster_name = cluster_name ,
170+ cluster_location = UNKNOW_LOCATION ,
171+ cluster_status = Status .ERROR .value ,
172+ cluster_status_message = str (e ),
173+ now_utc = now_utc ,
174+ )
175+ )
176+
177+
82178def print_failed_cluster_info (cluster_status_rows ):
83179 """Log failed cluster info for debugging"""
84180 result_rows_list = []
@@ -115,7 +211,7 @@ def insert_gspread_rows(rows: List[List[str]], sheet_id: str):
115211 insert_data_option = "INSERT_ROWS" ,
116212 value_input_option = "RAW" ,
117213 )
118- logging .info (f"Successfully appended rows to Google Sheet." )
214+ logging .info (f"Successfully appended { len ( rows ) } rows to Google Sheet." )
119215 except Exception as e :
120216 logging .error (f"An error occurred while writing to Google Sheet: { e } " )
121217
@@ -130,7 +226,7 @@ def get_clusters_from_view(credential) -> List[Any]:
130226 dataset_id = context ["params" ]["source_bq_dataset_id" ] or DEFAULT_DATASET_ID
131227 client = bigquery .Client (project = project_id , credentials = credential )
132228 query = f"""
133- SELECT project_name, cluster_name
229+ SELECT project_name, cluster_name, region
134230 FROM `{ project_id } .{ dataset_id } .cluster_view`
135231 """
136232 rows = list (client .query (query ).result ())
@@ -141,14 +237,6 @@ def get_clusters_from_view(credential) -> List[Any]:
141237# ================================================================
142238# Step 4: GKE Functions
143239# ================================================================
144- def list_clusters_by_project (credentials , project_id ) -> List [Any ]:
145- """List all clusters in a given GCP project"""
146- client = container_v1 .ClusterManagerClient (credentials = credentials )
147- parent = f"projects/{ project_id } /locations/-"
148- response = client .list_clusters (request = {"parent" : parent })
149- return response .clusters if response and response .clusters else []
150-
151-
152240def get_cluster_status (
153241 credentials , project_id , location , cluster_name
154242) -> Dict [str , Any ]:
@@ -180,7 +268,7 @@ def get_cluster_status(
180268
181269 return {
182270 "project_id" : project_id ,
183- "region " : location ,
271+ "location " : location ,
184272 "cluster_name" : cluster_name ,
185273 "status" : container_v1 .Cluster .Status (cluster .status ).name
186274 if cluster .status
@@ -193,144 +281,25 @@ def get_cluster_status(
193281# ================================================================
194282# Step 5: Workflow Functions
195283# ================================================================
196- def fetch_clusters_list (credential ):
284+ def fetch_clusters (credential ) -> List [ str ] :
197285 clusters = get_clusters_from_view (credential = credential )
198286 if not clusters :
199287 logging .info ("No rows found in view." )
200288 return []
201289 return clusters
202290
203291
204- def fetch_clusters_location (credentials , clusters ) -> Dict [str , Any ]:
205- """Map project::cluster_name -> location"""
206- cluster_locations = {}
207- projects = set (cluster .project_name for cluster in clusters )
208- logging .info (f"Fetching clusters from { len (projects )} distinct projects..." )
209- for idx , project in enumerate (projects , 1 ):
210- try :
211- clusters = list_clusters_by_project (
212- credentials = credentials , project_id = project
213- )
214- logging .info (
215- f"[{ idx } /{ len (projects )} ] { project } : { len (clusters )} clusters"
216- )
217- for cluster in clusters :
218- key = f"{ project } ::{ cluster .name } "
219- cluster_locations [key ] = cluster .location
220- except Exception as e :
221- logging .info (f"Error listing clusters for { project } : { e } " )
222- return cluster_locations
223-
224-
225- def insert_cluster_status_lists (
226- credentials , status_list , project_name , location , cluster_name , now_utc
227- ):
228- """Insert both cluster + nodepool status into list"""
229- try :
230- # Cannot query cluster info without location
231- if not location :
232- raise NotFound ("The requested resource was not found on the server." )
233- info = get_cluster_status (credentials , project_name , location , cluster_name )
234- cluster_status = info ["status" ]
235- cluster_status_message = info ["status_message" ]
236- mal_node_pools = [
237- node_pool
238- for node_pool in info ["node_pools" ]
239- if node_pool ["status" ] != Status .RUNNING .value
240- and node_pool ["status" ] != Status .PROVISIONING .value
241- and node_pool ["status" ] != Status .STOPPING .value
242- ]
243- is_cluster_malfunction = (
244- cluster_status != Status .RUNNING .value
245- and cluster_status != Status .RECONCILING .value
246- )
247- malfunction_node_pools_exist = len (mal_node_pools ) > 0
248-
249- if is_cluster_malfunction and malfunction_node_pools_exist :
250- status_list .append (
251- build_malfunction_row (
252- issue_type = IssueType .CLUSTER_AND_NODE_POOL ,
253- proj = project_name ,
254- cluster_name = cluster_name ,
255- cluster_location = location ,
256- cluster_status = cluster_status ,
257- cluster_status_message = cluster_status_message ,
258- node_pools = mal_node_pools ,
259- now_utc = now_utc ,
260- )
261- )
262- elif is_cluster_malfunction :
263- status_list .append (
264- build_malfunction_row (
265- issue_type = IssueType .CLUSTER ,
266- proj = project_name ,
267- cluster_location = location ,
268- cluster_name = cluster_name ,
269- cluster_status = cluster_status ,
270- cluster_status_message = cluster_status_message ,
271- now_utc = now_utc ,
272- )
273- )
274- elif malfunction_node_pools_exist :
275- status_list .append (
276- build_malfunction_row (
277- issue_type = IssueType .NODE_POOL ,
278- proj = project_name ,
279- cluster_name = cluster_name ,
280- cluster_location = location ,
281- cluster_status = cluster_status ,
282- cluster_status_message = cluster_status_message ,
283- node_pools = mal_node_pools ,
284- now_utc = now_utc ,
285- )
286- )
287- except NotFound :
288- status_list .append (
289- build_malfunction_row (
290- issue_type = IssueType .CLUSTER ,
291- proj = project_name ,
292- cluster_name = cluster_name ,
293- cluster_location = UNKNOW_LOCATION ,
294- cluster_status = Status .NOT_EXIST .value ,
295- cluster_status_message = NOT_FOUND_MSG ,
296- now_utc = now_utc ,
297- )
298- )
299- except Exception as e :
300- logging .info (
301- f"Error fetching details for { project_name } /{ cluster_name } : { e } "
302- )
303- status_list .append (
304- build_malfunction_row (
305- issue_type = IssueType .CLUSTER ,
306- proj = project_name ,
307- cluster_name = cluster_name ,
308- cluster_location = UNKNOW_LOCATION ,
309- cluster_status = Status .ERROR .value ,
310- cluster_status_message = str (e ),
311- now_utc = now_utc ,
312- )
313- )
314-
315-
316- def fetch_clusters_status (
317- credentials , clusters_list : List [Any ], cluster_locations : Dict [str , Any ]
318- ) -> List [Any ]:
292+ def fetch_clusters_status (credentials , clusters : List [Any ]) -> List [Any ]:
319293 """Fetch status for all clusters & node pools"""
320294 cluster_status_rows = []
321295 now_utc = datetime .now (timezone .utc ).isoformat ()
322- for cluster in clusters_list :
323- project_name = cluster .project_name
324- cluster_name = cluster .cluster_name
325- key = f"{ project_name } ::{ cluster_name } "
326- location = cluster_locations .get (key )
327- # cluster_status_rows is parameter for output
296+ for cluster in clusters :
328297 insert_cluster_status_lists (
329298 credentials ,
330299 cluster_status_rows ,
331- project_name ,
332- location ,
333- cluster_name ,
300+ cluster . project_name ,
301+ cluster . cluster_name ,
302+ cluster . region ,
334303 now_utc ,
335304 )
336305 print_failed_cluster_info (cluster_status_rows )
@@ -345,13 +314,8 @@ def pull_clusters_status() -> List[Any]:
345314 credentials , _ = google .auth .default (
346315 scopes = ["https://www.googleapis.com/auth/cloud-platform" ]
347316 )
348- target_clusters_list = fetch_clusters_list (credentials )
349- target_clusters_locations = fetch_clusters_location (
350- credentials , target_clusters_list
351- )
352- return fetch_clusters_status (
353- credentials , target_clusters_list , target_clusters_locations
354- )
317+ target_clusters = fetch_clusters (credentials )
318+ return fetch_clusters_status (credentials , target_clusters )
355319
356320
357321@task
0 commit comments