一、目的

从跳板机登录服务器是每次登录线上服务器都有的操作,如果每次都是手动ssh username@ip的形式就显得低效和繁琐,如果登录跳板机之后,自动执行一个命令,显示自己有登录权限的系统,选择系统后,就会列出该系统的所有节点ip,选择ip后就会自动登录到对应的机器就很方便了。带着这个想法就编写了本文的python脚本。



二、代码实施

2.1、python代码

文件名:smart_ssh,运行环境:python 2.7

#!/usr/bin/python

from optparse import OptionParser

import  pexpect
import  getpass
import  requests
import  json

def connect_to_server(ip):
    if(ip == None):
		return None
    ssh_cmd = "ssh iwill@{}".format(ip)
    child = pexpect.spawn(ssh_cmd)
    child.interact()

def list_authorized_apps(username, part_app_name):
    try:
		url = "http://localhost:8080/cmdb/list-app?username=%s&app=%s" % (username ,part_app_name)
		if part_app_name == None:
			url = "http://localhost:8080/cmdb/list-app?username=%s" % (username)
		resp = requests.get(url)
		if(resp.status_code != 200):
			print("request app list from cmdb fail !")
			return None
		resp_content = json.loads(resp.text)
		if(resp_content['success'] =='true'):
			result = resp_content['data']
			return result
		else:
			print("request app list from cmdb fail !")
			return None
    except:
		print("cmdb service is not available !")
		return None

def list_authorized_ips(username, app_name):
    if app_name == None:
		return None
    try:
		url = "http://localhost:8080/cmdb/list-ip?username=%s&artifact_id=%s" % (username, app_name)    
		resp = requests.get(url)
		if(resp.status_code != 200):
			print("request server ip list from cmdb fail !")
			return None
		resp_content = json.loads(resp.text)
		if(resp_content['success']=='true'):	
			result = resp_content['data']
			return result
		else:
			print("request ip list from cmdb fail !")
			return None
    except:
		print("cmdb service is not available !")
		return None

def show_app_list(part_app_name, app_name_list):
    if(app_name_list == None):
		return None
    print("all application like %s list below" %(part_app_name))
    index = 0 
    for app_name in app_name_list:
        print("  %d : %s " %(index ,app_name)) 
        index = index + 1
    show_msg = 'please select app (0...%d) : '%(index-1)
    try:
		app_index = input(show_msg)
		if(app_index < 0 or app_index > index):
			print("you input wrong number ! ")
			return None
		selected_app = app_name_list[app_index]
		return selected_app 
    except:
		print("you input wrong number ! ")
		return None

def show_ip_list(app_name, app_ip_list):
    if(app_ip_list == None):
		return None
    print("all ips of the application %s list below" %(app_name))
    index = 0 
    for app_ip in app_ip_list:
    	index = index + 1
        print("  %d : %s " %(index ,app_ip)) 
    show_msg = 'please select ip (1...%d) : '%index
    try:
		id_index = input(show_msg)
		if(id_index <= 0 or id_index > index):
			print("you input wrong number ! ")
			return None
		selected_ip = app_ip_list[id_index-1]
		return selected_ip   
    except:
		print("you input wrong number ! ")
		return None

def main():
    parser = OptionParser()
    parser.add_option('-a', '--app', dest='app', action='store', type='string', help='the application id in the auv')
    (options, args) = parser.parse_args()
    
    username = getpass.getuser()
    app_name_list = list_authorized_apps(username, options.app)

    if app_name_list == None:
		exit()
    elif (len(app_name_list) == 0 and options.app == None):
		print("you are not authorized to any app ,use jumper directly")
		exit()
    elif len(app_name_list) == 0 :
    	print("no app name like %s, use jumper directly" %(options.app))
    	exit()
    elif (len(app_name_list) == 1 and app_name_list[0] == options.app):
    	app_ip_list = list_authorized_ips(username, options.app)
    	selected_ip = show_ip_list(options.app, app_ip_list)
    	connect_to_server(selected_ip)
    else :
        jumper_name = 'no thanks ,I will use jumper'
        app_name_list.insert(0,jumper_name)
    	selected_app = show_app_list(options.app, app_name_list)
        if(selected_app == jumper_name) :
            exit()
    	app_ip_list = list_authorized_ips(username, selected_app)
    	selected_ip = show_ip_list(selected_app, app_ip_list)
    	connect_to_server(selected_ip)
    exit()
if __name__== '__main__':
   main()

2.2、mock的cmdb接口代码

@RestController
@RequestMapping("cmdb")
public class CmdbController {

    @GetMapping("list-app")
    public String listApp(@RequestParam(value = "username") String username, @RequestParam(value = "app", required = false) String app) {
        Result result = new Result("true");
        List<String> partApps = new ArrayList<>();
        partApps.add("axx-app");
        partApps.add("bxx-app");
        partApps.add("cxx-app");
        result.setData(partApps);
        return new Gson().toJson(result);

    }

    @GetMapping("list-ip")
    public String listIp(@RequestParam(value = "username") String username, @RequestParam(value = "artifact_id", required = false) String artifact_id) {
        Result result = new Result("true");
        List<String> ips = new ArrayList<>();
        ips.add("192.168.0.101");
        ips.add("192.168.0.102");
        ips.add("192.168.0.103");
        result.setData(ips);
        return new Gson().toJson(result);
    }
}

2.3、原理

程序会和cmdb交互两次,第一次交互去获取有登录权限的应用列表或者部分应用列表;第二次会去获取指定应用的ip列表,当用户选择了指定ip后,就会使用pexpect连接到对应的机器。

2.3、系统命令制作

将文件smart_ssh放到/usr/local/bin下,然后suorce一下/etc/profile,在命令行就可以运行smart_ssh了

2.4、用法

2.4.1、不带参数

直接使用smart_ssh时,会列举出当前登录用户所有有登录权限的应用列表,用户选择一个应用后,会列举出该应用的所有ip,用户选择一个ip后,程序就会自动登录到对应的机器。

2.4.2、带参数,模糊匹配

使用smart_ssh -a part_app_name,会列举出当前登录用户所有有登录权限且应用名模糊匹配part_app_name的应用列表,用户选择一个应用后,会列举出该应用的所有ip,用户选择一个ip后,程序就会自动登录到对应的机器。

2.4.3、完全匹配

使用smart_ssh -a app_name,会列举出当前登录用户所有有登录权限且应用名匹配app_name的应用列表进行校验,然后会直接列举出应用的所有ip,用户选择一个ip后,程序就会自动登录到对应的机器。

2.4、运行效果

登录服务器redis 登录服务器命令_json



三、感想

1、工作中,有很多可以挺高工作效率的方法,其中完备的工具就是其中之一。

2、很多事情,不是看到了希望才去做,而是做了才有希望。