高效登录远端机器

背景

工作中经常需要ssh到服务器上去操作,并且有些时候可能还会需要如下的情况:

  1. 通过跳板机登录到具体的应用服务器
  2. 用普通账号登录后再切换到admin用户操作

困惑

  1. 登录服务器需要记住一堆的服务器ip,目前这个已经有很多的解决方案了
  2. 如果在ssh连接建立之后进行更复杂的交互逻辑,这个一直是个困惑。

解决问题

expect

expect使用比较广泛,网上的教程也很多,做一些简单的当前用户操作完全没有问题

#!/usr/bin/expect


# 参数1:远程host;参数2:远程password
if { $argc != 1   } {
    send_user "Usage: host\n"
    exit
}

set host [lindex $argv 0]
set USER xxx
set PASSWORD xxx

# Start the session
catch {spawn ssh -l $USER $host}

expect {
    "*assword*"
        {send "$PASSWORD\n"}

}
expect "Last*" { interact   }

但是有个致命的问题,不能解决上述我说的第二点问题,不能有ssh嵌套或者切换用户。

pexpect

后来很有幸发现了python的工具包:https://github.com/pexpect/pexpect ; 发现可以扩展的空间非常大

#!/usr/bin/env python3

import pexpect
import sys

# print(sys.argv[1])
host = sys.argv[1]
user = sys.argv[2]
password = sys.argv[3]

child = pexpect.spawn('ssh %s@%s' % (user, host))
# 设置字符窗口大小,非常重要,不然会有换行和覆盖问题
child.setwinsize(400,400)

index = child.expect(['password', user, pexpect.EOF, pexpect.TIMEOUT])
# print("index %d" % (index) )
if index == 0:
    child.sendline(password)
elif index == 1:
    child.sendline(password)
elif index == 2:
        print("EOF")
    # child.sendline("\n")
elif index == 3:
        print("timeout")
    # child.sendline("\n")

 # Send the characters pass123 and "enter"
child.expect(user, timeout=120)

child.sendline('cd /home/admin')

child.sendline('sudo su admin')

# child.expect('[sudo]')

child.sendline(password)

child.interact()

完全根据输入,输出的字符来匹配,调试起来非常方便。

workflow

由于平时workflow用的比较多,所以顺便把整个流程在alfred里玩下:

服务器ip列表查询功能

#!/usr/bin/python
# encoding: utf-8

import sys

from workflow import Workflow

def main(wf):
    # The Workflow instance will be passed to the function
    # you call from `Workflow.run`. Not so useful, as
    # the `wf` object created in `if __name__ ...` below is global.
    #
    # Your imports go here if you want to catch import errors (not a bad idea)
    # or if the modules/packages are in a directory added via `Workflow(libraries=...)`
    # import somemodule
    # import anothermodule
    # Get args from Workflow, already in normalized Unicode
    # args = wf.args
    # print args

    query = None  # Ensure `query` is initialised
    if len(wf.args):
        query = wf.args[0]

    ipList = []
    with open('iplist.txt') as fileObj:
        for line in fileObj:
            ipList.append(line.strip())


    if query :
        ipList = wf.filter(query,ipList, match_on=32)

    if len(ipList) == 0 :
        ipList.append(query)


    for ip in ipList:
        wf.add_item(title=ip, arg=ip, autocomplete=ip, valid=True)
    # Send output to Alfred. You can only call this once.
    # Well, you *can* call it multiple times, but Alfred won't be listening
    # any more...
    wf.send_feedback()


if __name__ == '__main__':
    # Create a global `Workflow` object
    wf = Workflow()
    # Call your entry function via `Workflow.run()` to enable its helper
    # functions, like exception catching, ARGV normalization, magic
    # arguments etc.
    # wf.run(main)
    sys.exit(wf.run(main))

调用iterm2 启动 pexpect

on alfred_script(q)

tell application "iTerm"
  try
    tell current window
      create tab with default profile
    end tell
  on error msg
    display dialog msg
    create window with default profile
    tell current window
      create tab with default profile
    end tell
  end try
  tell current tab of current window
    select
    tell the current session
      write text "sussh " & q
    end tell
  end tell
end tell
end alfred_script
image.png

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 123,345评论 18 134
  • 请不要转载 背景介绍 Expect 程序主要用于人机对话的模拟,就是那种系统提问,人来回答 yes/no ,或者账...
    羽风之歌阅读 47,431评论 12 42
  • 前言 饱经Xcode7.3代码不提示的摧残,Xcode 8正式版刚出来,就跃跃欲试的更新了,终于下完安装好,泪奔!...
    LeeJoy阅读 2,274评论 2 4
  • 一请再等我一秒钟 早上小宝在餐椅上端起自己的小碗,喝粥,碗里面的粥没有多少了,所以看上去宝贝吃得特别的卖力气甚至有...
    明星123阅读 74评论 0 0