python运维开发(十二)----rabbitMQ、pymysql、SQLAlchemy
内容目录:
- rabbitMQ
- python操作mysql,pymysql模块
- Python ORM框架,SQLAchemy模块
- Paramiko
- 其他with上下文切换
rabbitMQ
RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统。他遵循Mozilla Public License开源协议。
MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们。消 息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用的技术。排队指的是应用程序通过 队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求。
1、基本安装配置使用
安装
ubuntu系统上安装rabbitmq
sudo apt install erlang
sudo apt install rabbitmq-server
#拷贝配置文件,否则连接rabbitmq会报错
cp /usr/share/doc/rabbitmq-server/rabbitmq.config.example.gz /etc/rabbitmq/
cd /etc/rabbitmq/
gunzip rabbitmq.config.example.gz
/etc/init.d/rabbitmq-server start #启动 centos上
安装配置epel源
$ rpm -ivh http://dl.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm 安装erlang
$ yum -y install erlang 安装RabbitMQ
$ yum -y install rabbitmq-server service rabbitmq-server start/stop python操作的客户端需要安装pika模块来操作rabbitmq python3 -m pip install pika
使用
基于queue方式实现的消费者和生产者模型
import queue
import threading
import time message = queue.Queue(10) def producer(i):#生产者方法
while True:
message.put('生产--'+str(i)) #添加到队列
time.sleep(1) def consumer(i):#消费者方法
msg = message.get() #从队列中取消息
print(msg) for i in range(3):#创建2个任务线程来生产
t = threading.Thread(target=producer, args=(i,))
t.start() for i in range(10):#创建5个消费者任务来消费
t = threading.Thread(target=consumer, args=(i,))
t.start()
对于RabbitMQ来说,生产和消费不再针对内存里的一个Queue对象,而是某台服务器上的RabbitMQ Server实现的消息队列。
生产者
import pika connection = pika.BlockingConnection(pika.ConnectionParameters
(host='192.168.139.137')) #创建连接
channel = connection.channel() #创建频道 channel.queue_declare(queue='hello') #定义队列名,和订阅者的一致 channel.basic_publish(exchange='',routing_key='hello',
body='Hello World!')#发布消息
print(" [x] Sent 'Hello World!'")
connection.close()
消费者
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters
(host='192.168.139.137')) #建立连接
channel = connection.channel()#创建频道 channel.queue_declare\
(queue='hello') #定义一个rabbitMQ下的一个队列名,与发布者一致 def callback(ch, method, properties, body):#回调函数
print(" [x] Received %r" % body) channel.basic_consume(callback,
queue='hello',
no_ack=True)#指定队列名核函数准备执行接收消息 print(' [*] Waiting for messages. To exit press CTRL+C')
channel.start_consuming()#开始接收消息
2、acknowledgment 消息不丢失
no-ack = False,如果消费者遇到情况(its channel is closed, connection is closed, or TCP connection is lost)挂掉了,那么,RabbitMQ会重新将该任务添加到队列中。
我们在操作中只需在订阅者上添加no-ack=False设置就行,生产者不变
消费者代码:
import pika
import time connection = pika.BlockingConnection(pika.ConnectionParameters
(host='192.168.139.137')) #建立连接
channel = connection.channel()#创建频道 channel.queue_declare\
(queue='hello') #定义一个rabbitMQ下的一个队列名 def callback(ch, method, properties, body):#回调函数
print(" [x] Received %r" % body)
time.sleep(3)
print('ok')
ch.basic_ack(delivery_tag = method.delivery_tag) channel.basic_consume(callback,
queue='hello',
no_ack=False)#此处设置no_ack=False
# 表示中途断开rabbitmq会将将改任务添加到队列中 print(' [*] Waiting for messages. To exit press CTRL+C')
channel.start_consuming()#开始接收消息
3、durable 消息不丢失
生产者
import pika connection = pika.BlockingConnection(pika.ConnectionParameters
(host='192.168.139.137')) #创建连接
channel = connection.channel() #创建频道 channel.queue_declare(queue='hello',
durable=True) #定义队列名,和接收者的一致 channel.basic_publish(exchange='',routing_key='hello',
properties=pika.BasicProperties
(delivery_mode=2),#make message persistent
body='Hello World!') #发布消息
print(" [x] Sent 'Hello World!'")
connection.close()
消费者
import pika
import time connection = pika.BlockingConnection(pika.ConnectionParameters
(host='192.168.139.137')) #建立连接
channel = connection.channel()#创建频道 channel.queue_declare(queue='hello',
durable=True) #定义一个rabbitMQ下的一个队列名 def callback(ch, method, properties, body):#回调函数
print(" [x] Received %r" % body)
time.sleep(3)
print('ok')
ch.basic_ack(delivery_tag = method.delivery_tag) channel.basic_consume(callback,
queue='hello',
no_ack=False)#此处设置no_ack=False
# 表示中途断开rabbitmq会将将改任务添加到队列中 print(' [*] Waiting for messages. To exit press CTRL+C')
channel.start_consuming()#开始接收消息
4、消息获取顺序
默认消息队列里的数据是按照顺序被消费者拿走,例如:消费者1 去队列中获取 奇数 序列的任务,消费者2去队列中获取 偶数 序列的任务。
channel.basic_qos(prefetch_count=1) 表示谁来谁取,不再按照奇偶数排列
订阅者代码和发布者均取消durable=True部分,测试时候只要开启多个订阅者执行就能看到第一个订阅者收第一个消息,第二个订阅者接收第二条消息。。。
消费者
import pika
import time connection = pika.BlockingConnection(pika.ConnectionParameters(host='192.168.139.137')) #建立连接
channel = connection.channel()#创建频道 #channel.queue_declare(queue='hello',durable=True) #定义一个rabbitMQ下的一个队列名
channel.queue_declare(queue='hello') #定义一个rabbitMQ下的一个队列名 def callback(ch, method, properties, body):#回调函数
print(" [x] Received %r" % body)
time.sleep(3)
print('ok')
ch.basic_ack(delivery_tag = method.delivery_tag) channel.basic_qos(prefetch_count=1) channel.basic_consume(callback,queue='hello',no_ack=False)#此处设置no_ack=False 表示中途断开rabbitmq会将将改任务添加到队列中 print(' [*] Waiting for messages. To exit press CTRL+C')
channel.start_consuming()#开始接收消息
消费者
生产者
import pika connection = pika.BlockingConnection(pika.ConnectionParameters(host='192.168.139.137')) #创建连接
channel = connection.channel() #创建频道 # channel.queue_declare(queue='hello',durable=True) #定义队列名,和接收者的一致
channel.queue_declare(queue='hello') #定义队列名,和接收者的一致 channel.basic_publish(exchange='',routing_key='hello',
properties=pika.BasicProperties(delivery_mode=2),#make message persistent
body='Hello World!') #发布消息
print(" [x] Sent 'Hello World!'")
connection.close()
生产者
5、发布订阅
发布订阅和简单的消息队列区别在于,发布订阅会将消息发送给所有的订阅者,而消息队列中的数据被消费一次便消失。所以,RabbitMQ实现发布和订阅时,会为每一个订阅者创建一个队列,而发布者发布消息时,会将消息放置在所有相关队列中。
exchange type = fanout
测试过程中可以执行多个订阅者代码窗口,执行发布者代码发布消息,所有打开的订阅者窗口都会收到消息。

