标签:
I. SQLalchemy联表操作
1. 一对多
class Group(Base): # 一对多的表,组中可能包含多个用户 __tablename__ = ‘group‘ nid = Column(Integer, primary_key=True, autoincrement=True) caption = Column(String(32)) class User(Base): __tablename__ = ‘user‘ uid = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(32)) gid = Column(Integer, ForeignKey(‘group.nid‘))
user表和group表中插入数据
# 创建完表之后,建立连接 Session = sessionmaker(bind=engine) session = Session() 新增Group表数据 session.add_all([ Group(caption=‘DBA‘), Group(caption=‘SA‘), ] ) session.commit() session.add(Group(caption=‘QA‘)) 新建User表数据 session.add_all([ User(name=‘Bob‘, gid=1), User(name=‘Boss‘, gid=2), ] ) session.commit()
这俩代码中定义了2个表,一个是“组”,一个是“用户表”。一对多表示:一个组中可能存在多个用户。
1.1 查找用户表中每个用户对应的组。
常规的联表查询如下:
ret = session.query(User.name, Group.caption).join(Group).all() print(ret) # join默认是进行left join out: [(‘Bob‘, ‘DBA‘), (‘Boss‘, ‘SA‘)]
SQLacademy查询方法:
步骤如下:
1. 建立关系
# 使用relationship,先必须在创建表的时候建立关系 class Group(Base): __tablename__ = ‘group‘ nid = Column(Integer, primary_key=True, autoincrement=True) caption = Column(String(32)) class User(Base): __tablename__ = ‘user‘ uid = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(32)) gid = Column(Integer, ForeignKey(‘group.nid‘)) <strong># 仅仅方便查询.</strong> group = relationship("Group")
2. 正向查询
ret = session.query(User).all() for obj in ret: # obj 代指user表中的每一行数据,是User对象 # obj.group代指group对象,可以用obj.group.XXX来获取group表中的字段的值 print(obj.uid, obj.name, obj.gid, obj.group, obj.group.nid, obj.group.caption)
3. 反向查询
group = relationship("Group", backref=‘uuu‘) obj = session.query(Group).filter(Group.caption==‘DBA‘).first() 带有筛选条件的语句,筛选DBA组所有成员 print(obj) # obj表示符合条件的Group对象 out: <__main__.Group object at 0x00000000032EB710><br> print(obj.uuu) # obj.uuu 就是符合筛选条件的User对象 out: [<__main__.User object at 0x0000000003B15400>, <__main__.User object at 0x0000000003B15470>] for i in obj.uuu:# obj.uuu需要用for循环来查询结果 print(i.uid, i.name, i.gid)
relationship()函数:这个函数告诉ORM,通过使用user.Group,Group类应该和User类连接起来
relationship()使用外键明确这两张表的关系。决定User.group属性是多对一的,即多个用户可以在同一个组里。
relationship()的子函数backref()提供表达反向关系的细节:relationship()对象的集合被Group.uuu引用。多对一的反向关系总是一对多,即一个组可以包含多个用户
2. 多对多
class Host(Base): __tablename__ = ‘host‘ nid = Column(Integer, primary_key=True, autoincrement=True) hostname = Column(String(32)) port = Column(String(32)) ip = Column(String(32)) class HostUser(Base): __tablename__ = ‘host_user‘ nid = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(32)) # 多对多 class HostToHostUser(Base): __tablename__ = ‘host_to_host_user‘ nid = Column(Integer, primary_key=True, autoincrement=True) # 两个关联的id,以外键的形式存在 host_id = Column(Integer, ForeignKey(‘host.nid‘)) host_user_id = Column(Integer, ForeignKey(‘host_user.nid‘))
# 创建完表之后,建立连接 Session = sessionmaker(bind=engine) session = Session() # 新增表数据 session.add_all([ Host(hostname=‘c1‘,port=‘22‘,ip=‘1.1.1.1‘), Host(hostname=‘c2‘,port=‘22‘,ip=‘1.1.1.2‘), Host(hostname=‘c3‘,port=‘22‘,ip=‘1.1.1.3‘), Host(hostname=‘c4‘,port=‘22‘,ip=‘1.1.1.4‘), Host(hostname=‘c5‘,port=‘22‘,ip=‘1.1.1.5‘), ]) session.commit() session.add_all([ HostUser(username=‘root‘), HostUser(username=‘db‘), HostUser(username=‘nb‘), HostUser(username=‘sb‘), ]) session.commit() session.add_all([ HostToHostUser(host_id=1,host_user_id=1), HostToHostUser(host_id=1,host_user_id=2), HostToHostUser(host_id=1,host_user_id=3), HostToHostUser(host_id=2,host_user_id=2), HostToHostUser(host_id=2,host_user_id=4), HostToHostUser(host_id=2,host_user_id=3), ]) session.commit()
上边增加的数据,增加了五台服务器,分别是c1,c2,c3,c4,c5。对应ID:1,2,3,4,5。增加了四个人,分别是root, db, nb, sb,对应ID:1,2,3,4
2.1 常规查询
# 1. 获取主机为c1的对象 host_obj = session.query(Host).filter(Host.hostname == ‘c1‘).first() # 2. 获取查询关系表中拥有主机c1的用户ID host_2_host_user = session.query(HostToHostUser.host_user_id).filter(HostToHostUser.host_id == host_obj.nid).all() print(host_2_host_user) # [(1,), (2,), (3,)] r = zip(*host_2_host_user) print(list(r)) #[(1, 2, 3)] 这就是用户ID列表 # 3. 根据用户ID列表,查询用户名 users = session.query(HostUser.username).filter(HostUser.nid.in_(list(r)[0])).all() print(users) # [(‘root‘,), (‘db‘,), (‘nb‘,)]
2.2 relationship查询
2.2.1 建立关系
class Host(Base): __tablename__ = ‘host‘ nid = Column(Integer, primary_key=True, autoincrement=True) hostname = Column(String(32)) port = Column(String(32)) ip = Column(String(32)) class HostUser(Base): __tablename__ = ‘host_user‘ nid = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(32)) # 多对多 class HostToHostUser(Base): __tablename__ = ‘host_to_host_user‘ nid = Column(Integer, primary_key=True, autoincrement=True) host_id = Column(Integer, ForeignKey(‘host.nid‘)) host_user_id = Column(Integer, ForeignKey(‘host_user.nid‘)) # 新写法中有用 host = relationship(‘Host‘, backref=‘h‘) host_user = relationship(‘HostUser‘, backref=‘u‘)
2.2.2 查询获取HostToHostUser表中的字段信息
host_obj = session.query(Host).filter(Host.hostname == ‘c1‘).first()<br> print(host_obj) # <__main__.Host object at 0x0000000003C11128> print(host_obj.hostname) # 主机名:c1 print(host_obj.h) # host_obj.h表示HostToHostUser表中,符合筛选条件的HostToHostUser数据对象列表 [<__main__.HostToHostUser object at 0x0000000003B3F198>, <__main__.HostToHostUser object at 0x0000000003B3F898>, <__main__.HostToHostUser object at 0x0000000003B3F908>] # 循环获取用户信息 for item in host_obj.h: # print(item.host_user) # 一行用户的数据, HostUser 表的一行数据对象 print(item.host_user.username)
II. paramiko
paramiko的两种基本用法:基于用户名密码连接、基于公钥私钥连接。主要有两个大类:SSHClient(用于连接远程服务器并执行基本命令)、SFTPClient(用于连接远程服务器并执行上传下载)
1. SSHClient
1.1 基于用户名密码连接:
import paramiko # 创建SSH对象 ssh = paramiko.SSHClient() # 允许连接不在know_hosts文件中的主机 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 连接服务器 ssh.connect(hostname=‘172.25.50.13‘, port=22, username=‘work‘, password=‘123456‘) # 执行命令 stdin, stdout, stderr = ssh.exec_command(‘ls -l‘) # 获取命令结果 result = stdout.read() print(result.decode()) # 关闭连接 ssh.close() out: total 8 drwxr-xr-x 2 work work 4096 Mar 18 19:22 cn_market_lua drwxrwxr-x 3 work work 4096 Mar 18 19:09 www 基于用户名密码实现执行命令
1.2 基于公钥密钥连接:
import paramiko # 创建key文件 private_key = paramiko.RSAKey.from_private_key_file(‘/home/auto/.ssh/id_rsa‘) # 创建SSH对象 ssh = paramiko.SSHClient() # 允许连接不在know_hosts文件中的主机 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 连接服务器 ssh.connect(hostname=‘172.25.50.13‘, port=22, username=‘work‘, key=private_key) # 执行命令 stdin, stdout, stderr = ssh.exec_command(‘df -h‘) # 获取命令结果 result = stdout.read() # 关闭连接 ssh.close() out: Filesystem Size Used Avail Use% Mounted on /dev/vda1 20G 4.2G 15G 23% / tmpfs 1.9G 0 1.9G 0% /dev/shm /dev/vdb1 99G 499M 93G 1% /data0 基于公钥私钥实现远程执行命令
2. SFTPClient
2.1 基于用户名密码连接:
import paramiko # 创建transport transport = paramiko.Transport((‘172.25.50.13‘,22)) transport.connect(username=‘work‘,password=‘123456‘) # 创建sftpclient,并基于transport连接,把他俩进行绑定 sftp = paramiko.SFTPClient.from_transport(transport) # 将location.py 上传至服务器 /tmp/test.py sftp.put(‘/tmp/location.py‘, ‘/tmp/test.py‘) # 将remove_path 下载到本地 local_path sftp.get(‘remove_path‘, ‘local_path‘) # 关闭session transport.close() 基于用户名密码实现上传下载
2.2 基于公钥密钥连接:
import paramiko # 创建key文件 private_key = paramiko.RSAKey.from_private_key_file(‘/home/auto/.ssh/id_rsa‘) transport = paramiko.Transport((‘172.25.50.13‘, 22)) transport.connect(username=‘work‘, pkey=private_key ) sftp = paramiko.SFTPClient.from_transport(transport) # 将location.py 上传至服务器 /tmp/test.py sftp.put(‘/tmp/location.py‘, ‘/tmp/test.py‘) # 将remove_path 下载到本地 local_path sftp.get(‘remove_path‘, ‘local_path‘) transport.close() 基于公钥密钥上传下载
3. 堡垒机
堡垒机大概构成:
使用paramiko就可以实现上述功能,这里先省略数据库方面:
版本一: 1)用户在终端输入内容,并将内容发送至远程服务器,
2)远程服务器执行命令,并将结果返回
3)用户终端显示内容
import paramiko import sys import os import socket import select import getpass from paramiko.py3compat import u # py27中注释掉这行 tran = paramiko.Transport((‘172.25.50.13‘, 22,)) tran.start_client() tran.auth_password(‘work‘, ‘123456‘) # 打开一个通道 chan = tran.open_session() # 获取一个终端 chan.get_pty() # 激活器 chan.invoke_shell() while True: # 监视用户输入和服务器返回数据 # sys.stdin 处理用户输入 # chan 是之前创建的通道,用于接收服务器返回信息 readable, writeable, error = select.select([chan, sys.stdin, ],[],[],1) if chan in readable: try: x = u(chan.recv(1024)) # py3中 代码 # x = chan.recv(1024) # py2中代码 if len(x) == 0: print(‘\r\n*** EOF\r\n‘) break sys.stdout.write(x) sys.stdout.flush() except socket.timeout: pass if sys.stdin in readable: inp = sys.stdin.readline() chan.sendall(inp) chan.close() tran.close()
终极版本: 带有用户日志的堡垒机
# 记录用户日志 import paramiko import sys import os import socket import getpass from paramiko.py3compat import u # windows does not have termios... try: import termios import tty has_termios = True except ImportError: has_termios = False def interactive_shell(chan): if has_termios: posix_shell(chan) else: windows_shell(chan) def posix_shell(chan): import select oldtty = termios.tcgetattr(sys.stdin) try: tty.setraw(sys.stdin.fileno()) tty.setcbreak(sys.stdin.fileno()) chan.settimeout(0.0) log = open(‘handle.log‘, ‘a+‘, encoding=‘utf-8‘) flag = False temp_list = [] while True: r, w, e = select.select([chan, sys.stdin], [], []) if chan in r: try: x = u(chan.recv(1024)) if len(x) == 0: sys.stdout.write(‘\r\n*** EOF\r\n‘) break if flag: if x.startswith(‘\r\n‘): pass else: temp_list.append(x) flag = False sys.stdout.write(x) sys.stdout.flush() except socket.timeout: pass if sys.stdin in r: x = sys.stdin.read(1) import json if len(x) == 0: break if x == ‘\t‘: flag = True else: temp_list.append(x) if x == ‘\r‘: log.write(‘‘.join(temp_list)) log.flush() temp_list.clear() chan.send(x) finally: termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty) def windows_shell(chan): import threading sys.stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.\r\n\r\n") def writeall(sock): while True: data = sock.recv(256) if not data: sys.stdout.write(‘\r\n*** EOF ***\r\n\r\n‘) sys.stdout.flush() break sys.stdout.write(data) sys.stdout.flush() writer = threading.Thread(target=writeall, args=(chan,)) writer.start() try: while True: d = sys.stdin.read(1) if not d: break chan.send(d) except EOFError: # user hit ^Z or F6 pass def run(): default_username = getpass.getuser() username = input(‘Username [%s]: ‘ % default_username) if len(username) == 0: username = default_username hostname = input(‘Hostname: ‘) if len(hostname) == 0: print(‘*** Hostname required.‘) sys.exit(1) tran = paramiko.Transport((hostname, 22,)) tran.start_client() default_auth = "p" auth = input(‘Auth by (p)assword or (r)sa key[%s] ‘ % default_auth) if len(auth) == 0: auth = default_auth if auth == ‘r‘: default_path = os.path.join(os.environ[‘HOME‘], ‘.ssh‘, ‘id_rsa‘) path = input(‘RSA key [%s]: ‘ % default_path) if len(path) == 0: path = default_path try: key = paramiko.RSAKey.from_private_key_file(path) except paramiko.PasswordRequiredException: password = getpass.getpass(‘RSA key password: ‘) key = paramiko.RSAKey.from_private_key_file(path, password) tran.auth_publickey(username, key) else: pw = getpass.getpass(‘Password for %s@%s: ‘ % (username, hostname)) tran.auth_password(username, pw) # 打开一个通道 chan = tran.open_session() # 获取一个终端 chan.get_pty() # 激活器 chan.invoke_shell() interactive_shell(chan) chan.close() tran.close() if __name__ == ‘__main__‘: run()
哗啦啦Python之路 - sqlalchemy/paramiko/堡垒机
标签:
原文地址:http://www.cnblogs.com/hualala/p/5740920.html