开发堡垒机之前,先来学习Python的paramiko模块,该模块机遇SSH用于连接远程服务器并执行相关操作
SSHClient
用于连接远程服务器并执行基本命令
基于用户名密码连接:

1 import paramiko
2
3 # 创建SSH对象
4 ssh = paramiko.SSHClient()
5 # 允许连接不在know_hosts文件中的主机
6 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
7 # 连接服务器
8 ssh.connect(hostname='c1.salt.com', port=22, username='wupeiqi', password='123')
9
10 # 执行命令
11 stdin, stdout, stderr = ssh.exec_command('df')
12 # 获取命令结果
13 result = stdout.read()
14
15 # 关闭连接
16 ssh.close()

1 import paramiko
2
3 transport = paramiko.Transport(('hostname', 22))
4 transport.connect(username='wupeiqi', password='123')
5
6 ssh = paramiko.SSHClient()
7 ssh._transport = transport
8
9 stdin, stdout, stderr = ssh.exec_command('df')
10 print stdout.read()
11
12 transport.close()
基于公钥密钥连接:

1 import paramiko
2
3 private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')
4
5 # 创建SSH对象
6 ssh = paramiko.SSHClient()
7 # 允许连接不在know_hosts文件中的主机
8 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
9 # 连接服务器
10 ssh.connect(hostname='c1.salt.com', port=22, username='wupeiqi', key=private_key)
11
12 # 执行命令
13 stdin, stdout, stderr = ssh.exec_command('df')
14 # 获取命令结果
15 result = stdout.read()
16
17 # 关闭连接
18 ssh.close()

1 import paramiko
2
3 private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')
4
5 transport = paramiko.Transport(('hostname', 22))
6 transport.connect(username='wupeiqi', pkey=private_key)
7
8 ssh = paramiko.SSHClient()
9 ssh._transport = transport
10
11 stdin, stdout, stderr = ssh.exec_command('df')
12
13 transport.close()

1 import paramiko
2 from io import StringIO
3
4 key_str = """-----BEGIN RSA PRIVATE KEY-----
5 MIIEpQIBAAKCAQEAq7gLsqYArAFco02/55IgNg0r7NXOtEM3qXpb/dabJ5Uyky/8
6 NEHhFiQ7deHIRIuTW5Zb0kD6h6EBbVlUMBmwJrC2oSzySLU1w+ZNfH0PE6W6fans
7 H80whhuc/YgP+fjiO+VR/gFcqib8Rll5UfYzf5H8uuOnDeIXGCVgyHQSmt8if1+e
8 7hn1MVO1Lrm9Fco8ABI7dyv8/ZEwoSfh2C9rGYgA58LT1FkBRkOePbHD43xNfAYC
9 tfLvz6LErMnwdOW4sNMEWWAWv1fsTB35PAm5CazfKzmam9n5IQXhmUNcNvmaZtvP
10 c4f4g59mdsaWNtNaY96UjOfx83Om86gmdkKcnwIDAQABAoIBAQCnDBGFJuv8aA7A
11 ZkBLe+GN815JtOyye7lIS1n2I7En3oImoUWNaJEYwwJ8+LmjxMwDCtAkR0XwbvY+
12 c+nsKPEtkjb3sAu6I148RmwWsGncSRqUaJrljOypaW9dS+GO4Ujjz3/lw1lrxSUh
13 IqVc0E7kyRW8kP3QCaNBwArYteHreZFFp6XmtKMtXaEA3saJYILxaaXlYkoRi4k8
14 S2/K8aw3ZMR4tDCOfB4o47JaeiA/e185RK3A+mLn9xTDhTdZqTQpv17/YRPcgmwz
15 zu30fhVXQT/SuI0sO+bzCO4YGoEwoBX718AWhdLJFoFq1B7k2ZEzXTAtjEXQEWm6
16 01ndU/jhAasdfasdasdfasdfa3eraszxqwefasdfadasdffsFIfAsjQb4HdkmHuC
17 OeJrJOd+CYvdEeqJJNnF6AbHyYHIECkj0Qq1kEfLOEsqzd5nDbtkKBte6M1trbjl
18 HtJ2Yb8w6o/q/6Sbj7wf/cW3LIYEdeVCjScozVcQ9R83ea05J+QOAr4nAoGBAMaq
19 UzLJfLNWZ5Qosmir2oHStFlZpxspax/ln7DlWLW4wPB4YJalSVovF2Buo8hr8X65
20 lnPiE41M+G0Z7icEXiFyDBFDCtzx0x/RmaBokLathrFtI81UCx4gQPLaSVNMlvQA
21 539GsubSrO4LpHRNGg/weZ6EqQOXvHvkUkm2bDDJAoGATytFNxen6GtC0ZT3SRQM
22 WYfasdf3xbtuykmnluiofasd2sfmjnljkt7khghmghdasSDFGQfgaFoKfaawoYeH
23 C2XasVUsVviBn8kPSLSVBPX4JUfQmA6h8HsajeVahxN1U9e0nYJ0sYDQFUMTS2t8
24 RT57+WK/0ONwTWHdu+KnaJECgYEAid/ta8LQC3p82iNAZkpWlGDSD2yb/8rH8NQg
25 9tjEryFwrbMtfX9qn+8srx06B796U3OjifstjJQNmVI0qNlsJpQK8fPwVxRxbJS/
26 pMbNICrf3sUa4sZgDOFfkeuSlgACh4cVIozDXlR59Z8Y3CoiW0uObEgvMDIfenAj
27 98pl3ZkCgYEAj/UCSni0dwX4pnKNPm6LUgiS7QvIgM3H9piyt8aipQuzBi5LUKWw
28 DlQC4Zb73nHgdREtQYYXTu7p27Bl0Gizz1sW2eSgxFU8eTh+ucfVwOXKAXKU5SeI
29 +MbuBfUYQ4if2N/BXn47+/ecf3A4KgB37Le5SbLDddwCNxGlBzbpBa0=
30 -----END RSA PRIVATE KEY-----"""
31
32 private_key = paramiko.RSAKey(file_obj=StringIO(key_str))
33 transport = paramiko.Transport(('10.0.1.40', 22))
34 transport.connect(username='wupeiqi', pkey=private_key)
35
36 ssh = paramiko.SSHClient()
37 ssh._transport = transport
38
39 stdin, stdout, stderr = ssh.exec_command('df')
40 result = stdout.read()
41
42 transport.close()
43
44 print(result)
SFTPClient
用于连接远程服务器并执行上传下载
基于用户名密码上传下载