import pika
import sys connection = pika.BlockingConnection(pika.ConnectionParameters(
host='192.168.62.168'))#建立连接
channel = connection.channel()#创建频道 channel.exchange_declare(exchange='logs',
type='fanout')#定义exchange,类型为fanout,fanout即为后端多个队列情况 message = ' '.join(sys.argv[1:]) or "info: Hello World!"#发送的消息
channel.basic_publish(exchange='logs',
routing_key='',
body=message)
print(" [x] Sent %r" % message)
connection.close()
发布者
import pika connection = pika.BlockingConnection(pika.ConnectionParameters(
host='192.168.62.168'))#建立rabbitMQ连接
channel = connection.channel() channel.exchange_declare(exchange='logs',
type='fanout')#定义exchange由exchange来指定后端队列 result = channel.queue_declare(exclusive=True)#后端队列随机命名
queue_name = result.method.queue#队列名字 channel.queue_bind(exchange='logs',
queue=queue_name)#将exchange和队列进行绑定 print(' [*] Waiting for logs. To exit press CTRL+C') def callback(ch, method, properties, body):
print(" [x] %r" % body) channel.basic_consume(callback,
queue=queue_name,
no_ack=True)#调用callback函数 channel.start_consuming()#执行
订阅者
6、关键字发送

