公司内部通常会限制MySQL
的登录访问的IP地址,如此情况下我们就需要通过ssh
登录指定的服务器(跳板机)才能访问远程MySQL
,程序本身不能直接连接MySQL
,在写一些自动化脚本时会很麻烦, Python
可通过paramiko
和sshtunnel
模块建立ssh通道在访问MySQL
1. 通过密钥或密码登录(ssh
)指定跳板机
2. 绑定本地地址与跳板机相通的端口
3. 登录MySQL
数据库
4. 执行SQL
5. 登出数据库和服务器
(一)服务器登录方法
#!/usr/bin/python3
# coding=utf-8
# Author: 文
import paramiko
from sshtunnel import SSHTunnelForwarder
class Jump_Server():
def login_server(self, address, address_port, username, remote_address, remote_address_port, **kw):
"""
:param address: 跳扳机的IP地址
:param address_port: 跳扳机的端口号
:param username: 跳板机的SSH登录账号
:param remote_address: 远程服务器的IP地址
:param remote_address_port: 远程服务器的端口号
:param kw: 参数ssh_pkey(客户端私钥路径)参数key_password(客户端开机密码) 参数ssh_password(客户端密码)
:return: 返回服务器操作指针
"""
try:
# 通过密钥调用connect函数建立Linux连接
if "ssh_pkey" in kw.keys():
server = SSHTunnelForwarder(
# 跳板机ip与ssh登录端口号
ssh_address_or_host=(address, address_port),
# 跳板机登录账号
ssh_username=username,
# PC(客户端)的私钥路径
ssh_pkey=paramiko.RSAKey.from_private_key_file(kw["ssh_pkey"]),
# PC(客户端)的密码
ssh_private_key_password=kw["key_password"],
# 远程MYSQL服务器的绑定的IP和端口号
remote_bind_address=(remote_address, remote_address_port)
)
# 通过密码调用connect函数建立Linux连接
elif "password" in kw.keys():
server = SSHTunnelForwarder(
ssh_address_or_host=(address, address_port),
ssh_username=username,
ssh_password=kw["password"],
remote_bind_address=(remote_address, remote_address_port),
# 绑定本地地址(默认127.0.0.1和端口号)及与跳板机相通的端口
local_bind_address=('127.0.0.1', 22),
)
else:
print("登录信息与方法错误,抛出异常 - ValueError")
raise ValueError
server.start()
print("账号【%s】登录【%s】服务器启动服务器【%s】的MySQL服务" % (username, address, remote_address))
return server
except Exception as e:
print("发生未知错误: %s" % e)
raise
def logout_server(self, server_pointer):
"""
:param server_pointer: 服务器操作指针
:return:
"""
try:
server_pointer.close()
print("登出服务器成功")
except Exception as e:
print("发生未知错误: %s" % e)
raise
(二)数据库登录方法
#!/usr/bin/python3
# coding=utf-8
# Author: 文
import pymysql
from operate_server import Jump_Server
def connect_db(sql, host=None, db=None):
"""
:param sql: mysql语句
:param host: 服务器登录信息
:param db: 数据库登录信息
:return:
"""
if "ssh_pkey" in host.keys():
server = Jump_Server().login_server(
address=host["address"],
address_port=host["address_port"],
username=host["username"],
remote_address=host["remote_address"],
remote_address_port=host["remote_address_port"],
ssh_pkey=host["ssh_pkey"],
key_password=["key_password"]
)
# 密码登录服务器
elif "password" in host.keys():
server = Jump_Server().login_server(
address=host["address"],
address_port=host["address_port"],
username=host["username"],
password=host["password"],
remote_address=host["remote_address"],
remote_address_port=host["remote_address_port"],
local_bind_address=('127.0.0.1', 22),
)
else:
print("登录方法错误,传参密钥登录或密码登录, 抛出异常 - ValueError")
raise ValueError
# 登录数据库
db = pymysql.connect(
host=db["address"], # mysql地址
port=server.local_bind_port, # 跳板机绑定的端口号
user=db["user"], # mysql账号
passwd=db["password"], # mysql密码
db=db["db"], # 数据库名
charset='utf8'
)
version = db.server_version
print("账号【{0}】登录【{1}】端口【{2}】数据库【{3}】成功, 数据库version: {4}".format(
dbs["user"], dbs["address"], host["remote_address_port"], dbs["db"], version))
# 使用cursor()方法获取mysql操作游标
cursor = db.cursor()
print("开始执行sql语句: {0}".format(sql))
try:
if sql[0:6].lower() == "select":
cursor.execute(sql) # 执行select语句
results = cursor.fetchall() # 获取查询结果
print("获得select查询结果:{0}".format(results))
elif sql[0:6].lower() == "update":
try:
cursor.execute(sql) # 执行update语句
db.commit() # 提交到数据库执行
print("update语句执行通过, {0}条记录被修改".format(cursor.rowcount))
except Exception:
db.rollback() # 数据操作失败, 回滚
print("数据更新失败, 数据回滚成功")
raise
elif sql[0:6].lower() == "delete":
cursor.execute(sql) # 执行delete语句
db.commit() # 提交到数据库执行
print("delete语句执行通过, {0}条记录被删除".format(cursor.rowcount))
elif sql[0:6].lower() == "insert":
cursor.execute(sql) # 执行insert语句
db.commit() # 提交到数据库执行
print("insert语句执行通过, 成功插入{0}条记录".format(cursor.rowcount))
else:
print("sql语句类型识别失败, 请校验sql语句, 抛出异常-ValueError")
raise ValueError
except Exception as e:
print("发生预料之外的错误: %s" % e)
raise
finally:
cursor.close()
print("关闭mysql光标对象")
db.close()
print("登出mysql数据库")
Jump_Server().logout_server(server_pointer=server)
(三)执行方式
#!/usr/bin/python3
# coding=utf-8
# Author: 文
if __name__ == "__main__":
hosts1 = {"address": "跳板机IP", "address_port": "跳板机登录端口", "username": "跳板机登录账号",
"remote_address": "mysql服务器IP", "remote_address_port": "数据库端口号",
"ssh_pkey": "私钥路径", "key_password": "私钥密码"}
hosts2 = {"address": "跳板机IP", "address_port": "跳板机登录端口", "username": "跳板机登录账号",
"remote_address": "mysql服务器IP", "remote_address_port": "数据库端口号",
"password": "数据库密码"}
dbs = {"address": "数据库IP", "user": "数据库账号", "password": "数据库密码", "db": "数据库名"}
sql = "select * from blog where id > 116 and id < 115;"
# 通过密钥登录跳板机
connect_db(sql=sql, host=hosts1, db=dbs)
# 通过密码登录跳板机
connect_db(sql=sql, host=hosts2, db=dbs)