1 import paramiko
2
3 transport = paramiko.Transport(('hostname',22))
4 transport.connect(username='wupeiqi',password='123')
5
6 sftp = paramiko.SFTPClient.from_transport(transport)
7 # 将location.py 上传至服务器 /tmp/test.py
8 sftp.put('/tmp/location.py', '/tmp/test.py')
9 # 将remove_path 下载到本地 local_path
10 sftp.get('remove_path', 'local_path')
11
12 transport.close()
基于公钥密钥上传下载

1 import paramiko
2
3 private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')
4
5 transport = paramiko.Transport(('hostname', 22))
6 transport.connect(username='wupeiqi', pkey=private_key )
7
8 sftp = paramiko.SFTPClient.from_transport(transport)
9 # 将location.py 上传至服务器 /tmp/test.py
10 sftp.put('/tmp/location.py', '/tmp/test.py')
11 # 将remove_path 下载到本地 local_path
12 sftp.get('remove_path', 'local_path')
13
14 transport.close()

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import paramiko
import uuid
class Haproxy(object):
def __init__(self):
self.host = '172.16.103.191'
self.port = 22
self.username = 'wupeiqi'
self.pwd = '123'
self.__k = None
def create_file(self):
file_name = str(uuid.uuid4())
with open(file_name,'w') as f:
f.write('sb')
return file_name
def run(self):
self.connect()
self.upload()
self.rename()
self.close()
def connect(self):
transport = paramiko.Transport((self.host,self.port))
transport.connect(username=self.username,password=self.pwd)
self.__transport = transport
def close(self):
self.__transport.close()
def upload(self):
# 连接,上传
file_name = self.create_file()
sftp = paramiko.SFTPClient.from_transport(self.__transport)
# 将location.py 上传至服务器 /tmp/test.py
sftp.put(file_name, '/home/wupeiqi/tttttttttttt.py')
def rename(self):
ssh = paramiko.SSHClient()
ssh._transport = self.__transport
# 执行命令
stdin, stdout, stderr = ssh.exec_command('mv /home/wupeiqi/tttttttttttt.py /home/wupeiqi/ooooooooo.py')
# 获取命令结果
result = stdout.read()
ha = Haproxy()
ha.run()
堡垒机的实现
实现思路:

