drone-deploy/main.py

128 lines
4.4 KiB
Python
Raw Normal View History

2019-03-05 18:30:10 +00:00
import io
import os
import random
import string
import warnings
import subprocess
from typing import List
from os.path import abspath, join, dirname
import paramiko
from paramiko import SSHClient
def get_random_string(length: int = 128) -> str:
return ''.join(random.choices(string.ascii_lowercase + string.digits, k=length))
2019-05-25 14:42:19 +00:00
def execute(c: SSHClient, cmd: str, path: str = None, env:dict = None) -> str:
2019-03-05 18:30:10 +00:00
if path is not None:
cmd = 'cd {}; {}'.format(path, cmd)
2019-05-25 14:42:19 +00:00
stdin, stdout, stderr = c.exec_command(cmd, environment=env)
2019-03-05 19:24:51 +00:00
return stdout.read().decode('utf-8').strip()
2019-03-05 18:30:10 +00:00
def main():
host = os.environ.get('PLUGIN_HOST')
port = os.environ.get('PLUGIN_PORT', 22)
user = os.environ.get('PLUGIN_USER')
password = os.environ.get('PLUGIN_PASSWORD')
key = os.environ.get('PLUGIN_KEY')
2019-05-25 14:42:19 +00:00
# Takes a string, splits it at the comma and removes empty elements
2019-03-05 18:30:10 +00:00
def clean_array(s: str) -> List[str]:
return list(filter(None, s.split(',')))
commands = clean_array(os.environ.get('PLUGIN_COMMANDS', ''))
sources = clean_array(os.environ.get('PLUGIN_SOURCES', ''))
deletes = clean_array(os.environ.get('PLUGIN_DELETE', ''))
target = os.environ.get('PLUGIN_TARGET')
2019-05-25 14:42:19 +00:00
# Check for host, port and user
2019-03-05 18:30:10 +00:00
for env in [host, port, user]:
if env is None:
2019-05-25 14:42:19 +00:00
raise Exception('Missing host, port or user env variable')
2019-03-05 18:30:10 +00:00
2019-05-25 14:42:19 +00:00
# Check if there is a possible authentication method
2019-03-05 18:30:10 +00:00
if len(list(filter(lambda x: x is not None, [password, key]))) is 0:
raise Exception('No authentication method provided')
2019-05-25 14:42:19 +00:00
# Check if target is set
2019-03-05 18:30:10 +00:00
if len(sources) is not 0 and target is None:
raise Exception('Target not set')
2019-05-25 14:42:19 +00:00
# Remote Envs
envsraw = os.environ.get('PLUGIN_ENVS')
2019-05-27 18:25:09 +00:00
envs = None
2019-05-25 14:42:19 +00:00
if envsraw is not None:
prefix = 'PLUGIN_'
# Take only the envs that start with PLUGIN_ and remore the prefix
2019-05-25 14:50:19 +00:00
envs = {k[len(prefix):]:v for k, v in os.environ.items() if k.startswith(prefix)}
2019-05-25 14:42:19 +00:00
if 'all' != envsraw or ',' in envsraw:
# Make them uppercase
selected = [x.upper() for x in clean_array(envsraw)]
# Select only the envs that where specified inside of envs
envs = {k:v for k,v in envs.items() if k in selected}
2019-03-05 18:30:10 +00:00
ssh: SSHClient = paramiko.SSHClient()
try:
k = paramiko.RSAKey.from_private_key(io.StringIO(key))
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname=host, username=user, pkey=k, port=port, password=password)
# If a target is set, make sure the directory is created and writable
if target is not None:
try:
execute(ssh, 'mkdir -p {}'.format(target))
tmp_file = get_random_string()
execute(ssh, 'touch {}; rm {}'.format(tmp_file, tmp_file), target)
except Exception:
raise Exception('Could not create directory')
sftp = ssh.open_sftp()
try:
# DELETE
for delete in deletes:
sftp.remove(join(target, delete))
# COPY
if len(sources) is not 0:
archive = get_random_string(100) + '.tar.gz' # Keep the max file name length under 128 chars
archive_local = abspath(archive)
archive_remote = join(target, archive)
# sources = list(map(lambda x: join(dirname(archive_local), x), sources))
# print(sources)
# Compress
cmd = ['tar', '-czf', archive, '-C', dirname(archive_local), *sources]
run = subprocess.run(cmd, capture_output=True)
if run.returncode is not 0:
raise Exception('Error while compressing locally. {}'.format(run.stderr.decode('utf-8').strip()))
# Upload
sftp.put(archive_local, archive_remote)
# Extract
execute(ssh, 'tar -xzf {}'.format(archive), target)
# Delete Archives
sftp.remove(archive_remote)
subprocess.run(['rm', archive_local], capture_output=True)
finally:
sftp.close()
for command in commands:
2019-05-25 14:55:08 +00:00
output = execute(ssh, command, target, envs)
2019-03-05 19:24:51 +00:00
print(command)
2019-03-05 18:30:10 +00:00
print(output)
finally:
ssh.close()
with warnings.catch_warnings():
warnings.simplefilter('ignore')
main()