1.6. SSH

1.6.1. paramiko

import paramiko

client = paramiko.SSHClient()

client.connect('example.com', username='tester')
# Traceback (most recent call last):
#   ...
# paramiko.ssh_exception.SSHException: Server 'example.com' not found in known_hosts
import paramiko

client = paramiko.SSHClient()

client.load_system_host_keys()
client.load_host_keys('/home/brandon/.ssh/known_hosts')
client.connect('example.com', username='test')

1.6.1.1. Password Auth

client.connect('example.com', username='brandon', password=mypass)
client.connect('my.example.com')

1.6.1.2. Public/Private Key Auth

client.connect('my.example.com', key_filename='/home/brandon/.ssh/id_sysadmin')

1.6.1.3. Running commands

import sys
import getpass
import paramiko


hostname = sys.argv[1]
username = sys.argv[2]
password = getpass.getpass()


client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy)
client.connect(hostname, username=username, password=password)

commands = [
    'echo "Hello, world!"',
    'uname',
    'uptime',
]

for command in commands:
    stdin, stdout, stderr = client.exec_command(command)
    stdin.close()
    print(repr(stdout.read()))
    stdout.close()
    stderr.close()

client.close

1.6.1.4. SCP

  • File transfer over SSH

1.6.1.5. SFTP

  • It is not FTPS

import sys
import paramiko

host = "example.com"
port = 22
password = "THEPASSWORD"
username = "THEUSERNAME"


transport = paramiko.Transport((host, port))
transport.connect(username = username, password = password)
sftp = paramiko.SFTPClient.from_transport(transport)

path_local = 'README.txt'
path_remote = '/tmp/README.txt'

sftp.put(path_local, path_remote)

sftp.close()
transport.close()

1.6.2. pysftp

pip install pysftp
import pysftp
import sys


host = "example.com"
port = 22
password = "THEPASSWORD"
username = "THEUSERNAME"

path_local = 'README.txt'
path_remote = '/tmp/README.txt'


with pysftp.Connection(host, username=username, password=password) as sftp:
    sftp.put(path_local, path_remote)

1.6.3. fabric

pip install fabric

1.6.3.1. Example

from fabric.api import *

env.hosts = ['THEHOST.com']
env.user = 'THEUSER'
env.password = 'THEPASSWORD'

def put_file(file):
    put(file, './THETARGETDIRECTORY/')
fab -f fab_putfile.py put_file:file=./path/to/my/file

1.6.3.2. Local

from fabric.api import local

def prepare_deploy():
    local("./manage.py test my_app")
    local("git add -p && git commit")
    local("git push")
$ fab prepare_deploy
[localhost] run: ./manage.py test my_app
Creating test database...
Creating tables
Creating indexes
..........................................
----------------------------------------------------------------------
Ran 42 tests in 9.138s

OK
Destroying test database...

[localhost] run: git add -p && git commit

<interactive Git add / git commit edit message session>

[localhost] run: git push

<git push session, possibly merging conflicts interactively>

Done.

1.6.3.3. Organization

from fabric.api import local

def test():
    local("./manage.py test my_app")

def commit():
    local("git add -p && git commit")

def push():
    local("git push")

def prepare_deploy():
    test()
    commit()
    push()

1.6.3.4. Failure handling

from fabric.api import local, settings, abort
from fabric.contrib.console import confirm

def test():
    with settings(warn_only=True):
        result = local('./manage.py test my_app', capture=True)

    if result.failed and not confirm("Tests failed. Continue anyway?"):
        abort("Aborting at user request.")

1.6.3.5. Executing on remote host

from fabric import SerialGroup

result = SerialGroup('web1', 'web2').run('hostname')
# web1
# web2

# it's a dict!
result.items()
# [
#   (<Connection host=web1>, <Result cmd='hostname' exited=0>),
#   ...
# ]
from fabric.api import *
from fabric.contrib.console import confirm

env.hosts = ['my_server']

def test():
    with settings(warn_only=True):
        result = local('./manage.py test my_app', capture=True)

    if result.failed and not confirm("Tests failed. Continue anyway?"):
        abort("Aborting at user request.")

def commit():
    local("git add -p && git commit")

def push():
    local("git push")

def prepare_deploy():
    test()
    commit()
    push()

def deploy():
    code_dir = '/srv/django/myproject'

    with settings(warn_only=True):
        if run("test -d %s" % code_dir).failed:
            run("git clone [email protected]:/path/to/repo/.git %s" % code_dir)

    with cd(code_dir):
        run("git pull")
        run("touch app.wsgi")
from fabric.api import *

def deploy():
    sudo("~/install_script.py")
    sudo("mkdir /var/www/new_docroot", user="www-data")
    sudo("ls /home/jdoe", user=1001)
    result = sudo("ls /tmp/")

    with settings(sudo_user='mysql'):
        sudo("whoami")
        # 'mysql'

1.6.3.6. Host

from fabric.api import hosts

@hosts(['127.0.0.1', 'localhost'])
def whoami():
    sudo('whoami')

1.6.4. pssh

../../_images/ssh-pssh-1.jpg
../../_images/ssh-pssh-2.png
../../_images/ssh-pssh-3.png