上面的事例中,发送消息时明确指定某个队列并向其中发送消息,RabbitMQ还支持根据关键字发送,即:队列绑定关键字,发送者将数据根据关键字发送到消息exchange,exchange根据 关键字 判定应该将数据发送至指定队列。
exchange type = direct
import pika
import sys connection = pika.BlockingConnection(pika.ConnectionParameters(
host='192.168.62.168')) # 建立rabbitMQ连接
channel = connection.channel()#创建频道 channel.exchange_declare(exchange='direct_logs',
type='direct')#关键字匹配type类型为direct severity = sys.argv[1] if len(sys.argv) > 1 else 'info'
'''
如果输入的参数长度大于1则将第一个参数传给serverity,否则小于1的话将inf传给serverity
'''
message = ' '.join(sys.argv[2:]) or 'Hello World!'
#将第二个参数传做字符串拼接传给message,或者将Hello World传给message
channel.basic_publish(exchange='direct_logs',
routing_key=severity,
body=message)
print(" [x] Sent %r:%r" % (severity, message))
connection.close()
发布者
import pika
import sys connection = pika.BlockingConnection(pika.ConnectionParameters(
host='192.168.62.168')) # 建立rabbitMQ连接
channel = connection.channel() channel.exchange_declare(exchange='direct_logs',
type='direct') result = channel.queue_declare(exclusive=True)
queue_name = result.method.queue severities = sys.argv[1:]#执行时候需要传代参数,如果不对的话提示如下说明并推出程序,输入的参数做为关键字
if not severities:
sys.stderr.write("Usage: %s [info] [warning] [error]\n" % sys.argv[0])
sys.exit(1) for severity in severities:#对输入的参数关键字进行循环,如果匹配上关键字就输出
channel.queue_bind(exchange='direct_logs',
queue=queue_name,
routing_key=severity) print(' [*] Waiting for logs. To exit press CTRL+C') def callback(ch, method, properties, body):
print(" [x] %r:%r" % (method.routing_key, body)) channel.basic_consume(callback,
queue=queue_name,
no_ack=True) channel.start_consuming()
订阅者
7、模糊匹配