堡垒机执行流程:
- 管理员为用户在服务器上创建账号(将公钥放置服务器,或者使用用户名密码)
- 用户登陆堡垒机,输入堡垒机用户名密码,现实当前用户管理的服务器列表
- 用户选择服务器,并自动登陆
- 执行操作并同时将用户操作记录
注:配置.brashrc实现ssh登陆后自动执行脚本,如:/usr/bin/python /home/wupeiqi/menu.py
实现过程
步骤一,实现用户登陆
1 import getpass
2
3 user = raw_input('username:')
4 pwd = getpass.getpass('password')
5 if user == 'alex' and pwd == '123':
6 print ('登陆成功')
7 else:
8 print '(登陆失败')
步骤二,根据用户获取相关服务器列表
1 dic = {
2 'alex': [
3 '172.16.103.189',
4 'c10.puppet.com',
5 'c11.puppet.com',
6 ],
7 'eric': [
8 'c100.puppet.com',
9 ]
10 }
11
12 host_list = dic['alex']
13
14 print 'please select:'
15 for index, item in enumerate(host_list, 1):
16 print index, item
17
18 inp = raw_input('your select (No):')
19 inp = int(inp)
20 hostname = host_list[inp-1]
21 port = 22
步骤三,根据用户名、私钥登陆服务器
1 tran = paramiko.Transport((hostname, port,))
2 tran.start_client()
3 default_path = os.path.join(os.environ['HOME'], '.ssh', 'id_rsa')
4 key = paramiko.RSAKey.from_private_key_file(default_path)
5 tran.auth_publickey('wupeiqi', key)
6
7 # 打开一个通道
8 chan = tran.open_session()
9 # 获取一个终端
10 chan.get_pty()
11 # 激活器
12 chan.invoke_shell()
13
14 #########
15 # 利用sys.stdin,肆意妄为执行操作
16 # 用户在终端输入内容,并将内容发送至远程服务器
17 # 远程服务器执行命令,并将结果返回
18 # 用户终端显示内容
19 #########
20
21 chan.close()
22 tran.close()

1 while True: 2 # 监视用户输入和服务器返回数据 3 # sys.stdin 处理用户输入 4 # chan 是之前创建的通道,用于接收服务器返回信息 5 readable, writeable, error = select.select([chan, sys.stdin, ],[],[],1) 6 if chan in readable: 7 try: 8 x = chan.recv(1024) 9 if len(x) == 0: 10 print '\r\n*** EOF\r\n', 11 break 12 sys.stdout.write(x) 13 sys.stdout.flush() 14 except socket.timeout: 15 pass 16 if sys.stdin in readable: 17 inp = sys.stdin.readline() 18 chan.sendall(inp)

1 # 获取原tty属性 2 oldtty = termios.tcgetattr(sys.stdin) 3 try: 4 # 为tty设置新属性 5 # 默认当前tty设备属性: 6 # 输入一行回车,执行 7 # CTRL+C 进程退出,遇到特殊字符,特殊处理。 8 9 # 这是为原始模式,不认识所有特殊符号 10 # 放置特殊字符应用在当前终端,如此设置,将所有的用户输入均发送到远程服务器 11 tty.setraw(sys.stdin.fileno()) 12 chan.settimeout(0.0) 13 14 while True: 15 # 监视 用户输入 和 远程服务器返回数据(socket) 16 # 阻塞,直到句柄可读 17 r, w, e = select.select([chan, sys.stdin], [], [], 1) 18 if chan in r: 19 try: 20 x = chan.recv(1024) 21 if len(x) == 0: 22 print '\r\n*** EOF\r\n', 23 break 24 sys.stdout.write(x) 25 sys.stdout.flush() 26 except socket.timeout: 27 pass 28 if sys.stdin in r: 29 x = sys.stdin.read(1) 30 if len(x) == 0: 31 break 32 chan.send(x) 33 34 finally: 35 # 重新设置终端属性 36 termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)

