diff --git a/milatools/cli/commands.py b/milatools/cli/commands.py index c38b4e88..891d967d 100644 --- a/milatools/cli/commands.py +++ b/milatools/cli/commands.py @@ -31,28 +31,11 @@ import rich.logging from typing_extensions import TypedDict +from milatools.__version__ import __version__ from milatools.cli import console -from milatools.utils.local_v1 import LocalV1 -from milatools.utils.remote_v1 import RemoteV1, SlurmRemote -from milatools.utils.remote_v2 import RemoteV2 -from milatools.utils.vscode_utils import ( - get_code_command, - # install_local_vscode_extensions_on_remote, - sync_vscode_extensions, - sync_vscode_extensions_with_hostnames, -) - -from ..__version__ import __version__ -from .init_command import ( - print_welcome_message, - setup_keys_on_login_node, - setup_passwordless_ssh_access, - setup_ssh_config, - setup_vscode_settings, - setup_windows_ssh_config_from_wsl, -) -from .profile import ensure_program, setup_profile -from .utils import ( +from milatools.cli.init import init +from milatools.cli.profile import ensure_program, setup_profile +from milatools.cli.utils import ( CLUSTERS, Cluster, CommandNotFoundError, @@ -69,6 +52,14 @@ running_inside_WSL, with_control_file, ) +from milatools.utils.local_v1 import LocalV1 +from milatools.utils.remote_v1 import RemoteV1, SlurmRemote +from milatools.utils.remote_v2 import RemoteV2 +from milatools.utils.vscode_utils import ( + get_code_command, + sync_vscode_extensions, + sync_vscode_extensions_with_hostnames, +) if typing.TYPE_CHECKING: from typing_extensions import Unpack @@ -492,32 +483,6 @@ def intranet(search: Sequence[str]) -> None: webbrowser.open(url) -def init(): - """Set up your configuration and credentials.""" - - ############################# - # Step 1: SSH Configuration # - ############################# - - print("Checking ssh config") - - ssh_config = setup_ssh_config() - - # if we're running on WSL, we actually just copy the id_rsa + id_rsa.pub and the - # ~/.ssh/config to the Windows ssh directory (taking care to remove the - # ControlMaster-related entries) so that the user doesn't need to install Python on - # the Windows side. - if running_inside_WSL(): - setup_windows_ssh_config_from_wsl(linux_ssh_config=ssh_config) - - success = setup_passwordless_ssh_access(ssh_config=ssh_config) - if not success: - exit() - setup_keys_on_login_node() - setup_vscode_settings() - print_welcome_message() - - def forward( remote: str, page: str | None, diff --git a/milatools/cli/init_command.py b/milatools/cli/init.py similarity index 78% rename from milatools/cli/init_command.py rename to milatools/cli/init.py index c58ebcf5..8829a672 100644 --- a/milatools/cli/init_command.py +++ b/milatools/cli/init.py @@ -9,21 +9,24 @@ import sys import warnings from logging import getLogger as get_logger -from pathlib import Path +from pathlib import Path, PosixPath from typing import Any import questionary as qn from invoke.exceptions import UnexpectedExit - -from milatools.utils.remote_v2 import SSH_CONFIG_FILE - -from ..utils.local_v1 import LocalV1, check_passwordless, display -from ..utils.remote_v1 import RemoteV1 -from ..utils.vscode_utils import ( +from paramiko.config import SSHConfig as SSHConfigReader + +from milatools.cli import console +from milatools.cli.utils import SSHConfig as SSHConfigWriter +from milatools.cli.utils import T, running_inside_WSL, yn +from milatools.utils.local_v1 import display +from milatools.utils.local_v2 import LocalV2 +from milatools.utils.remote_v1 import RemoteV1 +from milatools.utils.remote_v2 import control_socket_is_running, get_controlpath_for +from milatools.utils.vscode_utils import ( get_expected_vscode_settings_json_path, vscode_installed, ) -from .utils import SSHConfig, T, running_inside_WSL, yn logger = get_logger(__name__) @@ -68,8 +71,8 @@ # NOTE: will not work with --gres prior to Slurm 22.05, because srun --overlap # cannot share gpus "ProxyCommand": ( - 'ssh mila "/cvmfs/config.mila.quebec/scripts/milatools/slurm-proxy.sh ' - 'mila-cpu --mem=8G"' + "ssh mila " + '"/cvmfs/config.mila.quebec/scripts/milatools/slurm-proxy.sh mila-cpu --mem=8G"' ), "RemoteCommand": ( "/cvmfs/config.mila.quebec/scripts/milatools/entrypoint.sh mila-cpu" @@ -112,9 +115,37 @@ } +def init(): + """Set up your configuration and credentials.""" + + ############################# + # Step 1: SSH Configuration # + ############################# + + print("Checking ssh config") + ssh_config_path = Path("~/.ssh/config").expanduser() + + setup_ssh_config(ssh_config_path=ssh_config_path) + + # if we're running on WSL, we actually just copy the id_rsa + id_rsa.pub and the + # ~/.ssh/config to the Windows ssh directory (taking care to remove the + # ControlMaster-related entries) so that the user doesn't need to install Python on + # the Windows side. + if running_inside_WSL(): + assert isinstance(ssh_config_path, PosixPath) # we're running in linux (WSL). + setup_windows_ssh_config_from_wsl(linux_ssh_config_path=ssh_config_path) + + success = setup_passwordless_ssh_access(ssh_config_path) + if not success: + exit() + setup_keys_on_login_node() + setup_vscode_settings() + print_welcome_message() + + def setup_ssh_config( ssh_config_path: str | Path = "~/.ssh/config", -) -> SSHConfig: +) -> SSHConfigReader: """Interactively sets up some useful entries in the ~/.ssh/config file on the local machine. @@ -134,14 +165,18 @@ def setup_ssh_config( """ ssh_config_path = _setup_ssh_config_file(ssh_config_path) - ssh_config = SSHConfig(ssh_config_path) + + ssh_config = SSHConfigReader.from_path(str(ssh_config_path)) + ssh_config_writer = SSHConfigWriter(ssh_config_path) + mila_username: str = _get_mila_username(ssh_config) drac_username: str | None = _get_drac_username(ssh_config) - orig_config = ssh_config.cfg.config() + + orig_config = ssh_config_writer.cfg.config() for hostname, entry in MILA_ENTRIES.copy().items(): entry.update(User=mila_username) - _add_ssh_entry(ssh_config, hostname, entry) + _add_ssh_entry(ssh_config_writer, hostname, entry) _make_controlpath_dir(entry) if drac_username: @@ -150,31 +185,31 @@ def setup_ssh_config( ) for hostname, entry in DRAC_ENTRIES.copy().items(): entry.update(User=drac_username) - _add_ssh_entry(ssh_config, hostname, entry) + _add_ssh_entry(ssh_config_writer, hostname, entry) _make_controlpath_dir(entry) # Check for *.server.mila.quebec in ssh config, to connect to compute nodes old_cnode_pattern = "*.server.mila.quebec" - if old_cnode_pattern in ssh_config.hosts(): + if old_cnode_pattern in ssh_config_writer.hosts(): logger.info( f"The '{old_cnode_pattern}' entry in ~/.ssh/config is too general and " "should exclude login.server.mila.quebec. Fixing this." ) - ssh_config.remove(old_cnode_pattern) + ssh_config_writer.remove(old_cnode_pattern) - new_config = ssh_config.cfg.config() + new_config = ssh_config_writer.cfg.config() if orig_config == new_config: print("Did not change ssh config") - elif not _confirm_changes(ssh_config, previous=orig_config): + elif not _confirm_changes(ssh_config_writer, previous=orig_config): exit("Did not change ssh config") else: - ssh_config.save() + ssh_config_writer.save() print(f"Wrote {ssh_config_path}") return ssh_config -def setup_windows_ssh_config_from_wsl(linux_ssh_config: SSHConfig): +def setup_windows_ssh_config_from_wsl(linux_ssh_config_path: PosixPath): """Setup the Windows SSH configuration and public key from within WSL. This copies over the entries from the linux ssh configuration file, except for the @@ -186,6 +221,8 @@ def setup_windows_ssh_config_from_wsl(linux_ssh_config: SSHConfig): This makes it so the user doesn't need to install Python/Anaconda on the Windows side in order to use `mila code` from within WSL. """ + linux_ssh_config = SSHConfigWriter(linux_ssh_config_path) + assert running_inside_WSL() # NOTE: This also assumes that a public/private key pair has already been generated # at ~/.ssh/id_rsa.pub and ~/.ssh/id_rsa. @@ -193,7 +230,7 @@ def setup_windows_ssh_config_from_wsl(linux_ssh_config: SSHConfig): windows_ssh_config_path = windows_home / ".ssh/config" windows_ssh_config_path = _setup_ssh_config_file(windows_ssh_config_path) - windows_ssh_config = SSHConfig(windows_ssh_config_path) + windows_ssh_config = SSHConfigWriter(windows_ssh_config_path) initial_windows_config_contents = windows_ssh_config.cfg.config() _copy_valid_ssh_entries_to_windows_ssh_config_file( @@ -228,7 +265,7 @@ def setup_windows_ssh_config_from_wsl(linux_ssh_config: SSHConfig): _copy_if_needed(linux_key_file, windows_key_file) -def setup_passwordless_ssh_access(ssh_config: SSHConfig) -> bool: +def setup_passwordless_ssh_access(ssh_config_path: Path) -> bool: """Sets up passwordless ssh access to the Mila and optionally also to DRAC. Sets up ssh connection to the DRAC clusters if they are present in the SSH config @@ -236,37 +273,26 @@ def setup_passwordless_ssh_access(ssh_config: SSHConfig) -> bool: Returns whether the operation completed successfully or not. """ - print("Checking passwordless authentication") + print("Setting up passwordless SSH access.") - here = LocalV1() - sshdir = Path.home() / ".ssh" + ssh_config = SSHConfigReader.from_path(str(ssh_config_path)) - # Check if there is a public key file in ~/.ssh - if not list(sshdir.glob("id*.pub")): - if yn("You have no public keys. Generate one?"): - # Run ssh-keygen with the given location and no passphrase. - ssh_private_key_path = Path.home() / ".ssh" / "id_rsa" - create_ssh_keypair(ssh_private_key_path, here) - else: - print("No public keys.") - return False + # TODO: Generate SSH keys with ssh-keygen (not setting the passphrase so users can choose to use a passphrase or not). + setup_passwordless_ssh_access_to_cluster("mila", ssh_config_path) - # TODO: This uses the public key set in the SSH config file, which may (or may not) - # be the random id*.pub file that was just checked for above. - success = setup_passwordless_ssh_access_to_cluster("mila") - if not success: - return False - setup_keys_on_login_node("mila") + hosts_in_ssh_config = [ + hostname + for hostname in ssh_config.get_hostnames() + if not any(c in hostname for c in "!*?") + ] - drac_clusters_in_ssh_config: list[str] = [] - hosts_in_config = ssh_config.hosts() - for cluster in DRAC_CLUSTERS: - if any(cluster in hostname for hostname in hosts_in_config): - drac_clusters_in_ssh_config.append(cluster) + drac_clusters_in_ssh_config: list[str] = list( + set(DRAC_CLUSTERS).intersection(hosts_in_ssh_config) + ) if not drac_clusters_in_ssh_config: logger.debug( - f"There are no DRAC clusters in the SSH config at {ssh_config.path}." + f"There are no DRAC clusters in the SSH config at {ssh_config_path}." ) return True @@ -279,14 +305,32 @@ def setup_passwordless_ssh_access(ssh_config: SSHConfig) -> bool: "See https://docs.alliancecan.ca/wiki/SSH_Keys#Using_CCDB for more info." ) for drac_cluster in drac_clusters_in_ssh_config: - success = setup_passwordless_ssh_access_to_cluster(drac_cluster) + success = setup_passwordless_ssh_access_to_cluster( + drac_cluster, ssh_config_path + ) if not success: return False setup_keys_on_login_node(drac_cluster) return True -def setup_passwordless_ssh_access_to_cluster(cluster: str) -> bool: +def _get_private_key_path_for_hostname( + hostname: str, ssh_config_path: Path +) -> Path | None: + config = SSHConfigReader.from_path(str(ssh_config_path)) + identity_file = config.lookup(hostname).get("identityfile") + if not identity_file: + return None + # Seems to be a list for some reason? + if isinstance(identity_file, list): + assert identity_file + identity_file = identity_file[0] + return Path(identity_file).expanduser() + + +def setup_passwordless_ssh_access_to_cluster( + cluster: str, ssh_config_path: Path +) -> bool: """Sets up passwordless SSH access to the given hostname. On Mac/Linux, uses `ssh-copy-id`. Performs the steps of ssh-copy-id manually on @@ -294,21 +338,31 @@ def setup_passwordless_ssh_access_to_cluster(cluster: str) -> bool: Returns whether the operation completed successfully or not. """ - here = LocalV1() + here = LocalV2() # Check that it is possible to connect without using a password. print(f"Checking if passwordless SSH access is setup for the {cluster} cluster.") - # TODO: Potentially use a custom key like `~/.ssh/id_milatools.pub` instead of - # the default. + ssh_private_key_path = _get_private_key_path_for_hostname(cluster, ssh_config_path) + # TODO: Simplify the code here by assuming that users just accepted the changes to + # their SSH config proposed by the first part of `mila init`. + # - Instead of making the code complicated with lots of corner cases, just raise an + # error if the SSH config doesn't match what we expect to see after `mila init`. + if ssh_private_key_path is None: + # TODO: What to do if there isn't a private key set in the SSH config, but there + # is already a private key in the SSH dir? (it would be used by ssh). + console.log( + f"There is no private key set to be used for the {cluster} cluster." + ) + ssh_private_key_path = Path("~/.ssh/id_rsa").expanduser() + + if not ssh_private_key_path.exists(): + console.log( + f"The ssh key to use for host {cluster} does not exist at {ssh_private_key_path}. Creating it now." + ) + create_ssh_keypair(ssh_private_key_path) + config_writer = SSHConfigWriter(ssh_config_path) - from paramiko.config import SSHConfig + config_writer.set(cluster, IdentityFile=str(ssh_private_key_path)) - config = SSHConfig.from_path(str(SSH_CONFIG_FILE)) - identity_file = config.lookup(cluster).get("identityfile", "~/.ssh/id_rsa") - # Seems to be a list for some reason? - if isinstance(identity_file, list): - assert identity_file - identity_file = identity_file[0] - ssh_private_key_path = Path(identity_file).expanduser() ssh_public_key_path = ssh_private_key_path.with_suffix(".pub") assert ssh_public_key_path.exists() @@ -345,17 +399,21 @@ def setup_passwordless_ssh_access_to_cluster(cluster: str) -> bool: subprocess.run(command, check=True, text=False, stdin=f) else: here.run( - "ssh-copy-id", - "-i", - str(ssh_private_key_path), - "-o", - "StrictHostKeyChecking=no", - cluster, - check=True, + ( + "ssh-copy-id", + "-i", + str(ssh_private_key_path), + "-o", + "StrictHostKeyChecking=no", + cluster, + ), ) # double-check that this worked. - if not check_passwordless(cluster): + if not control_socket_is_running( + cluster, + control_path=get_controlpath_for(cluster, ssh_config_path=ssh_config_path), + ): print(f"'ssh-copy-id {cluster}' appears to have failed!") return False return True @@ -443,7 +501,7 @@ def get_windows_home_path_in_wsl() -> Path: def create_ssh_keypair( ssh_private_key_path: Path, - local: LocalV1 | None = None, + local: LocalV2 | None = None, passphrase: str | None = "", ) -> None: """Creates a public/private key pair at the given path using ssh-keygen. @@ -452,18 +510,17 @@ def create_ssh_keypair( Otherwise, if passphrase is an empty string, no passphrase will be used (default). If a string is passed, it is passed to ssh-keygen and used as the passphrase. """ - local = local or LocalV1() - command = [ + local = local or LocalV2() + command = ( "ssh-keygen", "-f", str(ssh_private_key_path.expanduser()), "-t", - "rsa", - ] + "rsa", # note: Could also let the user choose the type of encryption.. + ) if passphrase is not None: - command.extend(["-N", passphrase]) - display(command) - subprocess.run(command, check=True) + command += ("-N", passphrase) + local.run(command, display=True) def has_passphrase(ssh_private_key_path: Path) -> bool: @@ -613,30 +670,18 @@ def ask_to_confirm_changes(before: str, after: str, path: str | Path) -> bool: return yn("\nIs this OK?") -def _confirm_changes(ssh_config: SSHConfig, previous: str) -> bool: +def _confirm_changes(ssh_config: SSHConfigWriter, previous: str) -> bool: before = previous + "\n" after = ssh_config.cfg.config() + "\n" return ask_to_confirm_changes(before, after, ssh_config.path) -def _get_mila_username(ssh_config: SSHConfig) -> str: +def _get_mila_username(ssh_config: SSHConfigReader) -> str: # Check for a mila entry in ssh config # NOTE: This also supports the case where there's a 'HOST mila some_alias_for_mila' # entry. # NOTE: ssh_config.host(entry) returns an empty dictionary if there is no entry. - username: str | None = None - hosts_with_mila_in_name_and_a_user_entry = [ - host - for host in ssh_config.hosts() - if "mila" in host.split() and "user" in ssh_config.host(host) - ] - # Note: If there are none, or more than one, then we'll ask the user for their - # username, just to be sure. - if len(hosts_with_mila_in_name_and_a_user_entry) == 1: - username = ssh_config.host(hosts_with_mila_in_name_and_a_user_entry[0]).get( - "user" - ) - + username: str | None = ssh_config.lookup("mila").get("user") while not username: username = qn.text( "What's your username on the mila cluster?\n", @@ -645,36 +690,32 @@ def _get_mila_username(ssh_config: SSHConfig) -> str: return username.strip() -def _get_drac_username(ssh_config: SSHConfig) -> str | None: +def _get_drac_username(ssh_config: SSHConfigReader) -> str | None: """Retrieve or ask the user for their username on the ComputeCanada/DRAC clusters.""" # Check for one of the DRAC entries in ssh config - username: str | None = None - hosts_with_cluster_in_name_and_a_user_entry = [ - host - for host in ssh_config.hosts() - if any( - cc_cluster in host.split() or f"!{cc_cluster}" in host.split() - for cc_cluster in DRAC_CLUSTERS - ) - and "user" in ssh_config.host(host) - ] - users_from_drac_config_entries = set( - ssh_config.host(host)["user"] - for host in hosts_with_cluster_in_name_and_a_user_entry + users_from_drac_config_entries: set[str] = set( + drac_cluster_username + for drac_cluster in DRAC_CLUSTERS + if (drac_cluster_username := ssh_config.lookup(drac_cluster).get("user")) + is not None ) + if len(users_from_drac_config_entries) == 1: + return users_from_drac_config_entries.pop().strip() + + username: str | None = None # Note: If there are none, or more than one, then we'll ask the user for their # username, just to be sure. - if len(users_from_drac_config_entries) == 1: - username = users_from_drac_config_entries.pop() - elif yn("Do you also have an account on the ComputeCanada/DRAC clusters?"): - while not username: - username = qn.text( + if yn("Do you also have an account on the ComputeCanada/DRAC clusters?"): + while not ( + username := qn.text( "What's your username on the CC/DRAC clusters?\n", validate=functools.partial( _is_valid_username, cluster_name="ComputeCanada/DRAC clusters" ), ).unsafe_ask() + ): + pass return username.strip() if username else None @@ -693,7 +734,7 @@ def _is_valid_username(text: str, cluster_name: str = "mila cluster") -> bool | def _add_ssh_entry( - ssh_config: SSHConfig, + ssh_config: SSHConfigWriter, host: str, entry: dict[str, str | int], *, @@ -728,7 +769,7 @@ def _add_ssh_entry( def _copy_valid_ssh_entries_to_windows_ssh_config_file( - linux_ssh_config: SSHConfig, windows_ssh_config: SSHConfig + linux_ssh_config: SSHConfigWriter, windows_ssh_config: SSHConfigWriter ): unsupported_keys_lowercase = set(k.lower() for k in WINDOWS_UNSUPPORTED_KEYS) diff --git a/milatools/utils/local_v1.py b/milatools/utils/local_v1.py index 6f5520bc..8f465059 100644 --- a/milatools/utils/local_v1.py +++ b/milatools/utils/local_v1.py @@ -1,19 +1,14 @@ from __future__ import annotations import shlex -import socket import subprocess -import sys from logging import getLogger as get_logger from subprocess import CompletedProcess from typing import IO, Any -import fabric -import paramiko.ssh_exception from typing_extensions import deprecated -from milatools.cli.utils import CommandNotFoundError, T, cluster_to_connect_kwargs -from milatools.utils.remote_v2 import SSH_CONFIG_FILE, is_already_logged_in +from milatools.cli.utils import CommandNotFoundError, T logger = get_logger(__name__) @@ -69,9 +64,6 @@ def popen( cmd, stdout=stdout, stderr=stderr, universal_newlines=True ) - def check_passwordless(self, host: str): - return check_passwordless(host) - def display(split_command: list[str] | tuple[str, ...] | str) -> None: if isinstance(split_command, str): @@ -79,44 +71,3 @@ def display(split_command: list[str] | tuple[str, ...] | str) -> None: else: command = shlex.join(split_command) print(T.bold_green("(local) $ ", command)) - - -def check_passwordless(host: str) -> bool: - if ( - sys.platform != "win32" - and SSH_CONFIG_FILE.exists() - and is_already_logged_in(host, ssh_config_path=SSH_CONFIG_FILE) - ): - return True - - try: - connect_kwargs_for_host = {"allow_agent": False} - if host in cluster_to_connect_kwargs: - connect_kwargs_for_host.update(cluster_to_connect_kwargs[host]) - with fabric.Connection( - host, - connect_kwargs=connect_kwargs_for_host, - ) as connection: - results: fabric.runners.Result = connection.run( - "echo OK", - in_stream=False, - echo=True, - echo_format=T.bold_cyan(f"({host})" + " $ {command}"), - ) - - except ( - paramiko.ssh_exception.SSHException, - paramiko.ssh_exception.NoValidConnectionsError, - socket.gaierror, - # BUG: Also getting ValueError("q must be exactlu 160, 224, or 256 bits long") - # with older versions of paramiko. - # ValueError, - ) as err: - logger.debug(f"Unable to connect to {host} without a password: {err}") - return False - - if "OK" in results.stdout: - return True - logger.error("Unexpected output from SSH command, output didn't contain 'OK'!") - logger.error(f"stdout: {results.stdout}, stderr: {results.stderr}") - return False diff --git a/tests/cli/test_init_command.py b/tests/cli/test_init.py similarity index 97% rename from tests/cli/test_init_command.py rename to tests/cli/test_init.py index 2825c3cf..2cf3e112 100644 --- a/tests/cli/test_init_command.py +++ b/tests/cli/test_init.py @@ -11,7 +11,7 @@ import textwrap from functools import partial from logging import getLogger as get_logger -from pathlib import Path, PurePosixPath +from pathlib import Path, PosixPath, PurePosixPath from unittest.mock import Mock import invoke @@ -22,8 +22,8 @@ from prompt_toolkit.input import PipeInput, create_pipe_input from pytest_regressions.file_regression import FileRegressionFixture -from milatools.cli import init_command -from milatools.cli.init_command import ( +from milatools.cli import init +from milatools.cli.init import ( DRAC_CLUSTERS, _get_drac_username, _get_mila_username, @@ -42,7 +42,7 @@ SSHConfig, running_inside_WSL, ) -from milatools.utils.local_v1 import LocalV1, check_passwordless +from milatools.utils.local_v1 import LocalV1 from milatools.utils.remote_v1 import RemoteV1 from milatools.utils.remote_v2 import ( SSH_CACHE_DIR, @@ -542,8 +542,8 @@ def test_with_existing_entries( User Bob """ ), - ["bob\r"], - "bob", + [], # user input doesn't matter (won't get asked). + "george", id="two_matching_entries", ), pytest.param( @@ -579,7 +579,7 @@ def test_get_username( ssh_config_path = tmp_path / "config" with open(ssh_config_path, "w") as f: f.write(contents) - ssh_config = SSHConfig(ssh_config_path) + ssh_config = paramiko.SSHConfig.from_path(str(ssh_config_path)) if not prompt_inputs: input_pipe.close() for prompt_input in prompt_inputs: @@ -639,8 +639,8 @@ def test_get_username( User Bob """ ), - ["y", "bob\r"], - "bob", + [], # will not get asked for input. + "george", id="two_matching_entries", ), pytest.param( @@ -675,7 +675,7 @@ def test_get_drac_username( ssh_config_path = tmp_path / "config" with open(ssh_config_path, "w") as f: f.write(contents) - ssh_config = SSHConfig(ssh_config_path) + ssh_config = paramiko.SSHConfig.from_path(str(ssh_config_path)) if not prompt_inputs: input_pipe.close() for prompt_input in prompt_inputs: @@ -845,12 +845,12 @@ def test_setup_windows_ssh_config_from_wsl( windows_ssh_config_path = windows_home / ".ssh" / "config" monkeypatch.setattr( - init_command, + init, running_inside_WSL.__name__, Mock(spec=running_inside_WSL, return_value=True), ) monkeypatch.setattr( - init_command, + init, get_windows_home_path_in_wsl.__name__, Mock(spec=get_windows_home_path_in_wsl, return_value=windows_home), ) @@ -863,7 +863,9 @@ def test_setup_windows_ssh_config_from_wsl( for prompt in user_inputs: input_pipe.send_text(prompt) - setup_windows_ssh_config_from_wsl(linux_ssh_config=linux_ssh_config) + setup_windows_ssh_config_from_wsl( + linux_ssh_config_path=PosixPath(linux_ssh_config.path) + ) assert windows_ssh_config_path.exists() assert windows_ssh_config_path.stat().st_mode & 0o777 == 0o600 @@ -921,15 +923,15 @@ def test_setup_vscode_settings( json.dump(initial_settings, f, indent=4) monkeypatch.setattr( - init_command, - init_command.vscode_installed.__name__, - Mock(spec=init_command.vscode_installed, return_value=True), + init, + init.vscode_installed.__name__, + Mock(spec=init.vscode_installed, return_value=True), ) monkeypatch.setattr( - init_command, - init_command.get_expected_vscode_settings_json_path.__name__, + init, + init.get_expected_vscode_settings_json_path.__name__, Mock( - spec=init_command.get_expected_vscode_settings_json_path, + spec=init.get_expected_vscode_settings_json_path, return_value=vscode_settings_json_path, ), ) @@ -1005,12 +1007,12 @@ def test_setup_windows_ssh_config_from_wsl_copies_keys( monkeypatch.setattr(Path, "home", Mock(spec=Path.home, return_value=linux_home)) monkeypatch.setattr( - init_command, + init, running_inside_WSL.__name__, Mock(spec=running_inside_WSL, return_value=True), ) monkeypatch.setattr( - init_command, + init, get_windows_home_path_in_wsl.__name__, Mock(spec=get_windows_home_path_in_wsl, return_value=windows_home), ) @@ -1029,7 +1031,9 @@ def test_setup_windows_ssh_config_from_wsl_copies_keys( input_pipe.send_text("y") # accept creating the Windows config file input_pipe.send_text("y") # accept the changes - setup_windows_ssh_config_from_wsl(linux_ssh_config=linux_ssh_config) + setup_windows_ssh_config_from_wsl( + linux_ssh_config_path=PosixPath(linux_ssh_config.path) + ) windows_private_key_path = windows_home / ".ssh" / "id_rsa" windows_public_key_path = windows_private_key_path.with_suffix(".pub") @@ -1283,8 +1287,6 @@ def test_setup_passwordless_ssh_access_to_cluster( assert ssh_public_key_path.exists() def have_passwordless_ssh_access_to(cluster: str) -> bool: - if sys.platform == "win32": - return check_passwordless(cluster) return is_already_logged_in(cluster, ssh_config_path=SSH_CONFIG_FILE) def _exists(file: PurePosixPath | Path): @@ -1340,7 +1342,7 @@ def temporarily_disable_ssh_access_to_cluster(): # subprocess.check_call( # ["ssh", "-O", "exit", f"-oControlPath={control_path}", cluster] # ) - assert not check_passwordless(cluster) + assert not is_already_logged_in(cluster) else: assert passwordless_ssh_was_previously_setup if _exists(authorized_keys_file): @@ -1356,7 +1358,7 @@ def temporarily_disable_ssh_access_to_cluster(): hide=False, ) # todo: might not work well for the DRAC clusters! - assert not check_passwordless(cluster) + assert not is_already_logged_in(cluster) def reenable_ssh_access_to_cluster(): if cluster == "localhost": @@ -1376,7 +1378,7 @@ def reenable_ssh_access_to_cluster(): ssh_dir.mkdir(exist_ok=True, mode=0o700) assert not passwordless_ssh_was_previously_setup shutil.copy(backup_authorized_keys_file, authorized_keys_file) - assert check_passwordless(cluster) + assert is_already_logged_in(cluster) else: logger.info( f"Restoring the original {authorized_keys_file} from backup at " @@ -1570,16 +1572,16 @@ def test_setup_passwordless_ssh_access( spec=setup_passwordless_ssh_access_to_cluster, side_effect=[accept_mila, *(accept_drac for _ in drac_clusters_in_ssh_config)], ) - import milatools.cli.init_command + import milatools.cli.init monkeypatch.setattr( - milatools.cli.init_command, + milatools.cli.init, setup_passwordless_ssh_access_to_cluster.__name__, mock_setup_passwordless_ssh_access_to_cluster, ) monkeypatch.setattr( - milatools.cli.init_command, + milatools.cli.init, setup_keys_on_login_node.__name__, Mock(spec=setup_keys_on_login_node), ) diff --git a/tests/cli/test_init_command/test_fixes_overly_general_entry.txt b/tests/cli/test_init/test_fixes_overly_general_entry.txt similarity index 100% rename from tests/cli/test_init_command/test_fixes_overly_general_entry.txt rename to tests/cli/test_init/test_fixes_overly_general_entry.txt diff --git a/tests/cli/test_init_command/test_setup_passwordless_ssh_access_to_cluster_localhost_accept_registering_key_already_setup_.md b/tests/cli/test_init/test_setup_passwordless_ssh_access_to_cluster_localhost_accept_registering_key_already_setup_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_passwordless_ssh_access_to_cluster_localhost_accept_registering_key_already_setup_.md rename to tests/cli/test_init/test_setup_passwordless_ssh_access_to_cluster_localhost_accept_registering_key_already_setup_.md diff --git a/tests/cli/test_init_command/test_setup_passwordless_ssh_access_to_cluster_localhost_accept_registering_key_not_already_setup_.md b/tests/cli/test_init/test_setup_passwordless_ssh_access_to_cluster_localhost_accept_registering_key_not_already_setup_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_passwordless_ssh_access_to_cluster_localhost_accept_registering_key_not_already_setup_.md rename to tests/cli/test_init/test_setup_passwordless_ssh_access_to_cluster_localhost_accept_registering_key_not_already_setup_.md diff --git a/tests/cli/test_init_command/test_setup_passwordless_ssh_access_to_cluster_localhost_reject_registering_key_already_setup_.md b/tests/cli/test_init/test_setup_passwordless_ssh_access_to_cluster_localhost_reject_registering_key_already_setup_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_passwordless_ssh_access_to_cluster_localhost_reject_registering_key_already_setup_.md rename to tests/cli/test_init/test_setup_passwordless_ssh_access_to_cluster_localhost_reject_registering_key_already_setup_.md diff --git a/tests/cli/test_init_command/test_setup_passwordless_ssh_access_to_cluster_localhost_reject_registering_key_not_already_setup_.md b/tests/cli/test_init/test_setup_passwordless_ssh_access_to_cluster_localhost_reject_registering_key_not_already_setup_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_passwordless_ssh_access_to_cluster_localhost_reject_registering_key_not_already_setup_.md rename to tests/cli/test_init/test_setup_passwordless_ssh_access_to_cluster_localhost_reject_registering_key_not_already_setup_.md diff --git a/tests/cli/test_init_command/test_setup_ssh_empty_confirm_changes_drac_.md b/tests/cli/test_init/test_setup_ssh_empty_confirm_changes_drac_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_ssh_empty_confirm_changes_drac_.md rename to tests/cli/test_init/test_setup_ssh_empty_confirm_changes_drac_.md diff --git a/tests/cli/test_init_command/test_setup_ssh_empty_confirm_changes_no_drac_.md b/tests/cli/test_init/test_setup_ssh_empty_confirm_changes_no_drac_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_ssh_empty_confirm_changes_no_drac_.md rename to tests/cli/test_init/test_setup_ssh_empty_confirm_changes_no_drac_.md diff --git a/tests/cli/test_init_command/test_setup_ssh_empty_reject_changes_drac_.md b/tests/cli/test_init/test_setup_ssh_empty_reject_changes_drac_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_ssh_empty_reject_changes_drac_.md rename to tests/cli/test_init/test_setup_ssh_empty_reject_changes_drac_.md diff --git a/tests/cli/test_init_command/test_setup_ssh_empty_reject_changes_no_drac_.md b/tests/cli/test_init/test_setup_ssh_empty_reject_changes_no_drac_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_ssh_empty_reject_changes_no_drac_.md rename to tests/cli/test_init/test_setup_ssh_empty_reject_changes_no_drac_.md diff --git a/tests/cli/test_init_command/test_setup_ssh_has_comment_and_entry_confirm_changes_drac_.md b/tests/cli/test_init/test_setup_ssh_has_comment_and_entry_confirm_changes_drac_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_ssh_has_comment_and_entry_confirm_changes_drac_.md rename to tests/cli/test_init/test_setup_ssh_has_comment_and_entry_confirm_changes_drac_.md diff --git a/tests/cli/test_init_command/test_setup_ssh_has_comment_and_entry_confirm_changes_no_drac_.md b/tests/cli/test_init/test_setup_ssh_has_comment_and_entry_confirm_changes_no_drac_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_ssh_has_comment_and_entry_confirm_changes_no_drac_.md rename to tests/cli/test_init/test_setup_ssh_has_comment_and_entry_confirm_changes_no_drac_.md diff --git a/tests/cli/test_init_command/test_setup_ssh_has_comment_and_entry_reject_changes_drac_.md b/tests/cli/test_init/test_setup_ssh_has_comment_and_entry_reject_changes_drac_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_ssh_has_comment_and_entry_reject_changes_drac_.md rename to tests/cli/test_init/test_setup_ssh_has_comment_and_entry_reject_changes_drac_.md diff --git a/tests/cli/test_init_command/test_setup_ssh_has_comment_and_entry_reject_changes_no_drac_.md b/tests/cli/test_init/test_setup_ssh_has_comment_and_entry_reject_changes_no_drac_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_ssh_has_comment_and_entry_reject_changes_no_drac_.md rename to tests/cli/test_init/test_setup_ssh_has_comment_and_entry_reject_changes_no_drac_.md diff --git a/tests/cli/test_init_command/test_setup_ssh_has_comment_and_entry_with_extra_space_confirm_changes_drac_.md b/tests/cli/test_init/test_setup_ssh_has_comment_and_entry_with_extra_space_confirm_changes_drac_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_ssh_has_comment_and_entry_with_extra_space_confirm_changes_drac_.md rename to tests/cli/test_init/test_setup_ssh_has_comment_and_entry_with_extra_space_confirm_changes_drac_.md diff --git a/tests/cli/test_init_command/test_setup_ssh_has_comment_and_entry_with_extra_space_confirm_changes_no_drac_.md b/tests/cli/test_init/test_setup_ssh_has_comment_and_entry_with_extra_space_confirm_changes_no_drac_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_ssh_has_comment_and_entry_with_extra_space_confirm_changes_no_drac_.md rename to tests/cli/test_init/test_setup_ssh_has_comment_and_entry_with_extra_space_confirm_changes_no_drac_.md diff --git a/tests/cli/test_init_command/test_setup_ssh_has_comment_and_entry_with_extra_space_reject_changes_drac_.md b/tests/cli/test_init/test_setup_ssh_has_comment_and_entry_with_extra_space_reject_changes_drac_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_ssh_has_comment_and_entry_with_extra_space_reject_changes_drac_.md rename to tests/cli/test_init/test_setup_ssh_has_comment_and_entry_with_extra_space_reject_changes_drac_.md diff --git a/tests/cli/test_init_command/test_setup_ssh_has_comment_and_entry_with_extra_space_reject_changes_no_drac_.md b/tests/cli/test_init/test_setup_ssh_has_comment_and_entry_with_extra_space_reject_changes_no_drac_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_ssh_has_comment_and_entry_with_extra_space_reject_changes_no_drac_.md rename to tests/cli/test_init/test_setup_ssh_has_comment_and_entry_with_extra_space_reject_changes_no_drac_.md diff --git a/tests/cli/test_init_command/test_setup_ssh_has_comment_confirm_changes_drac_.md b/tests/cli/test_init/test_setup_ssh_has_comment_confirm_changes_drac_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_ssh_has_comment_confirm_changes_drac_.md rename to tests/cli/test_init/test_setup_ssh_has_comment_confirm_changes_drac_.md diff --git a/tests/cli/test_init_command/test_setup_ssh_has_comment_confirm_changes_no_drac_.md b/tests/cli/test_init/test_setup_ssh_has_comment_confirm_changes_no_drac_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_ssh_has_comment_confirm_changes_no_drac_.md rename to tests/cli/test_init/test_setup_ssh_has_comment_confirm_changes_no_drac_.md diff --git a/tests/cli/test_init_command/test_setup_ssh_has_comment_reject_changes_drac_.md b/tests/cli/test_init/test_setup_ssh_has_comment_reject_changes_drac_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_ssh_has_comment_reject_changes_drac_.md rename to tests/cli/test_init/test_setup_ssh_has_comment_reject_changes_drac_.md diff --git a/tests/cli/test_init_command/test_setup_ssh_has_comment_reject_changes_no_drac_.md b/tests/cli/test_init/test_setup_ssh_has_comment_reject_changes_no_drac_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_ssh_has_comment_reject_changes_no_drac_.md rename to tests/cli/test_init/test_setup_ssh_has_comment_reject_changes_no_drac_.md diff --git a/tests/cli/test_init_command/test_setup_ssh_has_different_indent_confirm_changes_drac_.md b/tests/cli/test_init/test_setup_ssh_has_different_indent_confirm_changes_drac_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_ssh_has_different_indent_confirm_changes_drac_.md rename to tests/cli/test_init/test_setup_ssh_has_different_indent_confirm_changes_drac_.md diff --git a/tests/cli/test_init_command/test_setup_ssh_has_different_indent_confirm_changes_no_drac_.md b/tests/cli/test_init/test_setup_ssh_has_different_indent_confirm_changes_no_drac_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_ssh_has_different_indent_confirm_changes_no_drac_.md rename to tests/cli/test_init/test_setup_ssh_has_different_indent_confirm_changes_no_drac_.md diff --git a/tests/cli/test_init_command/test_setup_ssh_has_different_indent_reject_changes_drac_.md b/tests/cli/test_init/test_setup_ssh_has_different_indent_reject_changes_drac_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_ssh_has_different_indent_reject_changes_drac_.md rename to tests/cli/test_init/test_setup_ssh_has_different_indent_reject_changes_drac_.md diff --git a/tests/cli/test_init_command/test_setup_ssh_has_different_indent_reject_changes_no_drac_.md b/tests/cli/test_init/test_setup_ssh_has_different_indent_reject_changes_no_drac_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_ssh_has_different_indent_reject_changes_no_drac_.md rename to tests/cli/test_init/test_setup_ssh_has_different_indent_reject_changes_no_drac_.md diff --git a/tests/cli/test_init_command/test_setup_vscode_settings_accept_None_.md b/tests/cli/test_init/test_setup_vscode_settings_accept_None_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_vscode_settings_accept_None_.md rename to tests/cli/test_init/test_setup_vscode_settings_accept_None_.md diff --git a/tests/cli/test_init_command/test_setup_vscode_settings_accept_initial_settings1_.md b/tests/cli/test_init/test_setup_vscode_settings_accept_initial_settings1_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_vscode_settings_accept_initial_settings1_.md rename to tests/cli/test_init/test_setup_vscode_settings_accept_initial_settings1_.md diff --git a/tests/cli/test_init_command/test_setup_vscode_settings_accept_initial_settings2_.md b/tests/cli/test_init/test_setup_vscode_settings_accept_initial_settings2_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_vscode_settings_accept_initial_settings2_.md rename to tests/cli/test_init/test_setup_vscode_settings_accept_initial_settings2_.md diff --git a/tests/cli/test_init_command/test_setup_vscode_settings_accept_initial_settings3_.md b/tests/cli/test_init/test_setup_vscode_settings_accept_initial_settings3_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_vscode_settings_accept_initial_settings3_.md rename to tests/cli/test_init/test_setup_vscode_settings_accept_initial_settings3_.md diff --git a/tests/cli/test_init_command/test_setup_vscode_settings_accept_initial_settings4_.md b/tests/cli/test_init/test_setup_vscode_settings_accept_initial_settings4_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_vscode_settings_accept_initial_settings4_.md rename to tests/cli/test_init/test_setup_vscode_settings_accept_initial_settings4_.md diff --git a/tests/cli/test_init_command/test_setup_windows_ssh_config_from_wsl_accept_.md b/tests/cli/test_init/test_setup_windows_ssh_config_from_wsl_accept_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_windows_ssh_config_from_wsl_accept_.md rename to tests/cli/test_init/test_setup_windows_ssh_config_from_wsl_accept_.md diff --git a/tests/cli/test_init_command/test_setup_windows_ssh_config_from_wsl_reject_.md b/tests/cli/test_init/test_setup_windows_ssh_config_from_wsl_reject_.md similarity index 100% rename from tests/cli/test_init_command/test_setup_windows_ssh_config_from_wsl_reject_.md rename to tests/cli/test_init/test_setup_windows_ssh_config_from_wsl_reject_.md diff --git a/tests/cli/test_init_command/test_with_existing_entries_has_mila_compute_entry_has_mila_cpu_entry_has_mila_entry_has_drac_entries_.md b/tests/cli/test_init/test_with_existing_entries_has_mila_compute_entry_has_mila_cpu_entry_has_mila_entry_has_drac_entries_.md similarity index 100% rename from tests/cli/test_init_command/test_with_existing_entries_has_mila_compute_entry_has_mila_cpu_entry_has_mila_entry_has_drac_entries_.md rename to tests/cli/test_init/test_with_existing_entries_has_mila_compute_entry_has_mila_cpu_entry_has_mila_entry_has_drac_entries_.md diff --git a/tests/cli/test_init_command/test_with_existing_entries_has_mila_compute_entry_has_mila_cpu_entry_has_mila_entry_no_drac_entries_.md b/tests/cli/test_init/test_with_existing_entries_has_mila_compute_entry_has_mila_cpu_entry_has_mila_entry_no_drac_entries_.md similarity index 100% rename from tests/cli/test_init_command/test_with_existing_entries_has_mila_compute_entry_has_mila_cpu_entry_has_mila_entry_no_drac_entries_.md rename to tests/cli/test_init/test_with_existing_entries_has_mila_compute_entry_has_mila_cpu_entry_has_mila_entry_no_drac_entries_.md diff --git a/tests/cli/test_init_command/test_with_existing_entries_has_mila_compute_entry_has_mila_cpu_entry_no_mila_entry_has_drac_entries_.md b/tests/cli/test_init/test_with_existing_entries_has_mila_compute_entry_has_mila_cpu_entry_no_mila_entry_has_drac_entries_.md similarity index 100% rename from tests/cli/test_init_command/test_with_existing_entries_has_mila_compute_entry_has_mila_cpu_entry_no_mila_entry_has_drac_entries_.md rename to tests/cli/test_init/test_with_existing_entries_has_mila_compute_entry_has_mila_cpu_entry_no_mila_entry_has_drac_entries_.md diff --git a/tests/cli/test_init_command/test_with_existing_entries_has_mila_compute_entry_has_mila_cpu_entry_no_mila_entry_no_drac_entries_.md b/tests/cli/test_init/test_with_existing_entries_has_mila_compute_entry_has_mila_cpu_entry_no_mila_entry_no_drac_entries_.md similarity index 100% rename from tests/cli/test_init_command/test_with_existing_entries_has_mila_compute_entry_has_mila_cpu_entry_no_mila_entry_no_drac_entries_.md rename to tests/cli/test_init/test_with_existing_entries_has_mila_compute_entry_has_mila_cpu_entry_no_mila_entry_no_drac_entries_.md diff --git a/tests/cli/test_init_command/test_with_existing_entries_has_mila_compute_entry_no_mila_cpu_entry_has_mila_entry_has_drac_entries_.md b/tests/cli/test_init/test_with_existing_entries_has_mila_compute_entry_no_mila_cpu_entry_has_mila_entry_has_drac_entries_.md similarity index 100% rename from tests/cli/test_init_command/test_with_existing_entries_has_mila_compute_entry_no_mila_cpu_entry_has_mila_entry_has_drac_entries_.md rename to tests/cli/test_init/test_with_existing_entries_has_mila_compute_entry_no_mila_cpu_entry_has_mila_entry_has_drac_entries_.md diff --git a/tests/cli/test_init_command/test_with_existing_entries_has_mila_compute_entry_no_mila_cpu_entry_has_mila_entry_no_drac_entries_.md b/tests/cli/test_init/test_with_existing_entries_has_mila_compute_entry_no_mila_cpu_entry_has_mila_entry_no_drac_entries_.md similarity index 100% rename from tests/cli/test_init_command/test_with_existing_entries_has_mila_compute_entry_no_mila_cpu_entry_has_mila_entry_no_drac_entries_.md rename to tests/cli/test_init/test_with_existing_entries_has_mila_compute_entry_no_mila_cpu_entry_has_mila_entry_no_drac_entries_.md diff --git a/tests/cli/test_init_command/test_with_existing_entries_has_mila_compute_entry_no_mila_cpu_entry_no_mila_entry_has_drac_entries_.md b/tests/cli/test_init/test_with_existing_entries_has_mila_compute_entry_no_mila_cpu_entry_no_mila_entry_has_drac_entries_.md similarity index 100% rename from tests/cli/test_init_command/test_with_existing_entries_has_mila_compute_entry_no_mila_cpu_entry_no_mila_entry_has_drac_entries_.md rename to tests/cli/test_init/test_with_existing_entries_has_mila_compute_entry_no_mila_cpu_entry_no_mila_entry_has_drac_entries_.md diff --git a/tests/cli/test_init_command/test_with_existing_entries_has_mila_compute_entry_no_mila_cpu_entry_no_mila_entry_no_drac_entries_.md b/tests/cli/test_init/test_with_existing_entries_has_mila_compute_entry_no_mila_cpu_entry_no_mila_entry_no_drac_entries_.md similarity index 100% rename from tests/cli/test_init_command/test_with_existing_entries_has_mila_compute_entry_no_mila_cpu_entry_no_mila_entry_no_drac_entries_.md rename to tests/cli/test_init/test_with_existing_entries_has_mila_compute_entry_no_mila_cpu_entry_no_mila_entry_no_drac_entries_.md diff --git a/tests/cli/test_init_command/test_with_existing_entries_no_mila_compute_entry_has_mila_cpu_entry_has_mila_entry_has_drac_entries_.md b/tests/cli/test_init/test_with_existing_entries_no_mila_compute_entry_has_mila_cpu_entry_has_mila_entry_has_drac_entries_.md similarity index 100% rename from tests/cli/test_init_command/test_with_existing_entries_no_mila_compute_entry_has_mila_cpu_entry_has_mila_entry_has_drac_entries_.md rename to tests/cli/test_init/test_with_existing_entries_no_mila_compute_entry_has_mila_cpu_entry_has_mila_entry_has_drac_entries_.md diff --git a/tests/cli/test_init_command/test_with_existing_entries_no_mila_compute_entry_has_mila_cpu_entry_has_mila_entry_no_drac_entries_.md b/tests/cli/test_init/test_with_existing_entries_no_mila_compute_entry_has_mila_cpu_entry_has_mila_entry_no_drac_entries_.md similarity index 100% rename from tests/cli/test_init_command/test_with_existing_entries_no_mila_compute_entry_has_mila_cpu_entry_has_mila_entry_no_drac_entries_.md rename to tests/cli/test_init/test_with_existing_entries_no_mila_compute_entry_has_mila_cpu_entry_has_mila_entry_no_drac_entries_.md diff --git a/tests/cli/test_init_command/test_with_existing_entries_no_mila_compute_entry_has_mila_cpu_entry_no_mila_entry_has_drac_entries_.md b/tests/cli/test_init/test_with_existing_entries_no_mila_compute_entry_has_mila_cpu_entry_no_mila_entry_has_drac_entries_.md similarity index 100% rename from tests/cli/test_init_command/test_with_existing_entries_no_mila_compute_entry_has_mila_cpu_entry_no_mila_entry_has_drac_entries_.md rename to tests/cli/test_init/test_with_existing_entries_no_mila_compute_entry_has_mila_cpu_entry_no_mila_entry_has_drac_entries_.md diff --git a/tests/cli/test_init_command/test_with_existing_entries_no_mila_compute_entry_has_mila_cpu_entry_no_mila_entry_no_drac_entries_.md b/tests/cli/test_init/test_with_existing_entries_no_mila_compute_entry_has_mila_cpu_entry_no_mila_entry_no_drac_entries_.md similarity index 100% rename from tests/cli/test_init_command/test_with_existing_entries_no_mila_compute_entry_has_mila_cpu_entry_no_mila_entry_no_drac_entries_.md rename to tests/cli/test_init/test_with_existing_entries_no_mila_compute_entry_has_mila_cpu_entry_no_mila_entry_no_drac_entries_.md diff --git a/tests/cli/test_init_command/test_with_existing_entries_no_mila_compute_entry_no_mila_cpu_entry_has_mila_entry_has_drac_entries_.md b/tests/cli/test_init/test_with_existing_entries_no_mila_compute_entry_no_mila_cpu_entry_has_mila_entry_has_drac_entries_.md similarity index 100% rename from tests/cli/test_init_command/test_with_existing_entries_no_mila_compute_entry_no_mila_cpu_entry_has_mila_entry_has_drac_entries_.md rename to tests/cli/test_init/test_with_existing_entries_no_mila_compute_entry_no_mila_cpu_entry_has_mila_entry_has_drac_entries_.md diff --git a/tests/cli/test_init_command/test_with_existing_entries_no_mila_compute_entry_no_mila_cpu_entry_has_mila_entry_no_drac_entries_.md b/tests/cli/test_init/test_with_existing_entries_no_mila_compute_entry_no_mila_cpu_entry_has_mila_entry_no_drac_entries_.md similarity index 100% rename from tests/cli/test_init_command/test_with_existing_entries_no_mila_compute_entry_no_mila_cpu_entry_has_mila_entry_no_drac_entries_.md rename to tests/cli/test_init/test_with_existing_entries_no_mila_compute_entry_no_mila_cpu_entry_has_mila_entry_no_drac_entries_.md diff --git a/tests/cli/test_init_command/test_with_existing_entries_no_mila_compute_entry_no_mila_cpu_entry_no_mila_entry_has_drac_entries_.md b/tests/cli/test_init/test_with_existing_entries_no_mila_compute_entry_no_mila_cpu_entry_no_mila_entry_has_drac_entries_.md similarity index 100% rename from tests/cli/test_init_command/test_with_existing_entries_no_mila_compute_entry_no_mila_cpu_entry_no_mila_entry_has_drac_entries_.md rename to tests/cli/test_init/test_with_existing_entries_no_mila_compute_entry_no_mila_cpu_entry_no_mila_entry_has_drac_entries_.md diff --git a/tests/cli/test_init_command/test_with_existing_entries_no_mila_compute_entry_no_mila_cpu_entry_no_mila_entry_no_drac_entries_.md b/tests/cli/test_init/test_with_existing_entries_no_mila_compute_entry_no_mila_cpu_entry_no_mila_entry_no_drac_entries_.md similarity index 100% rename from tests/cli/test_init_command/test_with_existing_entries_no_mila_compute_entry_no_mila_cpu_entry_no_mila_entry_no_drac_entries_.md rename to tests/cli/test_init/test_with_existing_entries_no_mila_compute_entry_no_mila_cpu_entry_no_mila_entry_no_drac_entries_.md diff --git a/tests/conftest.py b/tests/conftest.py index f74a8177..2c379b9f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -25,7 +25,7 @@ import milatools.utils.parallel_progress import milatools.utils.remote_v2 from milatools.cli import console -from milatools.cli.init_command import setup_ssh_config +from milatools.cli.init import setup_ssh_config from milatools.cli.utils import SSH_CONFIG_FILE from milatools.utils.compute_node import get_queued_milatools_job_ids from milatools.utils.remote_v1 import RemoteV1 @@ -379,7 +379,7 @@ def ssh_config_file( monkeypatch: pytest.MonkeyPatch, ) -> Path: """Fixture that creates the SSH config as setup by `mila init`.""" - from milatools.cli.init_command import yn + from milatools.cli.init import yn # NOTE: might want to put this in a fixture if we wanted the "real" mila / drac # usernames in the config. @@ -400,9 +400,9 @@ def _yn(question: str) -> bool: mock_yn = Mock(spec=yn, side_effect=_yn) - import milatools.cli.init_command + import milatools.cli.init - monkeypatch.setattr(milatools.cli.init_command, yn.__name__, mock_yn) + monkeypatch.setattr(milatools.cli.init, yn.__name__, mock_yn) def _mock_unsafe_ask(question: str, *args, **kwargs) -> str: question = question.strip() diff --git a/tests/utils/test_local_v1.py b/tests/utils/test_local_v1.py index 6d04ae50..fa1f1f3d 100644 --- a/tests/utils/test_local_v1.py +++ b/tests/utils/test_local_v1.py @@ -1,22 +1,17 @@ from __future__ import annotations -import sys from subprocess import PIPE import pytest from pytest_regressions.file_regression import FileRegressionFixture -from milatools.cli.utils import SSH_CONFIG_FILE -from milatools.utils.local_v1 import CommandNotFoundError, LocalV1, check_passwordless -from milatools.utils.remote_v2 import is_already_logged_in +from milatools.utils.local_v1 import CommandNotFoundError, LocalV1 from ..cli.common import ( in_github_CI, in_self_hosted_github_CI, output_tester, - passwordless_ssh_connection_to_localhost_is_setup, requires_no_s_flag, - skip_if_on_github_cloud_CI, xfails_on_windows, ) @@ -129,70 +124,3 @@ def test_popen( "and raises a ValueError." ), ) - - -# @PARAMIKO_SSH_BANNER_BUG -# @paramiko_openssh_key_parsing_issue -@pytest.mark.xfail( - reason="TODO: `check_passwordless` is incredibly flaky and needs to be reworked." -) -@pytest.mark.parametrize( - ("hostname", "expected"), - [ - pytest.param( - "localhost", - passwordless_ssh_connection_to_localhost_is_setup, - ), - ("blablabob@localhost", False), - pytest.param( - "mila", - True if (in_self_hosted_github_CI or not in_github_CI) else False, - ), - pytest.param( - "bobobobobobo@mila", - False, - marks=[ - paramiko_openssh_key_parsing_issue, - skip_if_on_github_cloud_CI, - ], - ), - # For the clusters with 2FA, we expect `check_passwordless` to return True if - # we've already setup the shared SSH connection. - pytest.param( - "blablabob@narval", - False, - marks=[ - skip_if_on_github_cloud_CI, - paramiko_openssh_key_parsing_issue, - ], - ), - *( - # note: can't properly test for the False case because of the 2FA - # prompt! - pytest.param( - drac_cluster, - True, - marks=pytest.mark.skipif( - sys.platform == "win32" - or not is_already_logged_in( - drac_cluster, ssh_config_path=SSH_CONFIG_FILE - ), - reason="Should give True when we're already logged in.", - ), - ) - for drac_cluster in ["narval", "beluga", "cedar", "graham"] - ), - pytest.param( - "niagara", - False, - marks=[ - skip_if_on_github_cloud_CI, - paramiko_openssh_key_parsing_issue, - ], - ), # SSH access to niagara isn't enabled by default. - ], -) -def test_check_passwordless(hostname: str, expected: bool): - # TODO: Maybe also test how `check_passwordless` behaves when using a key with a - # passphrase. - assert check_passwordless(hostname) == expected