在topic类型下,可以让队列绑定几个模糊的关键字,之后发送者将数据发送到exchange,exchange将传入”路由值“和 ”关键字“进行匹配,匹配成功,则将数据发送到指定队列。
exchange type = topic
- # 表示可以匹配 0 个 或 多个 单词
- * 表示只能匹配 一个 单词
发送者路由值 队列中
test.jabe.com test.* -- 不匹配
test.jabe.com test.# -- 匹配
import pika
import sys connection = pika.BlockingConnection(pika.ConnectionParameters(
host='192.168.62.168')) # 建立rabbitMQ连接
channel = connection.channel()#创建频道 channel.exchange_declare(exchange='topic_logs',
type='topic')#模糊匹配type类型为topic routing_key = sys.argv[1] if len(sys.argv) > 1 else 'anonymous.info'
message = ' '.join(sys.argv[2:]) or 'Hello World!'
channel.basic_publish(exchange='topic_logs',
routing_key=routing_key,
body=message)
print(" [x] Sent %r:%r" % (routing_key, message))
connection.close()
发布者
import pika
import sys connection = pika.BlockingConnection(pika.ConnectionParameters(
host='192.168.62.168')) # 建立rabbitMQ连接
channel = connection.channel() channel.exchange_declare(exchange='topic_logs',
type='topic') result = channel.queue_declare(exclusive=True)
queue_name = result.method.queue binding_keys = sys.argv[1:]
if not binding_keys:
sys.stderr.write("Usage: %s [binding_key]...\n" % sys.argv[0])
sys.exit(1) for binding_key in binding_keys:
channel.queue_bind(exchange='topic_logs',
queue=queue_name,
routing_key=binding_key) print(' [*] Waiting for logs. To exit press CTRL+C') def callback(ch, method, properties, body):
print(" [x] %r:%r" % (method.routing_key, body)) channel.basic_consume(callback,
queue=queue_name,
no_ack=True) channel.start_consuming()
订阅者
pymysql模块
pymsql是Python中操作MySQL的模块,其使用方法和MySQLdb(py2中)几乎相同。
安装pymysql模块,在py2中模块名为MySQLdb
安装
python3 -m pip install pymysql
使用
1、执行SQL
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import pymysql # 创建连接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='t1')
# 创建游标
cursor = conn.cursor() # 执行SQL,并返回收影响行数
effect_row = cursor.execute("update hosts set host = '1.1.1.2'") # 执行SQL,并返回受影响行数
#effect_row = cursor.execute("update hosts set host = '1.1.1.2' where nid > %s", (1,)) # 执行SQL,并返回受影响行数
#effect_row = cursor.executemany("insert into hosts(host,color_id)values(%s,%s)", [("1.1.1.11",1),("1.1.1.11",2)]) # 提交,不然无法保存新建或者修改的数据
conn.commit() # 关闭游标
cursor.close()
# 关闭连接
conn.close()
插入、修改
2、获取新创建数据自增ID
import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='t1')
cursor = conn.cursor()
cursor.executemany("insert into hosts(host,color_id)values(%s,%s)", [("1.1.1.11",1),("1.1.1.11",2)])
conn.commit()
cursor.close()
conn.close() # 获取最新自增ID
new_id = cursor.lastrowid
auto_increment
3、获取查询数据
import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='t1')
cursor = conn.cursor()
cursor.execute("select * from hosts") # 获取第一行数据
row_1 = cursor.fetchone() # 获取前n行数据
# row_2 = cursor.fetchmany(3)
# 获取所有数据
# row_3 = cursor.fetchall() conn.commit()
cursor.close()
conn.close() '''
注:在fetch数据时按照顺序进行,可以使用cursor.scroll(num,mode)来移动游标位置,如:
cursor.scroll(1,mode='relative') # 相对当前位置移动
cursor.scroll(2,mode='absolute') # 相对绝对位置移动
'''
4、fetch数据类型
关于默认获取的数据是元组类型,如果想要或者字典类型的数据,即:
import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='t1') # 游标设置为字典类型
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
r = cursor.execute("call p1()") result = cursor.fetchone() conn.commit()
cursor.close()
conn.close()
fetch
SQLAchemy模块
QLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取执行结果。