1 def windows_shell(chan):
2 import threading
3
4 sys.stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.\r\n\r\n")
5
6 def writeall(sock):
7 while True:
8 data = sock.recv(256)
9 if not data:
10 sys.stdout.write('\r\n*** EOF ***\r\n\r\n')
11 sys.stdout.flush()
12 break
13 sys.stdout.write(data)
14 sys.stdout.flush()
15
16 writer = threading.Thread(target=writeall, args=(chan,))
17 writer.start()
18
19 try:
20 while True:
21 d = sys.stdin.read(1)
22 if not d:
23 break
24 chan.send(d)
25 except EOFError:
26 # user hit ^Z or F6
27 pass
注:密码验证 t.auth_password(username, pw)
详见:paramiko源码demo
数据库操作
Python 操作 Mysql 模块的安装
1 linux: 2 yum install MySQL-python 3 4 window: 5 http://files.cnblogs.com/files/wupeiqi/py-mysql-win.zip
SQL基本使用
1、数据库操作
1 show databases; 2 use [databasename]; 3 create database [name];
2、数据表操作
1 show tables; 2 3 create table students 4 ( 5 id int not null auto_increment primary key, 6 name char(8) not null, 7 sex char(4) not null, 8 age tinyint unsigned not null, 9 tel char(13) null default "-" 10 );

1 CREATE TABLE `wb_blog` ( 2 `id` smallint(8) unsigned NOT NULL, 3 `catid` smallint(5) unsigned NOT NULL DEFAULT '0', 4 `title` varchar(80) NOT NULL DEFAULT '', 5 `content` text NOT NULL, 6 PRIMARY KEY (`id`), 7 UNIQUE KEY `catename` (`catid`) 8 ) ;
3、数据操作
1 insert into students(name,sex,age,tel) values('alex','man',18,'151515151')
2
3 delete from students where id =2;
4
5 update students set name = 'sb' where id =1;
6
7 select * from students
4、其他
1 主键 2 外键 3 左右连接
Python MySQL API
一、插入数据
1 import MySQLdb
2
3 conn = MySQLdb.connect(host='127.0.0.1',user='root',passwd='1234',db='mydb')
4
5 cur = conn.cursor()
6
7 reCount = cur.execute('insert into UserInfo(Name,Address) values(%s,%s)',('alex','usa'))
8 # reCount = cur.execute('insert into UserInfo(Name,Address) values(%(id)s, %(name)s)',{'id':12345,'name':'wupeiqi'})
9
10 conn.commit()
11
12 cur.close()
13 conn.close()
14
15 print reCount

1 import MySQLdb
2
3 conn = MySQLdb.connect(host='127.0.0.1',user='root',passwd='1234',db='mydb')
4
5 cur = conn.cursor()
6
7 li =[
8 ('alex','usa'),
9 ('sb','usa'),
10 ]
11 reCount = cur.executemany('insert into UserInfo(Name,Address) values(%s,%s)',li)
12
13 conn.commit()
14 cur.close()
15 conn.close()
16
17 print reCount
注意:cur.lastrowid
二、删除数据
1 import MySQLdb
2
3 conn = MySQLdb.connect(host='127.0.0.1',user='root',passwd='1234',db='mydb')
4
5 cur = conn.cursor()
6
7 reCount = cur.execute('delete from UserInfo')
8
9 conn.commit()
10
11 cur.close()
12 conn.close()
13
14 print reCount
三、修改数据
1 import MySQLdb
2
3 conn = MySQLdb.connect(host='127.0.0.1',user='root',passwd='1234',db='mydb')
4
5 cur = conn.cursor()
6
7 reCount = cur.execute('update UserInfo set Name = %s',('alin',))
8
9 conn.commit()
10 cur.close()
11 conn.close()
12
13 print reCount
四、查数据
1 # ############################## fetchone/fetchmany(num) ##############################
2
3 import MySQLdb
4
5 conn = MySQLdb.connect(host='127.0.0.1',user='root',passwd='1234',db='mydb')
6 cur = conn.cursor()
7
8 reCount = cur.execute('select * from UserInfo')
9
10 print cur.fetchone()
11 print cur.fetchone()
12 cur.scroll(-1,mode='relative')
13 print cur.fetchone()
14 print cur.fetchone()
15 cur.scroll(0,mode='absolute')
16 print cur.fetchone()
17 print cur.fetchone()
18
19 cur.close()
20 conn.close()
21
22 print reCount
23
24
25
26 # ############################## fetchall ##############################
27
28 import MySQLdb
29
30 conn = MySQLdb.connect(host='127.0.0.1',user='root',passwd='1234',db='mydb')
31 #cur = conn.cursor(cursorclass = MySQLdb.cursors.DictCursor)
32 cur = conn.cursor()
33
34 reCount = cur.execute('select Name,Address from UserInfo')
35
36 nRet = cur.fetchall()
37
38 cur.close()
39 conn.close()
40
41 print reCount
42 print nRet
43 for i in nRet:
44 print i[0],i[1]
