|
34 | 34 | get_cluster,
|
35 | 35 | _app_wrapper_status,
|
36 | 36 | _ray_cluster_status,
|
| 37 | + list_clusters_all_namespaces, |
37 | 38 | )
|
38 | 39 | from codeflare_sdk.cluster.auth import (
|
39 | 40 | TokenAuthentication,
|
@@ -200,14 +201,168 @@ def test_cluster_deletion_cli(mocker):
|
200 | 201 | runner = CliRunner()
|
201 | 202 | delete_cluster_command = """
|
202 | 203 | delete raycluster
|
203 |
| - quicktest |
| 204 | + quicktest --namespace=default |
204 | 205 | """
|
205 | 206 | result = runner.invoke(cli, delete_cluster_command)
|
206 | 207 |
|
207 | 208 | assert result.exit_code == 0
|
208 | 209 | assert "Cluster deleted successfully" in result.output
|
209 | 210 |
|
210 | 211 |
|
| 212 | +def test_list_clusters_all_namespaces(mocker, capsys): |
| 213 | + mocker.patch( |
| 214 | + "kubernetes.client.CustomObjectsApi.list_cluster_custom_object", |
| 215 | + side_effect=get_ray_obj_no_namespace, |
| 216 | + ) |
| 217 | + list_clusters_all_namespaces() |
| 218 | + captured = capsys.readouterr() |
| 219 | + assert captured.out == ( |
| 220 | + " 🚀 CodeFlare Cluster Details 🚀 \n" |
| 221 | + " \n" |
| 222 | + " ╭──────────────────────────────────────────────────────────────╮ \n" |
| 223 | + " │ Name │ \n" |
| 224 | + " │ quicktest Active ✅ │ \n" |
| 225 | + " │ │ \n" |
| 226 | + " │ URI: ray://quicktest-head-svc.ns.svc:10001 │ \n" |
| 227 | + " │ │ \n" |
| 228 | + " │ Dashboard🔗 │ \n" |
| 229 | + " │ │ \n" |
| 230 | + " │ Cluster Resources │ \n" |
| 231 | + " │ ╭─ Workers ──╮ ╭───────── Worker specs(each) ─────────╮ │ \n" |
| 232 | + " │ │ Min Max │ │ Memory CPU GPU │ │ \n" |
| 233 | + " │ │ │ │ │ │ \n" |
| 234 | + " │ │ 1 1 │ │ 2G~2G 1 0 │ │ \n" |
| 235 | + " │ │ │ │ │ │ \n" |
| 236 | + " │ ╰────────────╯ ╰──────────────────────────────────────╯ │ \n" |
| 237 | + " ╰──────────────────────────────────────────────────────────────╯ \n" |
| 238 | + ) |
| 239 | + |
| 240 | + |
| 241 | +def test_raycluster_details_cli(mocker): |
| 242 | + runner = CliRunner() |
| 243 | + mocker.patch( |
| 244 | + "kubernetes.client.CustomObjectsApi.list_namespaced_custom_object", |
| 245 | + side_effect=get_ray_obj, |
| 246 | + ) |
| 247 | + mocker.patch( |
| 248 | + "codeflare_sdk.cluster.cluster.Cluster.status", |
| 249 | + return_value=(False, CodeFlareClusterStatus.UNKNOWN), |
| 250 | + ) |
| 251 | + mocker.patch( |
| 252 | + "codeflare_sdk.cluster.cluster.Cluster.cluster_dashboard_uri", |
| 253 | + return_value="", |
| 254 | + ) |
| 255 | + mocker.patch.object(client, "ApiClient") |
| 256 | + raycluster_details_command = """ |
| 257 | + details raycluster quicktest --namespace=default |
| 258 | + """ |
| 259 | + result = runner.invoke(cli, raycluster_details_command) |
| 260 | + quicktest_details = ( |
| 261 | + " ╭──────────────────────────────────────────────────────────────╮ \n" |
| 262 | + + " │ Name │ \n" |
| 263 | + + " │ quicktest Inactive ❌ │ \n" |
| 264 | + + " │ │ \n" |
| 265 | + + " │ URI: ray://quicktest-head-svc.ns.svc:10001 │ \n" |
| 266 | + + " │ │ \n" |
| 267 | + + " │ Dashboard🔗 │ \n" |
| 268 | + + " │ │ \n" |
| 269 | + + " │ Cluster Resources │ \n" |
| 270 | + + " │ ╭─ Workers ──╮ ╭───────── Worker specs(each) ─────────╮ │ \n" |
| 271 | + + " │ │ Min Max │ │ Memory CPU GPU │ │ \n" |
| 272 | + + " │ │ │ │ │ │ \n" |
| 273 | + + " │ │ 1 1 │ │ 2~2 1 0 │ │ \n" |
| 274 | + + " │ │ │ │ │ │ \n" |
| 275 | + + " │ ╰────────────╯ ╰──────────────────────────────────────╯ │ \n" |
| 276 | + + " ╰──────────────────────────────────────────────────────────────╯ " |
| 277 | + ) |
| 278 | + assert quicktest_details in result.output |
| 279 | + |
| 280 | + |
| 281 | +def test_raycluster_status_cli(mocker): |
| 282 | + runner = CliRunner() |
| 283 | + mocker.patch( |
| 284 | + "kubernetes.client.CustomObjectsApi.list_namespaced_custom_object", |
| 285 | + side_effect=get_ray_obj, |
| 286 | + ) |
| 287 | + mocker.patch( |
| 288 | + "codeflare_sdk.cluster.cluster.get_current_namespace", |
| 289 | + return_value="ns", |
| 290 | + ) |
| 291 | + mocker.patch( |
| 292 | + "codeflare_sdk.cluster.cluster.Cluster.cluster_dashboard_uri", |
| 293 | + return_value="", |
| 294 | + ) |
| 295 | + mocker.patch.object(client, "ApiClient") |
| 296 | + test_raycluster = RayCluster( |
| 297 | + "quicktest", |
| 298 | + RayClusterStatus.READY, |
| 299 | + 1, |
| 300 | + 1, |
| 301 | + "1", |
| 302 | + "1", |
| 303 | + 1, |
| 304 | + 1, |
| 305 | + "default", |
| 306 | + "dashboard-url", |
| 307 | + ) |
| 308 | + mocker.patch( |
| 309 | + "codeflare_sdk.cluster.cluster._app_wrapper_status", |
| 310 | + return_value=test_raycluster, |
| 311 | + ) |
| 312 | + mocker.patch( |
| 313 | + "codeflare_sdk.cluster.cluster._ray_cluster_status", |
| 314 | + return_value=test_raycluster, |
| 315 | + ) |
| 316 | + raycluster_status_command = """ |
| 317 | + status raycluster quicktest --namespace=default |
| 318 | + """ |
| 319 | + result = runner.invoke(cli, raycluster_status_command) |
| 320 | + assert "Active" in result.output |
| 321 | + |
| 322 | + |
| 323 | +def test_raycluster_list_cli(mocker): |
| 324 | + runner = CliRunner() |
| 325 | + mocker.patch( |
| 326 | + "kubernetes.client.CustomObjectsApi.list_namespaced_custom_object", |
| 327 | + side_effect=get_ray_obj, |
| 328 | + ) |
| 329 | + mocker.patch( |
| 330 | + "codeflare_sdk.cluster.cluster.get_current_namespace", |
| 331 | + return_value="ns", |
| 332 | + ) |
| 333 | + mocker.patch( |
| 334 | + "codeflare_sdk.cluster.cluster.Cluster.status", |
| 335 | + return_value=(False, CodeFlareClusterStatus.UNKNOWN), |
| 336 | + ) |
| 337 | + mocker.patch( |
| 338 | + "codeflare_sdk.cluster.cluster.Cluster.cluster_dashboard_uri", |
| 339 | + return_value="", |
| 340 | + ) |
| 341 | + mocker.patch.object(client, "ApiClient") |
| 342 | + list_rayclusters_command = """ |
| 343 | + list rayclusters --namespace=ns |
| 344 | + """ |
| 345 | + result = runner.invoke(cli, list_rayclusters_command) |
| 346 | + assert ( |
| 347 | + " ╭──────────────────────────────────────────────────────────────╮ \n" |
| 348 | + + " │ Name │ \n" |
| 349 | + + " │ quicktest Active ✅ │ \n" |
| 350 | + + " │ │ \n" |
| 351 | + + " │ URI: ray://quicktest-head-svc.ns.svc:10001 │ \n" |
| 352 | + + " │ │ \n" |
| 353 | + + " │ Dashboard🔗 │ \n" |
| 354 | + + " │ │ \n" |
| 355 | + + " │ Cluster Resources │ \n" |
| 356 | + + " │ ╭─ Workers ──╮ ╭───────── Worker specs(each) ─────────╮ │ \n" |
| 357 | + + " │ │ Min Max │ │ Memory CPU GPU │ │ \n" |
| 358 | + + " │ │ │ │ │ │ \n" |
| 359 | + + " │ │ 1 1 │ │ 2G~2G 1 0 │ │ \n" |
| 360 | + + " │ │ │ │ │ │ \n" |
| 361 | + + " │ ╰────────────╯ ╰──────────────────────────────────────╯ │ \n" |
| 362 | + + " ╰──────────────────────────────────────────────────────────────╯ " |
| 363 | + ) in result.output |
| 364 | + |
| 365 | + |
211 | 366 | # For mocking openshift client results
|
212 | 367 | fake_res = openshift.Result("fake")
|
213 | 368 |
|
@@ -992,6 +1147,10 @@ def get_ray_obj(group, version, namespace, plural, cls=None):
|
992 | 1147 | return api_obj
|
993 | 1148 |
|
994 | 1149 |
|
| 1150 | +def get_ray_obj_no_namespace(group, version, plural, cls=None): |
| 1151 | + return get_ray_obj(group, version, "ns", plural, cls) |
| 1152 | + |
| 1153 | + |
995 | 1154 | def get_aw_obj(group, version, namespace, plural):
|
996 | 1155 | api_obj1 = {
|
997 | 1156 | "items": [
|
@@ -2360,4 +2519,3 @@ def test_cleanup():
|
2360 | 2519 | os.remove("tls-cluster-namespace/tls.key")
|
2361 | 2520 | os.rmdir("tls-cluster-namespace")
|
2362 | 2521 | os.remove("cli-test-cluster.yaml")
|
2363 |
| - os.removedirs(os.path.expanduser("~/.codeflare")) |
|
0 commit comments