Dialect用于和数据API进行交流,根据配置文件的不同调用不同的数据库API,从而实现对数据库的操作,如:
MySQL-Python
mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname> pymysql
mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>] MySQL-Connector
mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname> cx_Oracle
oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...] 更多详见:http://docs.sqlalchemy.org/en/latest/dialects/index.html
dailect
步骤一:
使用 Engine/ConnectionPooling/Dialect 进行数据库操作,Engine使用ConnectionPooling连接数据库,然后再通过Dialect执行SQL语句。
from sqlalchemy import create_engine
engine = create_engine("mysql+mysqldb://root:123@127.0.0.1:3306/s11", max_overflow=5)
engine.execute(
"INSERT INTO ts_test (a, b) VALUES ('2', 'v1')"
)
engine.execute(
"INSERT INTO ts_test (a, b) VALUES (%s, %s)",
((555, "v1"),(666, "v1"),)
)
engine.execute(
"INSERT INTO ts_test (a, b) VALUES (%(id)s, %(name)s)",
id=999, name="v1"
)
result = engine.execute('select * from ts_test')
result.fetchall()
事务操作
from sqlalchemy import create_engine
engine = create_engine("mysql+mysqldb://root:123@127.0.0.1:3306/s11", max_overflow=5)
# 事务操作
with engine.begin() as conn:
conn.execute("insert into table (x, y, z) values (1, 2, 3)")
conn.execute("my_special_procedure(5)")
conn = engine.connect()
# 事务操作
with conn.begin():
conn.execute("some statement", {'x':5, 'y':10})
事务操作
注:查看数据库连接:show status like 'Threads%';
步骤二:
使用 Schema Type/SQL Expression Language/Engine/ConnectionPooling/Dialect 进行数据库操作。Engine使用Schema Type创建一个特定的结构对象,之后通过SQL Expression Language将该对象转换成SQL语句,然后通过 ConnectionPooling 连接数据库,再然后通过 Dialect 执行SQL,并获取结果。
from sqlalchemy import create_engine, Table, Column, Integer, String, MetaData, ForeignKey
metadata = MetaData()
user = Table('user', metadata,
Column('id', Integer, primary_key=True),
Column('name', String(20)),
)
color = Table('color', metadata,
Column('id', Integer, primary_key=True),
Column('name', String(20)),
)
engine = create_engine("mysql+mysqldb://root:123@127.0.0.1:3306/s11", max_overflow=5)
metadata.create_all(engine)
# metadata.clear()
# metadata.remove()
增删改查操作
from sqlalchemy import create_engine, Table, Column, Integer, String, MetaData, ForeignKey
metadata = MetaData()
user = Table('user', metadata,
Column('id', Integer, primary_key=True),
Column('name', String(20)),
)
color = Table('color', metadata,
Column('id', Integer, primary_key=True),
Column('name', String(20)),
)
engine = create_engine("mysql+mysqldb://root:123@127.0.0.1:3306/s11", max_overflow=5)
conn = engine.connect()
# 创建SQL语句,INSERT INTO "user" (id, name) VALUES (:id, :name)
conn.execute(user.insert(),{'id':7,'name':'seven'})
conn.close()
# sql = user.insert().values(id=123, name='wu')
# conn.execute(sql)
# conn.close()
# sql = user.delete().where(user.c.id > 1)
# sql = user.update().values(fullname=user.c.name)
# sql = user.update().where(user.c.name == 'jack').values(name='ed')
# sql = select([user, ])
# sql = select([user.c.id, ])
# sql = select([user.c.name, color.c.name]).where(user.c.id==color.c.id)
# sql = select([user.c.name]).order_by(user.c.name)
# sql = select([user]).group_by(user.c.name)
# result = conn.execute(sql)
# print result.fetchall()
# conn.close()
增删改查
注:SQLAlchemy无法修改表结构,如果需要可以使用SQLAlchemy开发者开源的另外一个软件Alembic来完成。
步骤三:
使用 ORM/Schema Type/SQL Expression Language/Engine/ConnectionPooling/Dialect 所有组件对数据进行操作。根据类创建对象,对象转换成SQL,执行SQL。
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine engine = create_engine("mysql+mysqldb://root:123@127.0.0.1:3306/s11", max_overflow=5) Base = declarative_base() class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(50)) # 寻找Base的所有子类,按照子类的结构在数据库中生成对应的数据表信息
# Base.metadata.create_all(engine) Session = sessionmaker(bind=engine)
session = Session() # ########## 增 ##########
# u = User(id=2, name='sb')
# session.add(u)
# session.add_all([
# User(id=3, name='sb'),
# User(id=4, name='sb')
# ])
# session.commit() # ########## 删除 ##########
# session.query(User).filter(User.id > 2).delete()
# session.commit() # ########## 修改 ##########
# session.query(User).filter(User.id > 2).update({'cluster_id' : 0})
# session.commit()
# ########## 查 ##########
# ret = session.query(User).filter_by(name='sb').first() # ret = session.query(User).filter_by(name='sb').all()
# print ret # ret = session.query(User).filter(User.name.in_(['sb','bb'])).all()
# print ret # ret = session.query(User.name.label('name_label')).all()
# print ret,type(ret) # ret = session.query(User).order_by(User.id).all()
# print ret # ret = session.query(User).order_by(User.id)[1:3]
# print ret
# session.commit()
operation
Paramiko模块
paramiko模块,基于SSH用于连接远程服务器并执行相关操作。
1、安装模块
python3 -m pip install paramiko
2、使用
SSHClient
用于连接远程服务器并执行基本命令
import paramiko
ssh = paramiko.SSHClient() # 创建SSH对象
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())# 允许连接不在know_hosts文件中的主机 ssh.connect(hostname='192.168.139.137',port=22,username='jabe',password='')# 连接服务器 stdin,stdout,stderr = ssh.exec_command('ls')# 执行命令 resault = stdout.read()# 获取命令结果 print(str(resault,encoding='utf-8')) #打印
ssh.close()
ssh
import paramiko
transport = paramiko.Transport(('192.168.139.137', 22))
transport.connect(username='jabe', password='')
ssh = paramiko.SSHClient()
ssh._transport = transport
stdin, stdout, stderr = ssh.exec_command('df')
resault = stdout.read()# 获取命令结果
print(str(resault,encoding='utf-8'))
transport.close()
SSHClient 封装 Transport
SFTPClient
用于连接远程服务器并执行上传下载
基于用户名密码上传下载:
import paramiko
transport = paramiko.Transport(('192.168.139.137',22))
transport.connect(username='jabe',password='')
sftp = paramiko.SFTPClient.from_transport(transport)
#sftp.put('s1.py', '/tmp/test.py') # 将s1.py 上传至服务器 /tmp/test.py
sftp.get('/tmp/test.py', 'download.py') # 将remove_path 下载到本地 local_path
transport.close()
SFTP
基于公钥密钥上传下载:
import paramiko
private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')
transport = paramiko.Transport(('hostname', 22))
transport.connect(username='wupeiqi', 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()
key
简单应用
import paramiko
import uuid class SSHConnection(object): def __init__(self, host='172.16.103.191', port=22, username='wupeiqi',pwd=''):
self.host = host
self.port = port
self.username = username
self.pwd = pwd
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('/home/wupeiqi/tttttttttttt.py')
self.rename('/home/wupeiqi/tttttttttttt.py', '/home/wupeiqi/ooooooooo.py)
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,target_path):
# 连接,上传
file_name = self.create_file() sftp = paramiko.SFTPClient.from_transport(self.__transport)
# 将location.py 上传至服务器 /tmp/test.py
sftp.put(file_name, target_path) def rename(self, old_path, new_path): ssh = paramiko.SSHClient()
ssh._transport = self.__transport
# 执行命令
cmd = "mv %s %s" % (old_path, new_path,)
stdin, stdout, stderr = ssh.exec_command(cmd)
# 获取命令结果
result = stdout.read() def cmd(self, command):
ssh = paramiko.SSHClient()
ssh._transport = self.__transport
# 执行命令
stdin, stdout, stderr = ssh.exec_command(command)
# 获取命令结果
result = stdout.read()
return result ha = SSHConnection()
ha.run()
apply
# 对于更多限制命令,需要在系统中设置
/etc/sudoers Defaults requiretty
Defaults:cmdb !requiretty
with上下文切换
with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等。
import contextlib @contextlib.contextmanager
def worker_state(state_list, worker_thread): state_list.append(worker_thread)
print(state_list)
try:
yield
finally:
state_list.remove(worker_thread)
print(state_list) free_list = []
current_thread = "test_list"
with worker_state(free_list, current_thread):
'''执行worker_stat函数,遇到yield跳出,执行下面的程序,执行完之后执行finally的代码块'''
print(123)
print(456)
执行顺序如图所示

我们可以将socket做成with形式,其他的类似功能都可以这样来实现,用完之后自动关闭
import contextlib
import socket @contextlib.contextmanager
def context_socket(host, port):
sk = socket.socket()
sk.bind((host,port))
sk.listen(5)
try:
yield sk
finally:
sk.close() with context_socket('127.0.0.1', 8888) as sock:#将函数的yield以前的部分集成到sock中,
print(sock)
参考url:
http://www.cnblogs.com/wupeiqi/articles/5132791.html
http://www.cnblogs.com/wupeiqi/articles/5699254.html
python运维开发(十二)----rabbitMQ、pymysql、SQLAlchemy的更多相关文章
- python运维开发(十八)----Django(二)
内容目录 路由系统 模版 Ajax model数据库操作,ORM 路由系统 django中的路由系统和其他语言的框架有所不同,在django中每一个请求的url都要有一条路由映射,这样才能将请求交给对 ...
- python运维开发(十六)----Dom&&jQuery
内容目录: Dom 查找 操作 事件 jQuery 查找 筛选 操作 事件 扩展 Dom 文档对象模型(Document Object Model,DOM)是一种用于HTML和XML文档的编程接口.它 ...
- python运维开发(十五)----JavaScript
内容目录: HTML补充 javascript HTML补充 1.display标签 display的inline-block 属性会自动带3px的宽度 <span style="di ...
- python运维开发(十四)----HTML基本操作
内容目录: HTML概述 head标签 body中常用标签 css选择器 css常用属性 HTML HTML概述 HTML是英文Hyper Text Mark-up Language(超文本标记语言) ...
- python运维开发(十九)----Django后台表单验证、session、cookie、model操作
内容目录: Django后台表单验证 CSRF加密传输 session.cookie model数据库操作 Django后台Form表单验证 Django中Form一般有2种功能: 1.用于做用户提交 ...
- python运维开发(十)----IO多路复用线程基本使用
内容目录: python作用域 python2.7和python3.5的多继承区别 IO多路复用 socketserver模块源分析 多线程.进程.协程 python作用域 python中无块级作用 ...
- Python运维开发基础09-函数基础【转】
上节作业回顾 #!/usr/bin/env python3 # -*- coding:utf-8 -*- # author:Mr.chen # 实现简单的shell命令sed的替换功能 import ...
- Python运维开发基础10-函数基础【转】
一,函数的非固定参数 1.1 默认参数 在定义形参的时候,提前给形参赋一个固定的值. #代码演示: def test(x,y=2): #形参里有一个默认参数 print (x) print (y) t ...
- Python运维开发基础08-文件基础【转】
一,文件的其他打开模式 "+"表示可以同时读写某个文件: r+,可读写文件(可读:可写:可追加) w+,写读(不常用) a+,同a(不常用 "U"表示在读取时, ...
随机推荐
- MVC 模型绑定
在WebForm,获取提交表单的值一般都是Request.Form["Title"]这样的方式.在MVC中,提供了模型绑定机制.让后台获取表单或Url中的参数变得更加简单. 一.基 ...
- WebSocket C# Demo
WebSocket 规范 WebSocket 协议本质上是一个基于 TCP 的协议.为了建立一个 WebSocket 连接,客户端浏览器首先要向服务器发起一个 HTTP 请求,这个请求和通常的 HTT ...
- httrack,webdup,WinHTTrack,WebZip
怎么下载摄像头游戏jabbo,并使其能离线运行?修改 1.摄像头游戏jabbo:JABBO Ultimatum by LiveMurals Interactive电脑为:windows 7 32位.试 ...
- JavaEE Tutorials (29) - Duke辅导案例研究示例
29.1Duke辅导应用的设计和架构44529.2主界面447 29.2.1主界面中使用的Java持久化API实体447 29.2.2主界面中使用的企业bean448 29.2.3主界面中使用的Web ...
- 【转】Linux里如何查找文件内容
原文网址:http://blog.chinaunix.net/uid-25266990-id-199887.html Linux查找文件内容的常用命令方法. 从文件内容查找匹配指定字符串的行: $ g ...
- 瑞柏匡丞:国内外App市场分析报告
互联网不可阻挡的向移动互联网转化.对于各种新兴产业来讲,移动APP是当下行业的颠覆者,也是未来的王者.国内外app市场的火热程度都已经远远超出了人们的预想,然而国内外市场的区别还是相当明显的. 首先, ...
- WordPress SEO ☞ WordPress网站终极优化指南
原文地址:http://www.eastdesign.net/wordpress-seo/ 最新消息,东方设计学院 WordPress SEO 系列视频教程正在持续更新中,目前为了不至于让视频传播过于 ...
- Family Tree
Question A traditional constructing tree problem. Given a string to represent relationships, and pri ...
- 剑指offer-面试题22.栈的压入,弹出序列
题目:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第 二个序列是否为该栈的弹出顺序.假设压入栈的所有数字均不相等. 例如序列1.2.3.4.5是某栈的压栈序列,序列4.5.3.2.1 是该压栈 ...
- OpenStack Keystone v3 API新特性
原连接 http://blog.chinaunix.net/uid-21335514-id-3497996.html keystone的v3 API与v2.0相比有很大的不同,从API的请求格式到re ...