1818import contextlib
1919import io
2020import os
21- from time import sleep
21+ import warnings
2222import time
2323import codeflare_sdk
2424from kubernetes import client
@@ -103,7 +103,13 @@ def is_notebook() -> bool:
103103
104104
105105def view_clusters (namespace : str = None ):
106- """view_clusters function will display existing clusters with their specs, and handle user interactions."""
106+ """
107+ view_clusters function will display existing clusters with their specs, and handle user interactions.
108+ """
109+ if not is_notebook ():
110+ warnings .warn ("view_clusters can only be used in a Jupyter Notebook environment." )
111+ return # Exit function if not in Jupyter Notebook
112+
107113 from .cluster import get_current_namespace
108114 if not namespace :
109115 namespace = get_current_namespace ()
@@ -112,13 +118,13 @@ def view_clusters(namespace: str = None):
112118 raycluster_data_output = widgets .Output ()
113119 url_output = widgets .Output ()
114120
115- df = _fetch_cluster_data (namespace )
116- if df .empty :
121+ ray_clusters_df = _fetch_cluster_data (namespace )
122+ if ray_clusters_df .empty :
117123 print (f"No clusters found in the { namespace } namespace." )
118124 return
119125
120126 classification_widget = widgets .ToggleButtons (
121- options = df ["Name" ].tolist (), value = df ["Name" ].tolist ()[0 ],
127+ options = ray_clusters_df ["Name" ].tolist (), value = ray_clusters_df ["Name" ].tolist ()[0 ],
122128 description = 'Select an existing cluster:' ,
123129 )
124130 # Setting the initial value to trigger the event handler to display the cluster details.
@@ -132,39 +138,45 @@ def view_clusters(namespace: str = None):
132138 icon = 'trash' ,
133139 tooltip = "Delete the selected cluster"
134140 )
135- delete_button .on_click (lambda b : _on_delete_button_click (b , classification_widget , df , raycluster_data_output , user_output , delete_button , list_jobs_button , ray_dashboard_button ))
141+ delete_button .on_click (lambda b : _on_delete_button_click (b , classification_widget , ray_clusters_df , raycluster_data_output , user_output , delete_button , list_jobs_button , ray_dashboard_button ))
136142
137143 list_jobs_button = widgets .Button (
138144 description = 'View Jobs' ,
139145 icon = 'suitcase' ,
140146 tooltip = "Open the Ray Job Dashboard"
141147 )
142- list_jobs_button .on_click (lambda b : _on_list_jobs_button_click (b , classification_widget , df , user_output , url_output ))
148+ list_jobs_button .on_click (lambda b : _on_list_jobs_button_click (b , classification_widget , ray_clusters_df , user_output , url_output ))
143149
144150 ray_dashboard_button = widgets .Button (
145151 description = 'Open Ray Dashboard' ,
146152 icon = 'dashboard' ,
147153 tooltip = "Open the Ray Dashboard in a new tab" ,
148154 layout = widgets .Layout (width = 'auto' ),
149155 )
150- ray_dashboard_button .on_click (lambda b : _on_ray_dashboard_button_click (b , classification_widget , df , user_output , url_output ))
156+ ray_dashboard_button .on_click (lambda b : _on_ray_dashboard_button_click (b , classification_widget , ray_clusters_df , user_output , url_output ))
151157
152158 display (widgets .VBox ([classification_widget , raycluster_data_output ]))
153159 display (widgets .HBox ([delete_button , list_jobs_button , ray_dashboard_button ]), url_output , user_output )
154160
155- # Handles the event when a cluster is selected from the toggle buttons, updating the output with cluster details.
161+
156162def _on_cluster_click (selection_change , raycluster_data_output : widgets .Output , namespace : str , classification_widget : widgets .ToggleButtons ):
163+ """
164+ _on_cluster_click handles the event when a cluster is selected from the toggle buttons, updating the output with cluster details.
165+ """
157166 new_value = selection_change ["new" ]
158167 raycluster_data_output .clear_output ()
159- df = _fetch_cluster_data (namespace )
160- classification_widget .options = df ["Name" ].tolist ()
168+ ray_clusters_df = _fetch_cluster_data (namespace )
169+ classification_widget .options = ray_clusters_df ["Name" ].tolist ()
161170 with raycluster_data_output :
162- display (HTML (df [ df ["Name" ]== new_value ][["Name" , "Namespace" , "Head GPUs" , "Head CPU Req~Lim" , "Head Memory Req~Lim" , "Worker GPUs" , "Worker CPU Req~Lim" , "Worker Memory Req~Lim" , "status" ]].to_html (escape = False , index = False , border = 2 )))
171+ display (HTML (ray_clusters_df [ ray_clusters_df ["Name" ]== new_value ][["Name" , "Namespace" , "Num Workers " , "Head GPUs" , "Head CPU Req~Lim" , "Head Memory Req~Lim" , "Worker GPUs" , "Worker CPU Req~Lim" , "Worker Memory Req~Lim" , "status" ]].to_html (escape = False , index = False , border = 2 )))
163172
164173
165- def _on_delete_button_click (b , classification_widget : widgets .ToggleButtons , df : pd .DataFrame , raycluster_data_output : widgets .Output , user_output : widgets .Output , delete_button : widgets .Button , list_jobs_button : widgets .Button , ray_dashboard_button : widgets .Button ):
174+ def _on_delete_button_click (b , classification_widget : widgets .ToggleButtons , ray_clusters_df : pd .DataFrame , raycluster_data_output : widgets .Output , user_output : widgets .Output , delete_button : widgets .Button , list_jobs_button : widgets .Button , ray_dashboard_button : widgets .Button ):
175+ """
176+ _on_delete_button_click handles the event when the Delete Button is clicked, deleting the selected cluster.
177+ """
166178 cluster_name = classification_widget .value
167- namespace = df [ df ["Name" ]== classification_widget .value ]["Namespace" ].values [0 ]
179+ namespace = ray_clusters_df [ ray_clusters_df ["Name" ]== classification_widget .value ]["Namespace" ].values [0 ]
168180
169181 _delete_cluster (cluster_name , namespace )
170182
@@ -185,10 +197,13 @@ def _on_delete_button_click(b, classification_widget: widgets.ToggleButtons, df:
185197 else :
186198 classification_widget .options = new_df ["Name" ].tolist ()
187199
188- def _on_ray_dashboard_button_click (b , classification_widget : widgets .ToggleButtons , df : pd .DataFrame , user_output : widgets .Output , url_output : widgets .Output ):
200+ def _on_ray_dashboard_button_click (b , classification_widget : widgets .ToggleButtons , ray_clusters_df : pd .DataFrame , user_output : widgets .Output , url_output : widgets .Output ):
201+ """
202+ _on_ray_dashboard_button_click handles the event when the Open Ray Dashboard button is clicked, opening the Ray Dashboard in a new tab
203+ """
189204 from codeflare_sdk .cluster import Cluster
190205 cluster_name = classification_widget .value
191- namespace = df [ df ["Name" ]== classification_widget .value ]["Namespace" ].values [0 ]
206+ namespace = ray_clusters_df [ ray_clusters_df ["Name" ]== classification_widget .value ]["Namespace" ].values [0 ]
192207
193208 # Suppress from Cluster Object initialisation widgets and outputs
194209 with widgets .Output (), contextlib .redirect_stdout (io .StringIO ()), contextlib .redirect_stderr (io .StringIO ()):
@@ -201,10 +216,13 @@ def _on_ray_dashboard_button_click(b, classification_widget: widgets.ToggleButto
201216 with url_output :
202217 display (Javascript (f'window.open("{ dashboard_url } ", "_blank");' ))
203218
204- def _on_list_jobs_button_click (b , classification_widget : widgets .ToggleButtons , df : pd .DataFrame , user_output : widgets .Output , url_output : widgets .Output ):
219+ def _on_list_jobs_button_click (b , classification_widget : widgets .ToggleButtons , ray_clusters_df : pd .DataFrame , user_output : widgets .Output , url_output : widgets .Output ):
220+ """
221+ _on_list_jobs_button_click handles the event when the View Jobs button is clicked, opening the Ray Jobs Dashboard in a new tab
222+ """
205223 from codeflare_sdk .cluster import Cluster
206224 cluster_name = classification_widget .value
207- namespace = df [ df ["Name" ]== classification_widget .value ]["Namespace" ].values [0 ]
225+ namespace = ray_clusters_df [ ray_clusters_df ["Name" ]== classification_widget .value ]["Namespace" ].values [0 ]
208226
209227 # Suppress from Cluster Object initialisation widgets and outputs
210228 with widgets .Output (), contextlib .redirect_stdout (io .StringIO ()), contextlib .redirect_stderr (io .StringIO ()):
@@ -217,12 +235,17 @@ def _on_list_jobs_button_click(b, classification_widget: widgets.ToggleButtons,
217235 with url_output :
218236 display (Javascript (f'window.open("{ dashboard_url } /#/jobs", "_blank");' ))
219237
238+
220239def _delete_cluster (
221240 cluster_name : str ,
222241 namespace : str ,
223242 timeout : int = 5 ,
224243 interval : int = 1 ,
225244):
245+ """
246+ _delete_cluster function deletes the cluster with the given name and namespace.
247+ It optionally waits for the cluster to be deleted.
248+ """
226249 from .cluster import _check_aw_exists
227250
228251 try :
@@ -276,12 +299,16 @@ def _delete_cluster(
276299
277300
278301def _fetch_cluster_data (namespace ):
302+ """
303+ _fetch_cluster_data function fetches all clusters and their spec in a given namespace and returns a DataFrame.
304+ """
279305 from .cluster import list_all_clusters
280306 rayclusters = list_all_clusters (namespace , False )
281307 if not rayclusters :
282308 return pd .DataFrame ()
283309 names = [item .name for item in rayclusters ]
284310 namespaces = [item .namespace for item in rayclusters ]
311+ num_workers = [item .num_workers for item in rayclusters ]
285312 head_extended_resources = [
286313 f"{ list (item .head_extended_resources .keys ())[0 ]} : { list (item .head_extended_resources .values ())[0 ]} "
287314 if item .head_extended_resources else "0"
@@ -311,6 +338,7 @@ def _fetch_cluster_data(namespace):
311338 data = {
312339 "Name" : names ,
313340 "Namespace" : namespaces ,
341+ "Num Workers" : num_workers ,
314342 "Head GPUs" : head_extended_resources ,
315343 "Worker GPUs" : worker_extended_resources ,
316344 "Head CPU Req~Lim" : head_cpu_rl ,
@@ -323,6 +351,9 @@ def _fetch_cluster_data(namespace):
323351
324352
325353def _format_status (status ):
354+ """
355+ _format_status function formats the status enum.
356+ """
326357 status_map = {
327358 RayClusterStatus .READY : '<span style="color: green;">Ready ✓</span>' ,
328359 RayClusterStatus .SUSPENDED : '<span style="color: #007BFF;">Suspended ❄️</span>' ,
0 commit comments