Skip to content

Instantly share code, notes, and snippets.

@mamaj
Last active January 31, 2023 12:22
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mamaj/a7b378a5c969e3e32a9e4f9bceb0c5eb to your computer and use it in GitHub Desktop.
Save mamaj/a7b378a5c969e3e32a9e4f9bceb0c5eb to your computer and use it in GitHub Desktop.
Python: simple class to perform commands and copy files (scp) on ssh using subprocess and native ssh client (OpenSSH).
import subprocess
import os
from pathlib import Path
from typing import Union
class SshClient():
""" Perform commands and copy files on ssh using subprocess
and native ssh client (OpenSSH).
"""
def __init__(self,
user: str,
remote: str,
key_path: Union[str, Path]) -> None:
"""
Args:
user (str): username for the remote
remote (str): remote host IP/DNS
key_path (str or pathlib.Path): path to .pem file
"""
self.user = user
self.remote = remote
self.key_path = str(key_path)
def cmd(self,
cmds: list[str],
check=True,
strict_host_key_checking=False,
**run_kwargs) -> subprocess.CompletedProcess:
"""runs commands consecutively, ensuring success of each
after calling the next command.
Args:
cmds (list[str]): list of commands to run.
strict_host_key_checking (bool, optional): Defaults to True.
"""
strict_host_key_checking = 'yes' if strict_host_key_checking else 'no'
cmd = ' && '.join(cmds)
return subprocess.run(
[
'ssh',
'-i', self.key_path,
'-o', f'StrictHostKeyChecking={strict_host_key_checking}',
'-o', 'UserKnownHostsFile=/dev/null',
'-o', 'LogLevel=ERROR',
f'{self.user}@{self.remote}',
cmd
],
check=check,
**run_kwargs
)
def scp(self,
sources: list[Union[str, bytes, os.PathLike]],
destination: Union[str, bytes, os.PathLike],
check=True,
strict_host_key_checking=False,
recursive=False,
**run_kwargs) -> subprocess.CompletedProcess:
"""Copies `srouce` file to remote `destination` using the
native `scp` command.
Args:
source (Union[str, bytes, os.PathLike]): List of source files path.
destination (Union[str, bytes, os.PathLike]): Destination path on remote.
"""
strict_host_key_checking = 'yes' if strict_host_key_checking else 'no'
return subprocess.run(
list(filter(bool, [
'scp',
'-i', self.key_path,
'-o', f'StrictHostKeyChecking={strict_host_key_checking}',
'-o', 'UserKnownHostsFile=/dev/null',
'-o', 'LogLevel=ERROR',
'-r' if recursive else '',
*map(str, sources),
# sources,
f'{self.user}@{self.remote}:{str(destination)}',
])),
check=check,
**run_kwargs
)
def validate(self):
return self.cmd([f'echo " "'], check=False).returncode == 0
def ssh_connect_cmd(self) -> str:
return f'ssh -i {self.key_path} {self.user}@{self.remote}'
@mamaj
Copy link
Author

mamaj commented Aug 25, 2022

Feedbacks are welcome!

@mamaj
Copy link
Author

mamaj commented Aug 25, 2022

usage:

from ssh_utils import SshClient

client = SshClient(user='username', remote='remote_addr', key_path='/path/to/key.pem')

# run a list of commands
client.cmd(['mkdir ~/testdir', 'ls -la', 'echo done!'])

# copy files/dirs
client.scp('my_file.txt', '~/testdir')

@linuxguy123
Copy link

Is there a way to pass in the user's password and not use the key ?

@mamaj
Copy link
Author

mamaj commented Jan 1, 2023

Not with the native ssh command. Probably need to install sshpass on the remote and modify client.cmd function accordingly.

@linuxguy123
Copy link

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment