autoenv

  • v5
import os
import sys
import re
import time
import paramiko
import fabric
import tarfile
from tkinter import *
from tkinter import messagebox
from threading import Thread


# TODO: config
height = 600
width = 700
server_password_default = 'gta'
run_file_endswith = '.sh'
run_cmd = 'bash'
connection_timeout = 10
info_connection_timeout = 2


def get_servers() -> dict:
    servers ={}
    with open('servers.txt', 'r') as f:
        for line in f.readlines():
            line_ = line.split(',')
            line_ = [t.strip() for t in line_]
            name = line_[0]
            url = line_[1]
            url_ = url.split('@')
            user = url_[0]
            ip, port = url_[1].split(':')
            servers[name] = {'user':user, 'ip':ip, 'port':port}
    return servers
servers = get_servers()
# print('servers: ', servers)


def get_envs(env_list_dir='.') -> list:
    envs = []
    for dir in os.listdir(env_list_dir):
        if not os.path.isdir(dir): continue
        if dir.startswith('_'): continue
        envs.append(dir)
    return envs
envs = get_envs()
# print('envs:', envs)


def print_server_info(name):
    server = servers[name]
    return name + ' ' + server['user'] + '@' + server['ip'] + ':' + server['port']


# window
window = Tk()
window.title('autoenv')
screenwidth = window.winfo_screenwidth()
screenheight = window.winfo_screenheight()
alignstr = '%dx%d+%d+%d' % (width, height, (screenwidth-width)/2, (screenheight-height)/2*0.8)
window.geometry(alignstr)


# frame_list
frame_list = Frame()
frame_list.pack(side=TOP, fill=BOTH, expand=True)
list_envs, list_servers = Listbox(frame_list, exportselection=False), Listbox(frame_list, exportselection=False)
scrollnar_envs, scrollnar_servers = Scrollbar(frame_list), Scrollbar(frame_list)
list_envs.config(yscrollcommand=scrollnar_envs.set)
list_servers.config(yscrollcommand=scrollnar_servers.set)
scrollnar_envs.config(command=list_envs.yview)
scrollnar_servers.config(command=list_servers.yview)
list_envs.pack(side=LEFT, fill=BOTH, expand=True)
scrollnar_envs.pack(side=LEFT, fill=Y)
list_servers.pack(side=LEFT, fill=BOTH, expand=True)
scrollnar_servers.pack(side=LEFT, fill=Y)
for name in envs: list_envs.insert('end', name)
for name in servers.keys(): list_servers.insert(END, print_server_info(name))
[list_servers.itemconfig(i, bg='#e0f0ff') for i in range(len(servers.keys())) if i%2]
[list_envs.itemconfig(i, bg='#e0f0ff') for i in range(len(envs)) if i%2]


# frame_console
frame_console = Frame()
frame_console.pack(side=TOP, fill=BOTH, expand=True)
console = Text(frame_console, fg='white', bg='black')
scrollnar_console = Scrollbar(frame_console)
console.config(yscrollcommand=scrollnar_console.set)
scrollnar_console.config(command=console.yview)
console.pack(side=LEFT, fill=BOTH, expand=True)
scrollnar_console.pack(side=LEFT, fill=Y)
class Redirector:
    def __init__(self, text) -> None:
        self.text = text
    def write(self, string):
        def write_():
            self.text.insert('end', string)
            self.text.see('end')
        Thread(target=write_, daemon=True).start()
    def flush(self): pass
sys.stdout = Redirector(console)


# frame_ctl
frame_ctl = Frame(window).pack(side=TOP, fill=X, expand=False)
lb_run = Label(frame_ctl, text='runfile: ').pack(side=LEFT)
runfile_v = StringVar(value='run' + run_file_endswith)
entry_run = Entry(frame_ctl, textvariable=runfile_v, width=12).pack(side=LEFT, fill=X, expand=True)
lb_password = Label(frame_ctl, text='password: ').pack(side=LEFT)
password_v = StringVar(value=server_password_default)
entry_password = Entry(frame_ctl, textvariable=password_v, show='*', width=12).pack(side=LEFT, fill=X, expand=True)


def check():
    try:
        server_name = list_servers.get(list_servers.curselection()).split(' ')[0].strip()
        server = servers[server_name]
    except: return False
    conn = fabric.Connection(server['ip'], user=server['user'], 
        port=int(server['port']), connect_kwargs={"password": password_v.get()}, 
        connect_timeout=info_connection_timeout)
    try: 
        mem = conn.run('free -h | grep Mem', hide='stdout').stdout.strip().split(' ')
        mem = [t for t in mem if len(t)>0]
        disk = conn.run('df ~ -kh | grep G', hide='stdout').stdout.strip().split(' ')
        disk = [t for t in disk if len(t)>0]
    except:
        messagebox.showinfo(title='error', message='connection: ' + server['ip'] + ':' + server['port'])
        conn.close()
        return False
    mem_info = 'mem: ' + mem[2] + '/' + mem[1]
    disk_info = 'disk: ' + disk[2] + '/' + disk[1]
    print('[' + server_name + ']' + '[used/total] ' + mem_info + ', ' + disk_info)
    conn.close()
    return True
btn_info = Button(frame_ctl, text='Info', bg='gray', command=check).pack(side=LEFT, fill=X, expand=True)


def terminal():
    try:
        server_name = list_servers.get(list_servers.curselection()).split(' ')[0].strip()
        server = servers[server_name]
    except: return
    try: env = '~/' + list_envs.get(list_envs.curselection()).strip().replace('-', '/')
    except: env = '~'
    os.system('start cmd /k ssh -t -p ' + server['port'] + ' ' + server['user'] + '@' + server['ip'] + ' \" cd ' + env + '; bash --login\"')
btn_terminal = Button(frame_ctl, text='Terminal', bg='gray', command=terminal).pack(side=LEFT, fill=X, expand=True)


def auth():
    try:
        server_name = list_servers.get(list_servers.curselection()).split(' ')[0].strip()
        server = servers[server_name]
    except: return
    conn = fabric.Connection(server['ip'], user=server['user'], 
        port=server['port'], connect_kwargs={"password": password_v.get()}, 
        connect_timeout=connection_timeout)
    try: 
        pwd = conn.run('cd ~; pwd').stdout.strip()
    except:
        messagebox.showinfo(title='error', message='connection: ' + server['ip'] + ':' + server['port'])
        conn.close()
        return
    join = os.path.join
    pub_key = join(join(os.path.expanduser('~'), '.ssh'), 'id_rsa.pub')
    if not os.path.exists(pub_key): os.system('ssh-keygen -t rsa')
    remote_author_file = pwd + '/.ssh/authorized_keys'
    local_author_file = 'authorized_keys-' + str(round(time.time()*1000))
    try:
        conn.get(remote_author_file, local_author_file)
        with open(local_author_file, 'r') as f: lines = f.readlines()
        lines = [t.strip() for t in lines if len(t)>5]
    except: lines = []
    with open(pub_key, 'r') as f: item = f.readlines()[0].strip()
    if item in lines:
        conn.close()
        os.remove(local_author_file)
        return
    lines.append(item)
    out = '\n'.join(lines)
    with open(local_author_file, 'w') as f: f.write(out)
    try:
        conn.put(local_author_file, remote_author_file)
        conn.run('chmod 600 {}'.format(remote_author_file))
    except Exception as e:
        messagebox.showinfo(title='error', message=str(e))
        conn.close()
        os.remove(local_author_file)
        return
    conn.close()
    os.remove(local_author_file)
    return
btn_auth = Button(frame_ctl, text='Auth', bg='gray', command=auth).pack(side=LEFT, fill=X, expand=True)


btn_dispatch = Button(frame_ctl, text='Dispatch', bg='gray')
def dispatch_():
    try:
        env = list_envs.get(list_envs.curselection()).strip()
        server_name = list_servers.get(list_servers.curselection()).split(' ')[0].strip()
        server = servers[server_name]
    except: return
    notice = messagebox.askokcancel('notice', env + ' -> ' + server_name + '\nrelevant files will be deleted')
    if not notice: return
    print(env, ' -> ', server_name)
    def change_to_lf(endswith):
        for root, _, files in os.walk(env):
            for file in files:
                put_localpath = os.path.realpath(os.path.join(root, file))
                if put_localpath.endswith(endswith):
                    # print('-> lf ' + put_localpath)
                    with open(put_localpath, 'rb') as f: temp = f.read()
                    temp = temp.replace(b'\r\n', b'\n')
                    with open(put_localpath, 'wb') as f: f.write(temp)
    change_to_lf(run_file_endswith)
    # connect
    conn = fabric.Connection(server['ip'], user=server['user'], 
        port=server['port'], connect_kwargs={"password": password_v.get()}, 
        connect_timeout=connection_timeout)
    try: 
        pwd = conn.run('cd ~; pwd').stdout.strip()
    except:
        messagebox.showinfo(title='error', message='connection: ' + server['ip'] + ':' + server['port'])
        conn.close()
        return
    put_remotepath = pwd + '/' + '/'.join(re.split(r'[-]', env))
    try:
        conn.run("mkdir -p {0}; cd {0}".format(put_remotepath))
    except Exception as e:
        messagebox.showinfo(title='error', message=str(e))
        conn.close()
        return
    env_file = env + '-' + str(round(time.time()*1000)) + '.tar.gz'
    try:
        with tarfile.open(env_file, 'w:gz') as tar: tar.add(env, arcname=os.path.basename('.'))
    except Exception as e:
        messagebox.showinfo(title='error', message=str(e))
        conn.close()
        return
    try:
        conn.put(env_file, put_remotepath) # no callback
    except Exception as e:
        messagebox.showinfo(title='error', message=str(e))
        conn.close()
        return
    try:
        conn.run("cd {0}; tar -xzvf {1}; rm -rf {1}".format(put_remotepath, env_file))
    except Exception as e:
        messagebox.showinfo(title='error', message=str(e))
        conn.close()
        os.remove(env_file)
        return
    os.remove(env_file)
    try:
        conn.run("cd {0}; {2} {1}".format(put_remotepath, runfile_v.get(), run_cmd), pty=True, encoding='utf-8')
    except:
        messagebox.showinfo(title='partial success', message=server_name + '\nrunfile failed')
        conn.close()
        return
    messagebox.showinfo(title='success', message=server_name)
    conn.close()
def dispatch():
    def run():
        btn_dispatch.config(state=DISABLED)
        dispatch_()
        btn_dispatch.config(state=NORMAL)
    Thread(target=run, daemon=True).start()
btn_dispatch.config(command=dispatch)
btn_dispatch.pack(side=LEFT, fill=X, expand=True)


window.mainloop()
  • vscode
if [ ! -f ./vsc/code-server ]; then
wget https://github.com/cdr/code-server/releases/download/v3.12.0/code-server-3.12.0-linux-amd64.tar.gz -O vsc.tar.gz
mkdir ./vsc && tar -zxvf vsc.tar.gz -C ./vsc --strip-components 1
rm -rf vsc.tar.gz
fi

VSBASE=$(pwd)
IPADD=$(ifconfig | grep "inet " | grep "broadcast" | awk '{print $2}')
cd vsc
tmux kill-session -t $VSBASE
tmux new -s $VSBASE -d

for port in {8081..18081}
do
PORTCT=$(lsof -i -P -n | grep LISTEN | grep :$port | wc -l)
if [ $PORTCT = "0" ]; then
PORTUSE=$port
break
fi
done

tmux send -t $VSBASE "PASSWORD=gta ./code-server --host 0.0.0.0 --port $PORTUSE" Enter
echo http://$IPADD:$PORTUSE 2>&1 | tee ../url.log

  • v4
import os
import re
import time
import paramiko
import fabric
import tarfile
from tkinter import *
from tkinter import messagebox


# TODO: config
height = 420
width = 450
server_password_default = 'gta'
run_file_endswith = '.sh'
run_cmd = 'bash'
connection_timeout = 10
info_connection_timeout = 2


def get_servers() -> dict:
    servers ={}
    with open('servers.txt', 'r') as f:
        for line in f.readlines():
            line_ = line.split(',')
            line_ = [t.strip() for t in line_]
            name = line_[0]
            url = line_[1]
            url_ = url.split('@')
            user = url_[0]
            ip, port = url_[1].split(':')
            servers[name] = {'user':user, 'ip':ip, 'port':port}
    return servers
servers = get_servers()
# print('servers: ', servers)


def get_envs(env_list_dir='.') -> list:
    envs = []
    for dir in os.listdir(env_list_dir):
        if not os.path.isdir(dir): continue
        if dir.startswith('_'): continue
        envs.append(dir)
    return envs
envs = get_envs()
# print('envs:', envs)


def print_server_info(name):
    server = servers[name]
    return name + ' ' + server['user'] + '@' + server['ip'] + ':' + server['port']


window = Tk()
window.title('autoenv')
screenwidth = window.winfo_screenwidth()
screenheight = window.winfo_screenheight()
alignstr = '%dx%d+%d+%d' % (width, height, (screenwidth-width)/2, (screenheight-height)/2*0.8)
window.geometry(alignstr)
frame_list = Frame()
frame_list.pack(side=TOP, fill=BOTH, expand=True)
list_envs, list_servers = Listbox(frame_list, exportselection=False), Listbox(frame_list, exportselection=False)
scrollnar_envs, scrollnar_servers = Scrollbar(frame_list), Scrollbar(frame_list)
list_envs.config(yscrollcommand=scrollnar_envs.set)
list_servers.config(yscrollcommand=scrollnar_servers.set)
scrollnar_envs.config(command=list_envs.yview)
scrollnar_servers.config(command=list_servers.yview)
list_envs.pack(side=LEFT, fill=BOTH, expand=True)
scrollnar_envs.pack(side=LEFT, fill=Y)
list_servers.pack(side=LEFT, fill=BOTH, expand=True)
scrollnar_servers.pack(side=LEFT, fill=Y)
for name in envs: list_envs.insert('end', name)
for name in servers.keys(): list_servers.insert(END, print_server_info(name))
[list_servers.itemconfig(i, bg='#e0f0ff') for i in range(len(servers.keys())) if i%2]
[list_envs.itemconfig(i, bg='#e0f0ff') for i in range(len(envs)) if i%2]
info = StringVar(value='[please select machine][used/total]')
lb_info = Label(textvariable=info).pack(side=TOP, fill=X)
frame_ctl = Frame(window).pack(side=TOP, fill=X, expand=False)
lb_run = Label(frame_ctl, text='runfile: ').pack(side=LEFT)
runfile_v = StringVar(value='run' + run_file_endswith)
entry_run = Entry(frame_ctl, textvariable=runfile_v, width=12).pack(side=LEFT, fill=X, expand=True)
lb_password = Label(frame_ctl, text='password: ').pack(side=LEFT)
password_v = StringVar(value=server_password_default)
entry_password = Entry(frame_ctl, textvariable=password_v, show='*', width=12).pack(side=LEFT, fill=X, expand=True)


def dispatch():
    try:
        env = list_envs.get(list_envs.curselection()).strip()
        server_name = list_servers.get(list_servers.curselection()).split(' ')[0].strip()
        server = servers[server_name]
    except: return
    notice = messagebox.askokcancel('notice', env + ' -> ' + server_name + '\nrelevant files will be deleted')
    if not notice: return
    print(env, ' -> ', server_name)
    def change_to_lf(endswith):
        for root, _, files in os.walk(env):
            for file in files:
                put_localpath = os.path.realpath(os.path.join(root, file))
                if put_localpath.endswith(endswith):
                    # print('-> lf ' + put_localpath)
                    with open(put_localpath, 'rb') as f: temp = f.read()
                    temp = temp.replace(b'\r\n', b'\n')
                    with open(put_localpath, 'wb') as f: f.write(temp)
    change_to_lf(run_file_endswith)
    # connect
    conn = fabric.Connection(server['ip'], user=server['user'], 
        port=server['port'], connect_kwargs={"password": password_v.get()}, 
        connect_timeout=connection_timeout)
    try: 
        pwd = conn.run('cd ~; pwd').stdout.strip()
    except:
        messagebox.showinfo(title='error', message='connection: ' + server['ip'] + ':' + server['port'])
        conn.close()
        return
    put_remotepath = pwd + '/' + '/'.join(re.split(r'[-]', env))
    try:
        conn.run("mkdir -p {0}; cd {0}".format(put_remotepath))
    except Exception as e:
        messagebox.showinfo(title='error', message=str(e))
        conn.close()
        return
    env_file = env + '-' + str(round(time.time()*1000)) + '.tar.gz'
    try:
        with tarfile.open(env_file, 'w:gz') as tar: tar.add(env, arcname=os.path.basename('.'))
    except Exception as e:
        messagebox.showinfo(title='error', message=str(e))
        conn.close()
        return
    try:
        conn.put(env_file, put_remotepath) # no callback
    except Exception as e:
        messagebox.showinfo(title='error', message=str(e))
        conn.close()
        return
    try:
        conn.run("cd {0}; tar -xzvf {1}; rm -rf {1}".format(put_remotepath, env_file))
    except Exception as e:
        messagebox.showinfo(title='error', message=str(e))
        conn.close()
        os.remove(env_file)
        return
    os.remove(env_file)
    try:
        conn.run("cd {0}; {2} {1}".format(put_remotepath, runfile_v.get(), run_cmd), pty=True, encoding='utf-8')
    except:
        messagebox.showinfo(title='partial success', message=server_name + '\nrunfile failed')
        conn.close()
        return
    messagebox.showinfo(title='success', message=server_name)
    conn.close()


def check():
    try:
        server_name = list_servers.get(list_servers.curselection()).split(' ')[0].strip()
        server = servers[server_name]
    except: return False
    conn = fabric.Connection(server['ip'], user=server['user'], 
        port=int(server['port']), connect_kwargs={"password": password_v.get()}, 
        connect_timeout=info_connection_timeout)
    try: 
        mem = conn.run('free -h | grep Mem', hide='stdout').stdout.strip().split(' ')
        mem = [t for t in mem if len(t)>0]
        disk = conn.run('df ~ -kh | grep G', hide='stdout').stdout.strip().split(' ')
        disk = [t for t in disk if len(t)>0]
    except:
        messagebox.showinfo(title='error', message='connection: ' + server['ip'] + ':' + server['port'])
        conn.close()
        return False
    mem_info = 'mem: ' + mem[2] + '/' + mem[1]
    disk_info = 'disk: ' + disk[2] + '/' + disk[1]
    info.set('[' + server_name + ']' + '[used/total] ' + mem_info + ', ' + disk_info)
    conn.close()
    return True


def terminal():
    try:
        server_name = list_servers.get(list_servers.curselection()).split(' ')[0].strip()
        server = servers[server_name]
    except: return
    try: env = '~/' + list_envs.get(list_envs.curselection()).strip().replace('-', '/')
    except: env = '~'
    os.system('start cmd /k ssh -t -p ' + server['port'] + ' ' + server['user'] + '@' + server['ip'] + ' \" cd ' + env + '; bash --login\"')


def auth():
    try:
        server_name = list_servers.get(list_servers.curselection()).split(' ')[0].strip()
        server = servers[server_name]
    except: return
    conn = fabric.Connection(server['ip'], user=server['user'], 
        port=server['port'], connect_kwargs={"password": password_v.get()}, 
        connect_timeout=connection_timeout)
    try: 
        pwd = conn.run('cd ~; pwd').stdout.strip()
    except:
        messagebox.showinfo(title='error', message='connection: ' + server['ip'] + ':' + server['port'])
        conn.close()
        return
    join = os.path.join
    pub_key = join(join(os.path.expanduser('~'), '.ssh'), 'id_rsa.pub')
    if not os.path.exists(pub_key): os.system('ssh-keygen -t rsa')
    remote_author_file = pwd + '/.ssh/authorized_keys'
    local_author_file = 'authorized_keys-' + str(round(time.time()*1000))
    try:
        conn.get(remote_author_file, local_author_file)
        with open(local_author_file, 'r') as f: lines = f.readlines()
        lines = [t.strip() for t in lines if len(t)>5]
    except: lines = []
    with open(pub_key, 'r') as f: item = f.readlines()[0].strip()
    if item in lines:
        conn.close()
        os.remove(local_author_file)
        return
    lines.append(item)
    out = '\n'.join(lines)
    with open(local_author_file, 'w') as f: f.write(out)
    try:
        conn.put(local_author_file, remote_author_file)
        conn.run('chmod 600 {}'.format(remote_author_file))
    except Exception as e:
        messagebox.showinfo(title='error', message=str(e))
        conn.close()
        os.remove(local_author_file)
        return
    conn.close()
    os.remove(local_author_file)
    return


btn_info = Button(frame_ctl, text='Info', bg='gray', command=check).pack(side=LEFT, fill=X, expand=True)
btn_auth = Button(frame_ctl, text='Auth', bg='gray', command=auth).pack(side=LEFT, fill=X, expand=True)
btn_terminal = Button(frame_ctl, text='Terminal', bg='gray', command=terminal).pack(side=LEFT, fill=X, expand=True)
btn_dispatch = Button(frame_ctl, text='Dispatch', bg='gray', command=dispatch).pack(side=LEFT, fill=X, expand=True)
window.mainloop()
  • v3
import os
import re
import time
import paramiko
import fabric
import tarfile
from tkinter import *
from tkinter import messagebox


# TODO: config
height = 420
width = 450
server_password_default = 'gta'
run_file_endswith = '.sh'
run_cmd = 'bash'
connection_timeout = 10
info_connection_timeout = 2
proxy = 'http://child-prc.intel.com:913'
vscode_url = 'https://github.com/cdr/code-server/releases/download/v3.12.0/code-server-3.12.0-linux-amd64.tar.gz'


def get_servers() -> dict:
    servers ={}
    with open('servers.txt', 'r') as f:
        for line in f.readlines():
            line_ = line.split(',')
            line_ = [t.strip() for t in line_]
            name = line_[0]
            url = line_[1]
            url_ = url.split('@')
            user = url_[0]
            ip, port = url_[1].split(':')
            servers[name] = {'user':user, 'ip':ip, 'port':port}
    return servers
servers = get_servers()
# print('servers: ', servers)


def get_envs(env_list_dir='.') -> list:
    envs = []
    for dir in os.listdir(env_list_dir):
        if not os.path.isdir(dir): continue
        if dir.startswith('_'): continue
        envs.append(dir)
    return envs
envs = get_envs()
# print('envs:', envs)


def print_server_info(name):
    server = servers[name]
    return name + ' ' + server['user'] + '@' + server['ip'] + ':' + server['port']


window = Tk()
window.title('autoenv')
screenwidth = window.winfo_screenwidth()
screenheight = window.winfo_screenheight()
alignstr = '%dx%d+%d+%d' % (width, height, (screenwidth-width)/2, (screenheight-height)/2*0.8)
window.geometry(alignstr)
frame_list = Frame()
frame_list.pack(side=TOP, fill=BOTH, expand=True)
list_envs, list_servers = Listbox(frame_list, exportselection=False), Listbox(frame_list, exportselection=False)
scrollnar_envs, scrollnar_servers = Scrollbar(frame_list), Scrollbar(frame_list)
list_envs.config(yscrollcommand=scrollnar_envs.set)
list_servers.config(yscrollcommand=scrollnar_servers.set)
scrollnar_envs.config(command=list_envs.yview)
scrollnar_servers.config(command=list_servers.yview)
list_envs.pack(side=LEFT, fill=BOTH, expand=True)
scrollnar_envs.pack(side=LEFT, fill=Y)
list_servers.pack(side=LEFT, fill=BOTH, expand=True)
scrollnar_servers.pack(side=LEFT, fill=Y)
for name in envs: list_envs.insert('end', name)
for name in servers.keys(): list_servers.insert(END, print_server_info(name))
[list_servers.itemconfig(i, bg='#e0f0ff') for i in range(len(servers.keys())) if i%2]
[list_envs.itemconfig(i, bg='#e0f0ff') for i in range(len(envs)) if i%2]
info = StringVar(value='[please select machine][used/total]')
lb_info = Label(textvariable=info).pack(side=TOP, fill=X)
frame_ctl = Frame(window).pack(side=TOP, fill=X, expand=False)
lb_run = Label(frame_ctl, text='runfile: ').pack(side=LEFT)
runfile_v = StringVar(value='run' + run_file_endswith)
entry_run = Entry(frame_ctl, textvariable=runfile_v, width=12).pack(side=LEFT, fill=X, expand=True)
lb_password = Label(frame_ctl, text='password: ').pack(side=LEFT)
password_v = StringVar(value=server_password_default)
entry_password = Entry(frame_ctl, textvariable=password_v, show='*', width=12).pack(side=LEFT, fill=X, expand=True)


def dispatch():
    try:
        env = list_envs.get(list_envs.curselection()).strip()
        server_name = list_servers.get(list_servers.curselection()).split(' ')[0].strip()
        server = servers[server_name]
    except: return
    notice = messagebox.askokcancel('notice', env + ' -> ' + server_name + '\nrelevant files will be deleted')
    if not notice: return
    print(env, ' -> ', server_name)
    def change_to_lf(endswith):
        for root, _, files in os.walk(env):
            for file in files:
                put_localpath = os.path.realpath(os.path.join(root, file))
                if put_localpath.endswith(endswith):
                    # print('-> lf ' + put_localpath)
                    with open(put_localpath, 'rb') as f: temp = f.read()
                    temp = temp.replace(b'\r\n', b'\n')
                    with open(put_localpath, 'wb') as f: f.write(temp)
    change_to_lf(run_file_endswith)
    # connect
    conn = fabric.Connection(server['ip'], user=server['user'], 
        port=server['port'], connect_kwargs={"password": password_v.get()}, 
        connect_timeout=connection_timeout)
    try: 
        pwd = conn.run('cd ~; pwd').stdout.strip()
    except:
        messagebox.showinfo(title='error', message='connection: ' + server['ip'] + ':' + server['port'])
        conn.close()
        return
    put_remotepath = pwd + '/' + '/'.join(re.split(r'[-]', env))
    try:
        conn.run("mkdir -p {0}; cd {0}".format(put_remotepath))
    except Exception as e:
        messagebox.showinfo(title='error', message=str(e))
        conn.close()
        return
    env_file = env + '-' + str(round(time.time()*1000)) + '.tar.gz'
    try:
        with tarfile.open(env_file, 'w:gz') as tar: tar.add(env, arcname=os.path.basename('.'))
    except Exception as e:
        messagebox.showinfo(title='error', message=str(e))
        conn.close()
        return
    try:
        conn.put(env_file, put_remotepath) # no callback
    except Exception as e:
        messagebox.showinfo(title='error', message=str(e))
        conn.close()
        return
    try:
        conn.run("cd {0}; tar -xzvf {1}; rm -rf {1}".format(put_remotepath, env_file))
    except Exception as e:
        messagebox.showinfo(title='error', message=str(e))
        conn.close()
        os.remove(env_file)
        return
    os.remove(env_file)
    try:
        conn.run("cd {0}; {2} {1}".format(put_remotepath, runfile_v.get(), run_cmd), pty=True, encoding='utf-8')
    except:
        messagebox.showinfo(title='partial success', message=server_name + '\nrunfile failed')
        conn.close()
        return
    messagebox.showinfo(title='success', message=server_name)
    conn.close()


def check():
    try:
        server_name = list_servers.get(list_servers.curselection()).split(' ')[0].strip()
        server = servers[server_name]
    except: return False
    conn = fabric.Connection(server['ip'], user=server['user'], 
        port=int(server['port']), connect_kwargs={"password": password_v.get()}, 
        connect_timeout=info_connection_timeout)
    try: 
        mem = conn.run('free -h | grep Mem', hide='stdout').stdout.strip().split(' ')
        mem = [t for t in mem if len(t)>0]
        disk = conn.run('df ~ -kh | grep G', hide='stdout').stdout.strip().split(' ')
        disk = [t for t in disk if len(t)>0]
    except:
        messagebox.showinfo(title='error', message='connection: ' + server['ip'] + ':' + server['port'])
        conn.close()
        return False
    mem_info = 'mem: ' + mem[2] + '/' + mem[1]
    disk_info = 'disk: ' + disk[2] + '/' + disk[1]
    info.set('[' + server_name + ']' + '[used/total] ' + mem_info + ', ' + disk_info)
    conn.close()
    return True


def terminal():
    try:
        server_name = list_servers.get(list_servers.curselection()).split(' ')[0].strip()
        server = servers[server_name]
    except: return
    try: env = '~/' + list_envs.get(list_envs.curselection()).strip().replace('-', '/')
    except: env = '~'
    os.system('start cmd /k ssh -t -p ' + server['port'] + ' ' + server['user'] + '@' + server['ip'] + ' \" cd ' + env + '; bash --login\"')


def auth():
    try:
        server_name = list_servers.get(list_servers.curselection()).split(' ')[0].strip()
        server = servers[server_name]
    except: return
    conn = fabric.Connection(server['ip'], user=server['user'], 
        port=server['port'], connect_kwargs={"password": password_v.get()}, 
        connect_timeout=connection_timeout)
    try: 
        pwd = conn.run('cd ~; pwd').stdout.strip()
    except:
        messagebox.showinfo(title='error', message='connection: ' + server['ip'] + ':' + server['port'])
        conn.close()
        return
    join = os.path.join
    pub_key = join(join(os.path.expanduser('~'), '.ssh'), 'id_rsa.pub')
    if not os.path.exists(pub_key):
        os.system('ssh-keygen -t rsa')
    remote_file = pwd + '/.ssh/id_rsa' + '-' + str(round(time.time()*1000)) + '.pub'
    cmd = '''
import os
import stat
try: 
    with open('{0}', 'r') as f: lines = f.readlines()
    lines = [t.strip() for t in lines if len(t)>5]
except: lines = []
with open('{1}', 'r') as f: item = f.readlines()[0].strip()
if item not in lines:
    lines.append(item)
    out = '\\n'.join(lines)
    with open('{0}', 'w') as f: f.write(out)
os.remove('{1}')
os.chmod('{0}', stat.S_IRWXU)
'''.format(pwd+'/.ssh/authorized_keys', remote_file)
    try:
        conn.put(pub_key, remote_file) # no callback
        conn.run('python -c \"{}\"'.format(cmd))
    except Exception as e:
        messagebox.showinfo(title='error', message=str(e))
        conn.close()
        return
    conn.close()
    return


def vscode():
    try:
        env = list_envs.get(list_envs.curselection()).strip()
        server_name = list_servers.get(list_servers.curselection()).split(' ')[0].strip()
        server = servers[server_name]
    except: return
    conn = fabric.Connection(server['ip'], user=server['user'], 
        port=server['port'], connect_kwargs={"password": server['password']}, 
        connect_timeout=connection_timeout)
    try: 
        pwd = conn.run('cd ~; pwd').stdout.strip()
    except:
        messagebox.showinfo(title='error', message='connection: ' + server['ip'] + ':' + server['port'])
        conn.close()
        return
    put_remotepath = pwd + '/' + '/'.join(re.split(r'[-]', env))
    __proxy = 'export http_proxy={0}; export https_proxy={0};'.format(proxy)
    __wget = 'wget {0} -O vsc.tar.gz;'.format(vscode_url)
    __tar = 'mkdir ./vsc && tar -zxvf vsc.tar.gz -C ./vsc --strip-components 1; rm -rf vsc.tar.gz;'
    __tmux = 'cd vsc; tmux kill-session -t {0}; tmux new -s {0} -d;'.format(env)
    try:
        conn.run(__proxy + 'mkdir -p {0}; cd {0};'.format(put_remotepath) + __wget + __tar + __tmux)
    except:
        messagebox.showinfo(title='error', message='connection: ' + server['ip'] + ':' + server['port'])
        conn.close()
        return
    port = 8081
    try:
        conn.run('tmux send -t {0} \'PASSWORD={1} ./code-server --host 0.0.0.0 --port {2}\' Enter;'.format(env, server['password'], port))
    except:
        port += 1
    print(port)


btn_info = Button(frame_ctl, text='Info', bg='gray', command=check).pack(side=LEFT, fill=X, expand=True)
btn_auth = Button(frame_ctl, text='Auth', bg='gray', command=auth).pack(side=LEFT, fill=X, expand=True)
btn_terminal = Button(frame_ctl, text='Terminal', bg='gray', command=terminal).pack(side=LEFT, fill=X, expand=True)
btn_dispatch = Button(frame_ctl, text='Dispatch', bg='gray', command=dispatch).pack(side=LEFT, fill=X, expand=True)
window.mainloop()
  • new
'''
server.txt
NAME1, xx@101.11.40.61:22, ddd
NAME2, yy@101.11.40.11:32, sss
'''

import os
import re
import time
import paramiko
import fabric
import tarfile
import pyautogui
pyautogui.FAILSAFE = True
from tkinter import *
from tkinter import messagebox


# TODO: config
run_file_endswith = '.sh'
run_cmd = 'bash'
connection_timeout = 10


def get_servers() -> dict:
    servers ={}
    with open('servers.txt', 'r') as f:
        for line in f.readlines():
            line_ = line.split(',')
            line_ = [t.strip() for t in line_]
            name = line_[0]
            url = line_[1]
            password = line_[2]
            url_ = url.split('@')
            user = url_[0]
            ip, port = url_[1].split(':')
            servers[name] = {'user':user, 'ip':ip, 'port':port, 
                'password':password}
    return servers
servers = get_servers()
# print('servers: ', servers)


def get_envs(env_list_dir='.') -> list:
    envs = []
    for dir in os.listdir(env_list_dir):
        if not os.path.isdir(dir): continue
        envs.append(dir)
    return envs
envs = get_envs()
# print('envs:', envs)


def print_server_info(name):
    server = servers[name]
    return name + ' ' + server['user'] + '@' + server['ip'] + ':' + server['port']


window = Tk()
window.title('autoenv')
width = height = 440
screenwidth = window.winfo_screenwidth()
screenheight = window.winfo_screenheight()
alignstr = '%dx%d+%d+%d' % (width, height, (screenwidth-width)/2, (screenheight-height)/2*0.8)
window.geometry(alignstr)
frame_list = Frame()
frame_list.pack(side=TOP, fill=BOTH, expand=True)
list_envs, list_servers = Listbox(frame_list, exportselection=False), Listbox(frame_list, exportselection=False)
scrollnar_envs, scrollnar_servers = Scrollbar(frame_list), Scrollbar(frame_list)
list_envs.config(yscrollcommand=scrollnar_envs.set)
list_servers.config(yscrollcommand=scrollnar_servers.set)
scrollnar_envs.config(command=list_envs.yview)
scrollnar_servers.config(command=list_servers.yview)
list_envs.pack(side=LEFT, fill=BOTH, expand=True)
scrollnar_envs.pack(side=LEFT, fill=Y)
list_servers.pack(side=LEFT, fill=BOTH, expand=True)
scrollnar_servers.pack(side=LEFT, fill=Y)
for name in envs: list_envs.insert('end', name)
for name in servers.keys(): list_servers.insert(END, print_server_info(name))
[list_servers.itemconfig(i, bg='#e0f0ff') for i in range(len(servers.keys())) if i%2]
[list_envs.itemconfig(i, bg='#e0f0ff') for i in range(len(envs)) if i%2]
info = StringVar(value='[please select machine][used/total]')
lb_info = Label(textvariable=info).pack(side=TOP, fill=X)
frame_ctl = Frame(window).pack(side=TOP, fill=X, expand=False)
lb_run = Label(frame_ctl, text='runfile: ').pack(side=LEFT)
runfile_v = StringVar(value='run' + run_file_endswith)
entry_run = Entry(frame_ctl, textvariable=runfile_v, width=14).pack(side=LEFT, fill=X, expand=True)


def dispatch():
    try:
        env = list_envs.get(list_envs.curselection()).strip()
        server_name = list_servers.get(list_servers.curselection()).split(' ')[0].strip()
        server = servers[server_name]
    except: return
    notice = messagebox.askokcancel('notice', env + ' -> ' + server_name + '\nrelevant files will be deleted')
    if not notice: return
    print(env, ' -> ', server_name)
    def change_to_lf(endswith):
        for root, _, files in os.walk(env):
            for file in files:
                put_localpath = os.path.realpath(os.path.join(root, file))
                if put_localpath.endswith(endswith):
                    # print('-> lf ' + put_localpath)
                    with open(put_localpath, 'rb') as f: temp = f.read()
                    temp = temp.replace(b'\r\n', b'\n')
                    with open(put_localpath, 'wb') as f: f.write(temp)
    change_to_lf(run_file_endswith)
    # connect
    conn = fabric.Connection(server['ip'], user=server['user'], 
        port=server['port'], connect_kwargs={"password": server['password']}, 
        connect_timeout=connection_timeout)
    try: 
        pwd = conn.run('cd ~; pwd').stdout.strip()
    except:
        messagebox.showinfo(title='error', message='connection: ' + server['ip'] + ':' + server['port'])
        conn.close()
        return
    put_remotepath = pwd + '/' + '/'.join(re.split(r'[-]', env))
    if len(put_remotepath) <= len(pwd) + 2:
        messagebox.showinfo(title='error', message='path')
        conn.close()
        return
    try:
        conn.run("mkdir -p {0}; cd {0}".format(put_remotepath))
    except Exception as e:
        messagebox.showinfo(title='error', message=str(e))
        conn.close()
        return
    env_file = env + '-' + str(round(time.time()*1000)) + '.tar.gz'
    try:
        with tarfile.open(env_file, 'w:gz') as tar: tar.add(env, arcname=os.path.basename('.'))
    except Exception as e:
        messagebox.showinfo(title='error', message=str(e))
        conn.close()
        return
    try:
        conn.put(env_file, put_remotepath) # no callback
    except Exception as e:
        messagebox.showinfo(title='error', message=str(e))
        conn.close()
        return
    try:
        conn.run("cd {0}; tar -xzvf {1}; rm -rf {1}".format(put_remotepath, env_file))
    except Exception as e:
        messagebox.showinfo(title='error', message=str(e))
        conn.close()
        os.remove(env_file)
        return
    os.remove(env_file)
    try:
        conn.run("cd {0}; {2} {1}".format(put_remotepath, runfile_v.get(), run_cmd), pty=True, encoding='utf-8')
    except:
        messagebox.showinfo(title='partial success', message=server_name + '\nrunfile failed')
        conn.close()
        return
    messagebox.showinfo(title='success', message=server_name)
    conn.close()


def check():
    try:
        server_name = list_servers.get(list_servers.curselection()).split(' ')[0].strip()
        server = servers[server_name]
    except: return False
    conn = fabric.Connection(server['ip'], user=server['user'], 
        port=int(server['port']), connect_kwargs={"password": server['password']}, 
        connect_timeout=2)
    try: 
        mem = conn.run('free -h | grep Mem', hide='stdout').stdout.strip().split(' ')
        mem = [t for t in mem if len(t)>0]
        disk = conn.run('df ~ -kh | grep G', hide='stdout').stdout.strip().split(' ')
        disk = [t for t in disk if len(t)>0]
    except:
        messagebox.showinfo(title='error', message='connection: ' + server['ip'] + ':' + server['port'])
        conn.close()
        return False
    mem_info = 'mem: ' + mem[2] + '/' + mem[1]
    disk_info = 'disk: ' + disk[2] + '/' + disk[1]
    info.set('[' + server_name + ']' + '[used/total] ' + mem_info + ', ' + disk_info)
    return True


def press(cmd, enter=True):
    pyautogui.write(cmd, interval=0.005)
    if enter: pyautogui.press('enter')


def terminal():
    try:
        server_name = list_servers.get(list_servers.curselection()).split(' ')[0].strip()
        server = servers[server_name]
    except: return
    # if not check(): return
    # try: env = list_envs.get(list_envs.curselection()).strip()
    # except: env = '~'
    os.system('start cmd /k ssh -p ' + server['port'] + ' ' + server['user'] + '@' + server['ip'])
    # time.sleep(1)
    # press(server['password'])
    # env = env.replace('-', '/')
    # if env != '~': press('cd ~/' + env)


btn_info = Button(frame_ctl, text='info', bg='gray', command=check).pack(side=LEFT, fill=X, expand=True)
btn_terminal = Button(frame_ctl, text='terminal', bg='gray', command=terminal).pack(side=LEFT, fill=X, expand=True)
btn_dispatch = Button(frame_ctl, text='Dispatch', bg='gray', command=dispatch).pack(side=LEFT, fill=X, expand=True)
window.mainloop()
  • old
'''
author:xytpai@foxmail.com

autoenv:
|__ _servers_
|   |__ home.bat
|__ autoenv-test
|   |__ requirements.txt
|   |__ run.sh
|__ autoenv.py
|__ requirements.txt

home.bat:
ssh -oPort=6000 xytpai@111.11.111.111

requirements.txt:
paramiko
fabric
selenium

run.sh:
pip uninstall -r requirements.txt
pip install -r requirements.txt
'''

import os
import re
import time
import paramiko
import fabric
import tarfile
from tkinter import *
from tkinter import messagebox


# TODO: config
server_password_default = 'gta'
server_root = '_servers_' # cannot use ./servers
server_file_endswith = '.bat'
run_file_endswith = '.sh'
run_cmd = 'bash'
connection_timeout = 10


def get_servers(server_root, server_file_endswith) -> dict:
    servers = {}
    for root, _, files in os.walk(server_root):
        for file in files:
            path = os.path.join(root, file)
            if path.endswith(server_file_endswith):
                with open(path, 'r') as f:
                    items = re.split(r'[ =]', f.readline())
                    port = 22
                    for item in items:
                        item = item.strip()
                        if '@' in item:
                            item = item.split('@')
                            user = item[0]
                            ip = item[1]
                        else:
                            try: port = int(item)
                            except: continue
                    name = file[:len(file)-len(server_file_endswith)]
                    servers[name] = {'user':user, 'ip':ip, 'port':port}
    return servers
servers = get_servers(server_root, server_file_endswith)
# print('servers: ', servers)


def get_envs(env_list_dir='.', exclude_dirs=[server_root]) -> list:
    envs = []
    for dir in os.listdir(env_list_dir):
        if not os.path.isdir(dir): continue
        if dir in exclude_dirs: continue
        envs.append(dir)
    return envs
envs = get_envs()
# print('envs:', envs)


window = Tk()
window.title('autoenv')
width = height = 440
screenwidth = window.winfo_screenwidth()
screenheight = window.winfo_screenheight()
alignstr = '%dx%d+%d+%d' % (width, height, (screenwidth-width)/2, (screenheight-height)/2*0.8)
window.geometry(alignstr)
frame_list = Frame()
frame_list.pack(side=TOP, fill=BOTH, expand=True)
list_envs, list_servers = Listbox(frame_list, exportselection=False), Listbox(frame_list, exportselection=False)
scrollnar_envs, scrollnar_servers = Scrollbar(frame_list), Scrollbar(frame_list)
list_envs.config(yscrollcommand=scrollnar_envs.set)
list_servers.config(yscrollcommand=scrollnar_servers.set)
scrollnar_envs.config(command=list_envs.yview)
scrollnar_servers.config(command=list_servers.yview)
list_envs.pack(side=LEFT, fill=BOTH, expand=True)
scrollnar_envs.pack(side=LEFT, fill=Y)
list_servers.pack(side=LEFT, fill=BOTH, expand=True)
scrollnar_servers.pack(side=LEFT, fill=Y)
for name in envs: list_envs.insert('end', name)
for name in servers.keys(): list_servers.insert('end', name+' '+servers[name]['ip']+':'+str(servers[name]['port']))
[list_servers.itemconfig(i, bg='#e0f0ff') for i in range(len(servers.keys())) if i%2]
[list_envs.itemconfig(i, bg='#e0f0ff') for i in range(len(envs)) if i%2]
info = StringVar(value='[please select machine][used/total]')
lb_info = Label(textvariable=info).pack(side=TOP, fill=X)
frame_ctl = Frame(window).pack(side=TOP, fill=X, expand=False)
lb_run = Label(frame_ctl, text='runfile: ').pack(side=LEFT)
runfile_v = StringVar(value='run' + run_file_endswith)
entry_run = Entry(frame_ctl, textvariable=runfile_v, width=14).pack(side=LEFT, fill=X, expand=True)
lb_password = Label(frame_ctl, text='password: ').pack(side=LEFT)
password_v = StringVar(value=server_password_default)
entry_password = Entry(frame_ctl, textvariable=password_v, show='*', width=14).pack(side=LEFT, fill=X, expand=True)


def dispatch():
    try:
        env = list_envs.get(list_envs.curselection()).strip()
        server_name = list_servers.get(list_servers.curselection()).split(' ')[0].strip()
    except: return
    notice = messagebox.askokcancel('notice', env + ' -> ' + server_name + '\noriginal folder will be removed')
    if not notice: return
    print(env, ' -> ', server_name)
    def change_to_lf(endswith):
        for root, _, files in os.walk(env):
            for file in files:
                put_localpath = os.path.realpath(os.path.join(root, file))
                if put_localpath.endswith(endswith):
                    # print('-> lf ' + put_localpath)
                    with open(put_localpath, 'rb') as f: temp = f.read()
                    temp = temp.replace(b'\r\n', b'\n')
                    with open(put_localpath, 'wb') as f: f.write(temp)
    change_to_lf(run_file_endswith)
    # connect
    conn = fabric.Connection(servers[server_name]['ip'], user=servers[server_name]['user'], 
        port=servers[server_name]['port'], 
        connect_kwargs={"password": password_v.get()}, connect_timeout=connection_timeout)
    try: 
        pwd = conn.run('cd ~; pwd').stdout.strip()
    except:
        messagebox.showinfo(title='error', message='connection: ' + servers[server_name]['ip'])
        conn.close()
        return
    put_remotepath = pwd + '/' + '/'.join(re.split(r'[-]', env))
    if len(put_remotepath) <= len(pwd) + 2:
        messagebox.showinfo(title='error', message='path')
        conn.close()
        return
    try:
        conn.run("mkdir -p {0}; cd {0}; rm -rf *".format(put_remotepath))
    except Exception as e:
        messagebox.showinfo(title='error', message=str(e))
        conn.close()
        return
    env_file = env + '-' + str(round(time.time()*1000)) + '.tar.gz'
    try:
        with tarfile.open(env_file, 'w:gz') as tar: tar.add(env, arcname=os.path.basename('.'))
    except Exception as e:
        messagebox.showinfo(title='error', message=str(e))
        conn.close()
        return
    try:
        conn.put(env_file, put_remotepath) # no callback
    except Exception as e:
        messagebox.showinfo(title='error', message=str(e))
        conn.close()
        return
    try:
        conn.run("cd {0}; tar -xzvf {1}; rm -rf {1}".format(put_remotepath, env_file))
    except Exception as e:
        messagebox.showinfo(title='error', message=str(e))
        conn.close()
        os.remove(env_file)
        return
    os.remove(env_file)
    try:
        conn.run("cd {0}; {2} {1}".format(put_remotepath, runfile_v.get(), run_cmd), pty=True, encoding='utf-8')
    except:
        messagebox.showinfo(title='partial success', message=server_name + '\nrunfile failed')
        conn.close()
        return
    messagebox.showinfo(title='success', message=server_name)
    conn.close()


def check():
    try:
        server_name = list_servers.get(list_servers.curselection()).split(' ')[0].strip()
    except: return
    conn = fabric.Connection(servers[server_name]['ip'], user=servers[server_name]['user'], 
        port=servers[server_name]['port'], 
        connect_kwargs={"password": password_v.get()}, connect_timeout=connection_timeout)
    try: 
        mem = conn.run('free -h | grep Mem', hide='stdout').stdout.strip().split(' ')
        mem = [t for t in mem if len(t)>0]
        disk = conn.run('df ~ -kh | grep G', hide='stdout').stdout.strip().split(' ')
        disk = [t for t in disk if len(t)>0]
    except:
        messagebox.showinfo(title='error', message='connection: ' + servers[server_name]['ip'])
        conn.close()
        return
    mem_info = 'mem: ' + mem[2] + '/' + mem[1]
    disk_info = 'disk: ' + disk[2] + '/' + disk[1]
    info.set('[' + server_name + ']' + '[used/total] ' + mem_info + ', ' + disk_info)


def terminal():
    try:
        server_name = list_servers.get(list_servers.curselection()).split(' ')[0].strip()
    except: return
    os.system(os.path.join(server_root, server_name + server_file_endswith))


btn_info = Button(frame_ctl, text='info', bg='gray', command=check).pack(side=LEFT, fill=X, expand=True)
btn_terminal = Button(frame_ctl, text='terminal', bg='gray', command=terminal).pack(side=LEFT, fill=X, expand=True)
btn_dispatch = Button(frame_ctl, text='Dispatch', bg='gray', command=dispatch).pack(side=LEFT, fill=X, expand=True)
window.mainloop()
posted @ 2021-10-24 00:21  xytpai  阅读(50)  评论(0编辑  收藏  举报