outerbounds 0.8.0rc1__py3-none-any.whl → 0.8.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- outerbounds/command_groups/workstations_cli.py +30 -9
- outerbounds/utils/kubectl_utils.py +2 -2
- outerbounds/utils/ssh_utils.py +26 -6
- {outerbounds-0.8.0rc1.dist-info → outerbounds-0.8.1.dist-info}/METADATA +5 -4
- {outerbounds-0.8.0rc1.dist-info → outerbounds-0.8.1.dist-info}/RECORD +7 -7
- {outerbounds-0.8.0rc1.dist-info → outerbounds-0.8.1.dist-info}/WHEEL +1 -1
- {outerbounds-0.8.0rc1.dist-info → outerbounds-0.8.1.dist-info}/entry_points.txt +0 -0
@@ -598,7 +598,11 @@ def show_relevant_links(config_dir=None, profile=None, perimeter_id="", output="
|
|
598
598
|
click.secho("Error: {}".format(str(e)), fg="red", err=True)
|
599
599
|
|
600
600
|
|
601
|
-
|
601
|
+
WORKSTATION_CONNECT_MODE = "workstation-connect"
|
602
|
+
WORKSTATION_INIT_MODE = "workstation-init"
|
603
|
+
|
604
|
+
|
605
|
+
@cli.command(help="Prepare a workstation for SSH access", hidden=True)
|
602
606
|
@click.option(
|
603
607
|
"--workstation-id",
|
604
608
|
default="",
|
@@ -618,11 +622,24 @@ def show_relevant_links(config_dir=None, profile=None, perimeter_id="", output="
|
|
618
622
|
help="Show output in the specified format.",
|
619
623
|
type=click.Choice(["json", ""]),
|
620
624
|
)
|
621
|
-
|
625
|
+
@click.option(
|
626
|
+
"--mode",
|
627
|
+
default="workstation-connect",
|
628
|
+
help="The mode in which the command is being run.",
|
629
|
+
type=click.Choice([WORKSTATION_CONNECT_MODE, WORKSTATION_INIT_MODE]),
|
630
|
+
)
|
631
|
+
def prepare_for_ssh_access(
|
632
|
+
workstation_id="", setup_context="", output="", mode=WORKSTATION_CONNECT_MODE
|
633
|
+
):
|
622
634
|
"""
|
623
635
|
Finds the pod whose WORKSTATION_NAME env var matches `workstation_name`
|
624
636
|
and opens an interactive bash shell in its "workstation" container.
|
625
637
|
"""
|
638
|
+
|
639
|
+
# Workstation Init is only supported on remote workstation.
|
640
|
+
if mode == WORKSTATION_INIT_MODE and setup_context == "local":
|
641
|
+
raise Exception("workstation-init mode is not supported for local setup")
|
642
|
+
|
626
643
|
response = {
|
627
644
|
"status": "OK",
|
628
645
|
"message": "SSH access prepared successfully",
|
@@ -631,7 +648,7 @@ def prepare_for_ssh_access(workstation_id="", setup_context="", output=""):
|
|
631
648
|
if setup_context == "local":
|
632
649
|
prepare_for_ssh_access_local(workstation_id)
|
633
650
|
elif setup_context == "remote":
|
634
|
-
prepare_for_ssh_access_remote()
|
651
|
+
prepare_for_ssh_access_remote(mode)
|
635
652
|
except Exception as e:
|
636
653
|
response["message"] = str(e)
|
637
654
|
response["status"] = "FAIL"
|
@@ -699,7 +716,7 @@ def prepare_for_ssh_access_local(workstation_id):
|
|
699
716
|
raise Exception(f"Failed to add entry to ssh config: {msg}")
|
700
717
|
|
701
718
|
|
702
|
-
def prepare_for_ssh_access_remote():
|
719
|
+
def prepare_for_ssh_access_remote(mode: str):
|
703
720
|
"""
|
704
721
|
SSH connection requires both local instance and workstation pod to do some work.
|
705
722
|
This function takes care of the remote instance.
|
@@ -712,16 +729,20 @@ def prepare_for_ssh_access_remote():
|
|
712
729
|
if "WORKSTATION_ID" not in os.environ:
|
713
730
|
raise Exception("This can only be run from a workstation!")
|
714
731
|
|
715
|
-
ok, message = ssh_utils.
|
732
|
+
ok, message = ssh_utils.best_effort_install_remote_deps()
|
716
733
|
if not ok:
|
717
|
-
raise Exception(f"Failed to install
|
734
|
+
raise Exception(f"Failed to install deps in remote instance: {message}")
|
718
735
|
|
719
736
|
ok, msg = ssh_utils.configure_ssh_server()
|
720
737
|
if not ok:
|
721
738
|
raise Exception(f"Failed to configure ssh server: {msg}")
|
722
739
|
|
723
|
-
|
724
|
-
if
|
725
|
-
|
740
|
+
# SSH keys can only be guaranteed to be present when a connection is initiated.
|
741
|
+
if mode == WORKSTATION_CONNECT_MODE:
|
742
|
+
ok, msg = ssh_utils.ensure_public_key_registered_in_ssh_agent()
|
743
|
+
if not ok:
|
744
|
+
raise Exception(
|
745
|
+
f"Failed to ensure public key registered in ssh agent: {msg}"
|
746
|
+
)
|
726
747
|
|
727
748
|
ssh_utils.add_env_loader_to_bashrc()
|
@@ -3,7 +3,7 @@ import subprocess
|
|
3
3
|
from typing import Tuple
|
4
4
|
|
5
5
|
|
6
|
-
def exec_in_pod(pod_name: str, namespace: str, command: str) -> Tuple[int, str]:
|
6
|
+
def exec_in_pod(pod_name: str, namespace: str, command: str) -> Tuple[int, str, str]:
|
7
7
|
"""
|
8
8
|
Executes a command using kubectl exec in the remote pod.
|
9
9
|
"""
|
@@ -39,7 +39,7 @@ def exec_in_pod(pod_name: str, namespace: str, command: str) -> Tuple[int, str]:
|
|
39
39
|
|
40
40
|
def cp_to_pod(
|
41
41
|
pod_name: str, namespace: str, source_on_local: str, destination_on_pod: str
|
42
|
-
) -> Tuple[int, str]:
|
42
|
+
) -> Tuple[int, str, str]:
|
43
43
|
"""
|
44
44
|
Copies a file to a pod using kubectl cp.
|
45
45
|
"""
|
outerbounds/utils/ssh_utils.py
CHANGED
@@ -318,7 +318,7 @@ fi
|
|
318
318
|
return False
|
319
319
|
|
320
320
|
|
321
|
-
def
|
321
|
+
def best_effort_install_remote_deps():
|
322
322
|
"""
|
323
323
|
Best effort installation of openssh-server and netcat.
|
324
324
|
|
@@ -369,42 +369,49 @@ def best_effort_install_ssh_netcat():
|
|
369
369
|
"install": "apt-get install -y",
|
370
370
|
"ssh_package": "openssh-server",
|
371
371
|
"nc_packages": ["netcat-openbsd", "netcat-traditional", "netcat"],
|
372
|
+
"curl_package": "curl",
|
372
373
|
},
|
373
374
|
"apt": {
|
374
375
|
"update": "apt update",
|
375
376
|
"install": "apt install -y",
|
376
377
|
"ssh_package": "openssh-server",
|
377
378
|
"nc_packages": ["netcat-openbsd", "netcat-traditional", "netcat"],
|
379
|
+
"curl_package": "curl",
|
378
380
|
},
|
379
381
|
"yum": {
|
380
382
|
"update": "yum makecache",
|
381
383
|
"install": "yum install -y",
|
382
384
|
"ssh_package": "openssh-server",
|
383
385
|
"nc_packages": ["nmap-ncat", "nc", "netcat"],
|
386
|
+
"curl_package": "curl",
|
384
387
|
},
|
385
388
|
"dnf": {
|
386
389
|
"update": "dnf makecache",
|
387
390
|
"install": "dnf install -y",
|
388
391
|
"ssh_package": "openssh-server",
|
389
392
|
"nc_packages": ["nmap-ncat", "nc", "netcat"],
|
393
|
+
"curl_package": "curl",
|
390
394
|
},
|
391
395
|
"zypper": {
|
392
396
|
"update": "zypper refresh",
|
393
397
|
"install": "zypper install -n",
|
394
398
|
"ssh_package": "openssh",
|
395
399
|
"nc_packages": ["netcat-openbsd", "gnu-netcat", "netcat"],
|
400
|
+
"curl_package": "curl",
|
396
401
|
},
|
397
402
|
"pacman": {
|
398
403
|
"update": "pacman -Sy",
|
399
404
|
"install": "pacman -S --noconfirm",
|
400
405
|
"ssh_package": "openssh",
|
401
406
|
"nc_packages": ["gnu-netcat", "openbsd-netcat"],
|
407
|
+
"curl_package": "curl",
|
402
408
|
},
|
403
409
|
"apk": {
|
404
410
|
"update": "apk update",
|
405
411
|
"install": "apk add --no-cache",
|
406
412
|
"ssh_package": "openssh-server",
|
407
|
-
"nc_packages": ["netcat-openbsd"
|
413
|
+
"nc_packages": ["netcat-openbsd"],
|
414
|
+
"curl_package": "curl",
|
408
415
|
},
|
409
416
|
}
|
410
417
|
|
@@ -431,9 +438,10 @@ def best_effort_install_ssh_netcat():
|
|
431
438
|
or check_command_exists("netcat")
|
432
439
|
or check_command_exists("ncat")
|
433
440
|
)
|
441
|
+
curl_installed = check_command_exists("curl")
|
434
442
|
|
435
|
-
if ssh_installed and nc_installed:
|
436
|
-
return True, "
|
443
|
+
if ssh_installed and nc_installed and curl_installed:
|
444
|
+
return True, "openssh-server, netcat, and curl are already installed"
|
437
445
|
|
438
446
|
# Prepare status messages
|
439
447
|
status = []
|
@@ -441,6 +449,8 @@ def best_effort_install_ssh_netcat():
|
|
441
449
|
status.append("openssh-server is already installed")
|
442
450
|
if nc_installed:
|
443
451
|
status.append("netcat is already installed")
|
452
|
+
if curl_installed:
|
453
|
+
status.append("curl is already installed")
|
444
454
|
|
445
455
|
# Step 2 & 3: Check sudo availability and access
|
446
456
|
has_sudo = check_command_exists("sudo")
|
@@ -504,6 +514,15 @@ def best_effort_install_ssh_netcat():
|
|
504
514
|
or check_command_exists("ncat")
|
505
515
|
)
|
506
516
|
|
517
|
+
# Install curl if needed
|
518
|
+
if not curl_installed:
|
519
|
+
curl_package = pm_config["curl_package"]
|
520
|
+
if install_package(curl_package, pm_config, use_sudo):
|
521
|
+
status.append(f"Successfully installed {curl_package}")
|
522
|
+
curl_installed = check_command_exists("curl")
|
523
|
+
else:
|
524
|
+
status.append(f"Failed to install {curl_package}")
|
525
|
+
|
507
526
|
# Step 7: Final check and return appropriate message
|
508
527
|
ssh_final = check_ssh_server()
|
509
528
|
nc_final = (
|
@@ -511,10 +530,11 @@ def best_effort_install_ssh_netcat():
|
|
511
530
|
or check_command_exists("netcat")
|
512
531
|
or check_command_exists("ncat")
|
513
532
|
)
|
533
|
+
curl_final = check_command_exists("curl")
|
514
534
|
|
515
|
-
if ssh_final and nc_final:
|
535
|
+
if ssh_final and nc_final and curl_final:
|
516
536
|
return True, "Successfully installed all required packages. " + " ".join(status)
|
517
|
-
elif ssh_final or nc_final:
|
537
|
+
elif ssh_final or nc_final or curl_final:
|
518
538
|
installed = []
|
519
539
|
missing = []
|
520
540
|
if ssh_final:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: outerbounds
|
3
|
-
Version: 0.8.
|
3
|
+
Version: 0.8.1
|
4
4
|
Summary: More Data Science, Less Administration
|
5
5
|
License: Proprietary
|
6
6
|
Keywords: data science,machine learning,MLOps
|
@@ -14,6 +14,7 @@ Classifier: Programming Language :: Python :: 3.8
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.9
|
15
15
|
Classifier: Programming Language :: Python :: 3.10
|
16
16
|
Classifier: Programming Language :: Python :: 3.11
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
17
18
|
Provides-Extra: azure
|
18
19
|
Provides-Extra: gcp
|
19
20
|
Provides-Extra: otel
|
@@ -28,9 +29,9 @@ Requires-Dist: google-cloud-secret-manager (>=2.20.0,<3.0.0) ; extra == "gcp"
|
|
28
29
|
Requires-Dist: google-cloud-storage (>=2.14.0,<3.0.0) ; extra == "gcp"
|
29
30
|
Requires-Dist: metaflow_checkpoint (==0.2.4)
|
30
31
|
Requires-Dist: ob-metaflow (==2.17.1.0)
|
31
|
-
Requires-Dist: ob-metaflow-extensions (==1.4.
|
32
|
-
Requires-Dist: ob-metaflow-stubs (==6.0.
|
33
|
-
Requires-Dist: ob-project-utils (==0.1.
|
32
|
+
Requires-Dist: ob-metaflow-extensions (==1.4.8)
|
33
|
+
Requires-Dist: ob-metaflow-stubs (==6.0.8.1)
|
34
|
+
Requires-Dist: ob-project-utils (==0.1.33)
|
34
35
|
Requires-Dist: opentelemetry-distro (>=0.41b0) ; extra == "otel"
|
35
36
|
Requires-Dist: opentelemetry-exporter-otlp-proto-http (>=1.20.0) ; extra == "otel"
|
36
37
|
Requires-Dist: opentelemetry-instrumentation-requests (>=0.41b0) ; extra == "otel"
|
@@ -51,16 +51,16 @@ outerbounds/command_groups/local_setup_cli.py,sha256=tuuqJRXQ_guEwOuQSIf9wkUU0yg
|
|
51
51
|
outerbounds/command_groups/perimeters_cli.py,sha256=iF_Uw7ROiSctf6FgoJEy30iDBLVE1j9FKuR3shgJRmc,19050
|
52
52
|
outerbounds/command_groups/secrets_cli.py,sha256=Vgn_aiTo76a0s5hCJhNWEOrCVhyYeivD08ooQxz0y7c,2952
|
53
53
|
outerbounds/command_groups/tutorials_cli.py,sha256=UInFyiMqtscHFfi8YQwiY_6Sdw9quJOtRu5OukEBccw,3522
|
54
|
-
outerbounds/command_groups/workstations_cli.py,sha256=-
|
54
|
+
outerbounds/command_groups/workstations_cli.py,sha256=-VFJqIvi_jcHcydaMLj8EaZ-Lbe-yBukkd9QCKrH5f0,27201
|
55
55
|
outerbounds/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
56
56
|
outerbounds/utils/kubeconfig.py,sha256=yvcyRXGR4AhQuqUDqmbGxEOHw5ixMFV0AZIDg1LI_Qo,7981
|
57
|
-
outerbounds/utils/kubectl_utils.py,sha256=
|
57
|
+
outerbounds/utils/kubectl_utils.py,sha256=YxiUVDfXTW7FDpCj639f9upkJNGPf2WuQTjUaBOzX5Q,1926
|
58
58
|
outerbounds/utils/metaflowconfig.py,sha256=l2vJbgPkLISU-XPGZFaC8ZKmYFyJemlD6bwB-EKUsAw,5770
|
59
59
|
outerbounds/utils/schema.py,sha256=lMUr9kNgn9wy-sO_t_Tlxmbt63yLeN4b0xQXbDUDj4A,2331
|
60
|
-
outerbounds/utils/ssh_utils.py,sha256=
|
60
|
+
outerbounds/utils/ssh_utils.py,sha256=MRJ7Oy0M7Lqqs397JDJczTYvxvyHJ_XvBdjt4ZYKaPE,19599
|
61
61
|
outerbounds/utils/utils.py,sha256=4Z8cszNob_8kDYCLNTrP-wWads_S_MdL3Uj3ju4mEsk,501
|
62
62
|
outerbounds/vendor.py,sha256=gRLRJNXtZBeUpPEog0LOeIsl6GosaFFbCxUvR4bW6IQ,5093
|
63
|
-
outerbounds-0.8.
|
64
|
-
outerbounds-0.8.
|
65
|
-
outerbounds-0.8.
|
66
|
-
outerbounds-0.8.
|
63
|
+
outerbounds-0.8.1.dist-info/METADATA,sha256=YgZHW3BBy6BZKgcUAZCmj07XgZEn9Y1HGt0uq0loHzw,1873
|
64
|
+
outerbounds-0.8.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
65
|
+
outerbounds-0.8.1.dist-info/entry_points.txt,sha256=AP6rZg7y5SK9e9a9iVq0Fi9Q2KPjPZSwtZ6R98rLw-8,56
|
66
|
+
outerbounds-0.8.1.dist-info/RECORD,,
|
File without changes
|