Commit 304d71fb authored by shenshuo's avatar shenshuo

更新依赖

parents
# Created by .ignore support plugin (hsz.mobi)
### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.idea
\ No newline at end of file
## 安装
### python3.6 安装
[python链接](https://www.python.org/)
##### 在 CentOS 7 中安装 Python 依赖
```bash
$ yum -y groupinstall development
$ yum -y install zlib-devel
$ yum install -y python3-devel openssl-devel libxslt-devel libxml2-devel libcurl-devel
```
##### 在 Debian 中,我们需要安装 gcc、make 和 zlib 压缩/解压缩库
```bash
$ aptitude -y install gcc make zlib1g-dev
```
##### 运行下面的命令来安装 Python 3.6:
```bash
$ wget https://www.python.org/ftp/python/3.6.3/Python-3.6.3.tar.xz
$ xz -d Python-3.6.3.tar.xz
$ tar xvf Python-3.6.3.tar
$ cd Python-3.6.3/
$ ./configure
$ make && make install
# 查看安装
$ python3 -V
```
##### pip3安装
```bash
$ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
$ python3 get-pip.py
# 查看安装
$ pip3 -V
```
##### SDK 安装
```bash
$ pip3 install -U git+https://github.com/ss1917/ops_sdk.git
```
## 结构
```shell
.
├── README.md 项目readme
└── opssdk
├── logs 日志模块
├── install 安装模块
├── get_info 配置获取
└── operate 运维操作
├── check 系统参数检查和获取
├── mysql mysql 操作
├── mail 发送邮件
└── centralization 集中化管理工具 salt
└── websdk web开发使用
├── application.py tornado application
├── base_handler.py tornado 基类
├── cache.py 处理redis缓存
├── configs.py 配置文件管理
├── consts.py 常量
├── db_context.py MySQL 处理类
├── error.py 异常
├── fetch_coroutine.py
├── __init__.py
├── jwt_token.py jwt
├── mqhelper.py MQ 处理类
├── program.py
├── salt_api.py salt 处理类 可以移到工具类
├── sms.py 发送短信 可以移到工具类
├── tools.py 工具类
└── web_logs.py 日志处理
```
## logs
```python
import os
from opssdk.logs import Log
### 日志路径
log_path = '/log/yunwei/{0}.log'.format(os.path.basename(__file__))
### 添加日志标识
log_ins = Log('yunwei', log_path)
### 写日志 ('debug', 'info', 'warning', 'error', 'critical')
log_ins.write_log('info', 'ceshi')
```
## operate
- exec_shell 执行shell命令
```python
from opssdk.operate import exec_shell
recode,stdout = exec_shell('ls')
# recode 为0 则代表成功,stdout 内容 为列表格式 半月逗号分隔
# recode 非0 则代表失败,stdout 内容 字符串格式
```
- exclusiveLock 脚本锁,防止脚本重复执行
```python
from opssdk.operate import exclusiveLock
exclusiveLock(脚本名称)
```
- MyCrypt 加密解密模块
```python
from opssdk.operate import MyCrypt
mc = MyCrypt() # 实例化
mc.my_encrypt('ceshi') # 对字符串ceshi进行加密
mc.my_decrypt('') # 对密文进行解密
```
- now_time 获取当前时间 '%Y-%m-%d-%H-%M-%S'格式
```python
from opssdk.operate import now_time
print(now_time())
```
- is_ip 判断是否是IP ,True代表是,False代表不是
```python
from opssdk.operate import is_ip
print(is_ip('192.168.1.11'))
```
## check
系统参数检查和获取
- check_disk 检查目录磁盘剩余空间是否大于10G
- 参数1 检查的目录 参数2 大于磁盘剩余量
```python
from opssdk.operate.check import check_disk
print(check_disk('/data1', 10))
```
- check_sys_version 检查系统版本
```python
from opssdk.operate.check import check_sys_version
print(check_sys_version())
```
- get_ip_address 根据网卡获取ip地址
```
from opssdk.operate.check import get_ip_address
print(get_ip_address('lo'))
```
## get_info
解析配置文件
- json_to_dict 根据json文件的路径 把内容转化成字典格式
```python
from opssdk.get_info import json_to_dict
print(json_to_dict('/tmp/conf.json'))
```
- IniToDict 根据ini文件的路径、节点 把内容转化成字典格式
```python
from opssdk.get_info import IniToDict
itd = IniToDict('/tmp/conf.ini','config') # 实例化
print(itd.get_option())
print(itd.get_option('v1'))
```
## mysql 操作
```python
from opssdk.operate.mysql import MysqlBase
mysql_dict = {"host": "172.16.0.223", "port": 3306, "user": "root", "passwd": "ljXrcyn7", "db": "zhi"}
mb = MysqlBase(**mysql_dict)
### 查询 返回查询值
mb.query(sql)
### 增删改 返回影响行
mb.change(sql)
```
## mail
发送邮件
```python
from opssdk.operate.mail import Mail
mailto_list = "191715030@qq.com, shenshuo@shinezone.com, 381759019@qq.com"
sm = Mail()
"""
:param to_list: 收件人以半角逗号分隔 必填
:param header: 发件名,必填
:param sub: 标题 必填。
:param content: 发件内容 必填。
:param subtype: 发件格式 默认plain,可选 html格式
:param att: 附件 只支持单附件,选填
:return: True or False
"""
sm.send_mail(mailto_list, '运维', "标题", "内容")
sm.send_mail(mailto_list, '运维', "标题", "内容", 'plain', '/tmp/cof.ini')
```
## utils 实用工具
- timeit 装饰器,获取函数执行时长
## salt api 操作
```python
from opssdk.operate.centralization import SaltApi
my_salt = SaltApi(url='https://127.0.0.1:8001/', username="saltapi", password="shenshuo")
### 主机 执行方法 命令
req = my_salt.run('*', 'cmd.run_all', 'w')
status, stdout, stderr = req[0], req[1], req[2]
print(status, stdout, stderr)
```
#!/usr/bin/env python
# -*-coding:utf-8-*-
'''
author : shenshuo
date : 2018年2月6日11:18:40
role : 解析配置文件
'''
import json
import os
import configparser
def json_to_dict(conf_path):
if not os.path.isfile(conf_path):
raise FileNotFoundError('{0} file does not exist'.format(conf_path))
with open(conf_path, encoding='utf-8') as f:
try:
conf_data = json.load(f)
except ValueError as e:
raise ValueError('仅解析json格式')
return conf_data
class IniToDict:
def __init__(self, conf_path, section):
self.path = conf_path
self.sect = section
def get_option(self, *keys):
###判断配置文件path是否存在
if not os.path.isfile(self.path):
raise FileNotFoundError('{0} file does not exist'.format(self.path))
###解析文件
fh_conf = configparser.ConfigParser()
fh_conf.read(self.path)
###确认配置文件有无配置层
list_section = fh_conf.sections()
res_back = {}
if self.sect in list_section:
###取出section下的所有配置项
res_list = fh_conf.items(self.sect)
###转换成字典
res_dict = dict(res_list)
if keys:
###取出指定的键
for k, v in res_dict.items():
if k in keys:
res_back[k] = v
else:
res_back = res_dict
else:
raise ValueError('{0} not have {1}'.format(self.path, self.sect))
###如果只取一个键,则返回值,其他返回字典
if keys and len(keys) == 1:
return res_back.get(keys[0], "")
return res_back
\ No newline at end of file
#!/usr/bin/env python
# -*-coding:utf-8-*-
'''
author : shenshuo
date : 2018年2月5日13:37:54
role : 运维日志
'''
import logging
import os
###写日志类
class Log:
def __init__(self, log_flag='yunwei', log_file='/log/yunwei/yunwei.log'):
self.logFlag = log_flag
self.logFile = log_file
def write_log(self, log_level, log_message):
###创建一个logger
logger = logging.getLogger(self.logFlag)
logger.setLevel(logging.DEBUG)
###建立日志目录
log_dir = os.path.dirname(self.logFile)
if not os.path.isdir(log_dir):
os.makedirs(log_dir)
###创建一个handler用于写入日志文件
fh = logging.FileHandler(self.logFile)
fh.setLevel(logging.DEBUG)
###创建一个handler用于输出到终端
th = logging.StreamHandler()
th.setLevel(logging.DEBUG)
###定义handler的输出格式
formatter = logging.Formatter('%(asctime)s %(name)s %(levelname)s %(message)s')
fh.setFormatter(formatter)
###给logger添加handler
logger.addHandler(fh)
logger.addHandler(th)
###记录日志
level_dic = {'debug': logger.debug, 'info': logger.info, 'warning': logger.warning, 'error': logger.error,
'critical': logger.critical}
level_dic[log_level](log_message)
###删除重复记录
fh.flush()
logger.removeHandler(fh)
th.flush()
logger.removeHandler(th)
if __name__ == "__main__":
pass
\ No newline at end of file
#!/usr/bin/env python
# -*-coding:utf-8-*-
'''
author : shenshuo
date : 2018年2月5日13:37:54
role : 运维操作
'''
import os
import sys
import time
import re
import subprocess
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
###执行shell命令函数
def exec_shell(cmd):
sub2 = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, stderr = sub2.communicate()
ret = sub2.returncode
if ret == 0:
return ret, stdout.decode('utf-8').split('\n')
else:
return ret, stdout.decode('utf-8').replace('\n', '')
###脚本排它函数
def exclusiveLock(scriptName):
pid_file = '/tmp/%s.pid' % scriptName
lockcount = 0
while True:
if os.path.isfile(pid_file):
###打开脚本运行进程id文件并读取进程id
fp_pid = open(pid_file, 'r')
process_id = fp_pid.readlines()
fp_pid.close()
###判断pid文件取出的是否是数字
if not process_id:
break
if not re.search(r'^\d', process_id[0]):
break
###确认此进程id是否还有进程
lockcount += 1
if lockcount > 4:
print('2 min after this script is still exists')
sys.exit(111)
else:
if os.popen('/bin/ps %s|grep "%s"' % (process_id[0], scriptName)).readlines():
print("The script is running...... ,Please wait for a moment!")
time.sleep(30)
else:
os.remove(pid_file)
else:
break
###把进程号写入文件
wp_pid = open(pid_file, 'w')
sc_pid = os.getpid()
wp_pid.write('%s' % sc_pid)
wp_pid.close()
### 加密解密模块
class MyCrypt:
"""
usage: mc = MyCrypt() 实例化
mc.my_encrypt('ceshi') 对字符串ceshi进行加密
mc.my_decrypt('') 对密文进行解密
"""
def __init__(self, key='HOrUmuJ4bCVG6EYu2docoRNNYSdDpJJw'):
# 这里密钥key 长度必须为16(AES-128)、24(AES-192)、或32(AES-256)Bytes 长度
self.key = key
self.mode = AES.MODE_CBC
def my_encrypt(self, text):
length = 32
count = len(text)
if count < length:
add = length - count
text = text + ('\0' * add)
elif count > length:
add = (length - (count % length))
text = text + ('\0' * add)
cryptor = AES.new(self.key, self.mode, b'0000000000000000')
self.ciphertext = cryptor.encrypt(text)
return b2a_hex(self.ciphertext).decode('utf-8')
def my_decrypt(self, text):
cryptor = AES.new(self.key, self.mode, b'0000000000000000')
plain_text = cryptor.decrypt(a2b_hex(text)).decode('utf-8')
return plain_text.rstrip('\0')
### 当前时间
def now_time():
return time.strftime('%Y-%m-%d-%H-%M-%S',time.localtime(time.time()))
def is_ip(ip):
if re.search(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b$', ip):
return True
return False
if __name__ == "__main__":
pass
#!/usr/bin/env python
# -*-coding:utf-8-*-
'''
Author : SS
date : 2017年12月29日14:43:24
role : 集中化管理工具的使用
'''
import requests
import json
import time
try:
import cookielib
except:
import http.cookiejar as cookielib
import ssl
context = ssl._create_unverified_context()
import urllib3
urllib3.disable_warnings()
class SaltApi:
"""
定义salt api接口的类
初始化获得token
"""
def __init__(self, url='https://127.0.0.1:8001/', username="saltapi", password="shenshuo"):
self.__url = url
self.__username = username
self.__password = password
self.headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36",
"Content-type": "application/json"
# "Content-type": "application/x-yaml"
}
self.params = {'client': 'local', 'fun': '', 'tgt': ''}
self.login_url = self.__url + "login"
self.login_params = {'username': self.__username, 'password': self.__password, 'eauth': 'pam'}
self.token = self.get_data(self.login_url, self.login_params)['token']
self.headers['X-Auth-Token'] = self.token
def get_data(self, url, params):
send_data = json.dumps(params)
request = requests.post(url, data=send_data, headers=self.headers, verify=False)
response = request.json()
result = dict(response)
return result['return'][0]
def salt_command(self, tgt, method, arg=None):
"""远程执行命令,相当于salt 'client1' cmd.run 'free -m'"""
if arg:
params = {'client': 'local', 'fun': method, 'tgt': tgt, 'arg': arg}
else:
params = {'client': 'local', 'fun': method, 'tgt': tgt}
result = self.get_data(self.__url, params)
return result
def salt_async_command(self, tgt, method, arg=None): # 异步执行salt命令,根据jid查看执行结果
"""远程异步执行命令"""
if arg:
params = {'client': 'local_async', 'fun': method, 'tgt': tgt, 'arg': arg}
else:
params = {'client': 'local_async', 'fun': method, 'tgt': tgt}
jid = self.get_data(self.__url, params).get('jid', None)
return jid
def look_jid(self, jid): # 根据异步执行命令返回的jid查看事件结果
params = {'client': 'runner', 'fun': 'jobs.lookup_jid', 'jid': jid}
result = self.get_data(self.__url, params)
return result
def run(self, salt_client='*', salt_method='cmd.run_all', salt_params='w', timeout=1800):
try:
if not self.salt_command(salt_client, 'test.ping')[salt_client]:
return -98, 'test.ping error 98', ''
except Exception as e:
return -99, 'test.ping error', str(e)
t = 0
jid = self.salt_async_command(salt_client, salt_method, salt_params)
if not jid:
return -100, '连接失败', '连接失败或主机不存在'
while True:
time.sleep(5)
if t == timeout:
print('exec timeout!')
break
else:
t += 5
result = self.look_jid(jid)
for i in result.keys():
return result[i]['retcode'], result[i]['stdout'], result[i]['stderr']
if __name__ == '__main__':
pass
#!/usr/bin/env python
# -*-coding:utf-8-*-
"""
author : shenshuo
date : 2018年2月5日19:23:09
role : 检查
"""
import os
import socket
import fcntl
import struct
from opssdk.operate import exec_shell
def check_disk(d='/data1', f=10):
vfs = os.statvfs(d)
available = vfs.f_bsize * vfs.f_bavail / 1024 / 1024 / 1024
if available > f:
return True
return False
def check_sys_version():
recode, res = exec_shell(
"awk -F'release' '{print $2}' /etc/redhat-release | awk '{print $1}'|awk -F'.' '{print $1}'")
return res[0]
def get_ip_address(ifname):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
return socket.inet_ntoa(fcntl.ioctl(
s.fileno(),
0x8915, # SIOCGIFADDR
struct.pack('256s', bytes(ifname[:15], 'utf-8'))
)[20:24])
#!/usr/bin/env python
# -*-coding:utf-8-*-
"""
author : shenshuo
date : 2018年2月6日16:28:03
role : 发送邮件
"""
import smtplib
import os
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
class Mail:
def __init__(self, mail_host="smtp.163.com", mail_user="xz_ops_mail", mail_pass="shenshuo1",
mail_postfix="163.com"):
self.mail_host = mail_host # 使用的邮箱的smtp服务器地址,这里是163的smtp地址
self.__mail_user = mail_user # 用户名
self.__mail_pass = mail_pass # 密码
self.mail_postfix = mail_postfix # 邮箱的后缀,网易就是163.com
def send_mail(self, to_list, header, sub, content, subtype='plain', att='none'):
"""
:param to_list: 收件人以半角逗号分隔 必填
:param header: 发件名,必填
:param sub: 标题 必填。
:param content: 发件内容 必填。
:param subtype: 发件格式 默认plain,可选 html格式
:param att: 附件 只支持单附件,选填
"""
me = header + "<" + self.__mail_user + "@" + self.mail_postfix + ">"
msg = MIMEMultipart()
msg['Subject'] = sub ## 标题
msg['From'] = me ## 发件人
msg['To'] = to_list # 收件人,必须是一个字符串
# 邮件正文内容
msg.attach(MIMEText(content, subtype, 'utf-8'))
### 附件
if att != 'none':
if not os.path.isfile(att):
raise FileNotFoundError('{0} file does not exist'.format(att))
dirname, filename = os.path.split(att)
# 构造附件1,传送当前目录下的 test.txt 文件
att1 = MIMEText(open(att, 'rb').read(), 'base64', 'utf-8')
att1["Content-Type"] = 'application/octet-stream'
# 这里的filename可以任意写,写什么名字,邮件中显示什么名字
att1["Content-Disposition"] = 'attachment; filename="{0}"'.format(filename)
msg.attach(att1)
try:
server = smtplib.SMTP()
server.connect(self.mail_host) # 连接服务器
server.login(self.__mail_user, self.__mail_pass) # 登录操作
server.sendmail(me, to_list.split(','), msg.as_string())
server.close()
return True
except Exception as e:
print(str(e))
return False
#!/usr/bin/env python
# -*-coding:utf-8-*-
'''
author : shenshuo
date : 2018年2月5日13:37:54
role : mysql操作
'''
import pymysql
from opssdk.logs import Log
class MysqlBase:
def __init__(self, **args):
self.host = args.get('host')
self.user = args.get('user')
self.pswd = args.get('passwd')
self.db = args.get('db')
self.port = args.get('port')
self.charset = args.get('charset', 'utf8')
log_path = '/log/yunwei/yunwei_mysql.log'
self.log_ins = Log('111', log_path)
try:
self.conn = pymysql.connect(host=self.host, user=self.user,
password=self.pswd, db=self.db, port=self.port, charset=self.charset)
self.cur = self.conn.cursor()
except:
raise ValueError('mysql connect error {0}'.format(self.host))
###释放资源
def __del__(self):
self.cur.close()
self.conn.close()
def __exit__(self, exc_type, exc_val, exc_tb):
self.cur.close()
self.conn.close()
### 查询
def query(self, sql):
try:
self.cur.execute(sql) # 执行sql语句
res = self.cur.fetchall() # 获取查询的所有记录
except Exception as e:
self.log_ins.write_log("error", e)
raise e
return res
def change(self, sql):
resnum = 0
try:
resnum = self.cur.execute(sql)
# 提交
self.conn.commit()
except Exception as e:
# 错误回滚
self.log_ins.write_log("error", e)
self.conn.rollback()
return resnum
#!/usr/bin/env python
# -*-coding:utf-8-*-
'''
author : shenshuo
date : 2018-3-7
role : 工具类
'''
import time
from opssdk.logs import Log
log_path = '/log/yunwei/yunwei.log'
log_ins = Log('utils', log_path)
def timeit(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
duration = end_time - start_time
log_ins.write_log("info", '%s execute duration :%.3f second' % (str(func), duration))
return result
return wrapper
\ No newline at end of file
#!/usr/bin/env python
# -*-coding:utf-8-*-
""""
author : shenshuo
date : 2018年2月5日13:37:54
desc : SDK
"""
from distutils.core import setup
setup(
name='opssdk',
version='0.0.8',
packages=['opssdk', 'opssdk.logs', 'opssdk.operate', 'opssdk.install', 'opssdk.get_info', 'opssdk.utils', 'websdk'],
url='https://github.com/ss1917/ops_sdk/',
license='',
install_requires=['fire', 'shortuuid', 'pymysql===0.9.3', 'sqlalchemy===1.1.14', 'python3-pika===0.9.14', 'PyJWT',
'Crypto===1.4.1', 'requests', 'redis===2.10.6', 'tornado===5.0',
'aliyun-python-sdk-core-v3===2.8.6', 'aliyun-python-sdk-dysmsapi','python-dateutil===2.7.5'],
author='shenshuo',
author_email='191715030@qq.com',
description='SDK of the operation and maintenance script'
'logs'
'operate'
)
#!/usr/bin/env python
# -*-coding:utf-8-*-
"""
Author : ming
date : 2018年1月12日13:43:27
role : 定制 Application
"""
from shortuuid import uuid
from tornado import httpserver, ioloop
from tornado import options as tnd_options
from tornado.options import options, define
from tornado.web import Application as tornadoApp
from .web_logs import ins_log
from .configs import configs
define("addr", default='0.0.0.0', help="run on the given ip address", type=str)
define("port", default=8000, help="run on the given port", type=int)
define("progid", default=str(uuid()), help="tornado progress id", type=str)
class Application(tornadoApp):
""" 定制 Tornado Application 集成日志、sqlalchemy 等功能 """
def __init__(self, handlers=None, default_host="", transforms=None, **settings):
tnd_options.parse_command_line()
if configs.can_import:
configs.import_dict(**settings)
ins_log.read_log('info', '%s' % options.progid)
super(Application, self).__init__(handlers, default_host, transforms, **configs)
http_server = httpserver.HTTPServer(self)
http_server.listen(options.port, address=options.addr)
self.io_loop = ioloop.IOLoop.instance()
def start_server(self):
"""
启动 tornado 服务
:return:
"""
try:
ins_log.read_log('info', 'progressid: %(progid)s' % dict(progid=options.progid))
ins_log.read_log('info', 'server address: %(addr)s:%(port)d' % dict(addr=options.addr, port=options.port))
ins_log.read_log('info', 'web server start sucessfuled.')
self.io_loop.start()
except KeyboardInterrupt:
self.io_loop.stop()
except:
import traceback
ins_log.read_log('error', '%(tra)s' % dict(tra=traceback.format_exc()))
if __name__ == '__main__':
pass
#!/usr/bin/env python
# -*-coding:utf-8-*-
import shortuuid
from .cache import get_cache
from tornado.web import RequestHandler, HTTPError
from .jwt_token import AuthToken
class BaseHandler(RequestHandler):
def __init__(self, *args, **kwargs):
self.new_csrf_key = str(shortuuid.uuid())
self.user_id = None
self.username = None
self.nickname = None
self.is_super = False
self.is_superuser = self.is_super
super(BaseHandler, self).__init__(*args, **kwargs)
def prepare(self):
# 验证客户端CSRF,如请求为GET,则不验证,否则验证。最后将写入新的key
cache = get_cache()
if self.request.method != 'GET':
csrf_key = self.get_cookie('csrf_key')
pipeline = cache.get_pipeline()
result = cache.get(csrf_key, private=False, pipeline=pipeline)
cache.delete(csrf_key, private=False, pipeline=pipeline)
if result != '1':
raise HTTPError(402, 'csrf error')
cache.set(self.new_csrf_key, 1, expire=1800, private=False)
self.set_cookie('csrf_key', self.new_csrf_key)
### 登陆验证
auth_key = self.get_cookie('auth_key', None)
if not auth_key:
# if not auth_key or not self.get_secure_cookie("user_id") or not self.get_secure_cookie("username") :
# 没登录,就让跳到登陆页面
raise HTTPError(401, 'auth failed')
else:
auth_token = AuthToken()
user_info = auth_token.decode_auth_token(auth_key)
self.user_id = user_info.get('user_id', None)
self.username = user_info.get('username', None)
self.nickname = user_info.get('nickname', None)
self.is_super = user_info.get('is_superuser', False)
if not self.user_id:
raise HTTPError(401, 'auth failed')
else:
self.user_id = str(self.user_id )
self.set_secure_cookie("user_id", self.user_id)
self.set_secure_cookie("nickname", self.nickname)
self.set_secure_cookie("username", self.username)
self.is_superuser = self.is_super
### SDK 不用处理鉴权
# my_verify = MyVerify(self.user_id)
#
#
# # ### 如果不是超级管理员,开始鉴权
# if not self.is_superuser:
# # 没权限,就让跳到权限页面 0代表有权限,1代表没权限
# if not my_verify.get_verify(self.request.method, self.request.uri):
# '''如果没有权限,就刷新一次权限'''
# my_verify.write_verify()
#
# if not my_verify.get_verify(self.request.method, self.request.uri) != 0:
# raise HTTPError(403, 'request forbidden!')
### 写入日志 改为网关收集
def get_current_user(self):
return self.username
def get_current_id(self):
return self.user_id
def get_current_nickname(self):
return self.nickname
def is_superuser(self):
return self.is_superuser
def write_error(self, status_code, **kwargs):
if status_code == 404:
self.set_status(status_code)
return self.finish('找不到相关路径-404')
elif status_code == 400:
self.set_status(status_code)
return self.finish('bad request.')
elif status_code == 402:
self.set_status(status_code)
return self.finish('csrf error.')
elif status_code == 403:
self.set_status(status_code)
return self.finish('Sorry, you have no permission. Please contact the administrator')
elif status_code == 500:
self.set_status(status_code)
return self.finish('服务器内部错误')
elif status_code == 401:
self.set_status(status_code)
return self.finish('你没有登录')
else:
self.set_status(status_code)
class LivenessProbe(RequestHandler):
def get(self, *args, **kwargs):
self.write("I'm OK")
#!/usr/bin/env python
# -*-coding:utf-8-*-
"""
Author : ss
date : 2018年4月11日
role : 缓存
"""
import base64
import json
import pickle
from .consts import const
import redis
from shortuuid import uuid
from .configs import configs as my_configs
from .tools import singleton, bytes_to_unicode, convert
@singleton
class Cache(object):
def __init__(self):
self.__redis_connections = {}
redis_configs = my_configs[const.REDIS_CONFIG_ITEM]
for config_key, redis_config in redis_configs.items():
auth = redis_config[const.RD_AUTH_KEY]
host = redis_config[const.RD_HOST_KEY]
port = redis_config[const.RD_PORT_KEY]
db = redis_config[const.RD_DB_KEY]
return_utf8 = False
if const.RD_DECODE_RESPONSES in redis_config:
return_utf8 = redis_config[const.RD_DECODE_RESPONSES]
password = redis_config[const.RD_PASSWORD_KEY]
if auth:
redis_conn = redis.Redis(host=host, port=port, db=db, password=password, decode_responses=return_utf8)
else:
redis_conn = redis.Redis(host=host, port=port, db=db, decode_responses=return_utf8)
self.__redis_connections[config_key] = redis_conn
self.__salt = str(uuid())
def set(self, key, value, expire=-1, conn_key=const.DEFAULT_RD_KEY, private=True, pipeline=None):
real_key = self.__get_key(key, private)
execute_main = self.__get_execute_main(conn_key, pipeline)
if expire > 0:
execute_main.set(real_key, value, ex=expire)
else:
execute_main.set(real_key, value)
def set_json(self, key, value, expire=-1, conn_key=const.DEFAULT_RD_KEY, private=True, pipeline=None):
value = json.dumps(value)
value = base64.b64encode(value.encode('utf-8'))
self.set(key, value, expire, conn_key, private, pipeline)
def get(self, key, default='', conn_key=const.DEFAULT_RD_KEY, private=True, pipeline=None):
real_key = self.__get_key(key, private)
execute_main = self.__get_execute_main(conn_key, pipeline)
if execute_main.exists(real_key):
result = execute_main.get(real_key)
return bytes_to_unicode(result)
return default
def incr(self, key, private=True,
conn_key=const.DEFAULT_RD_KEY, amount=1):
real_key = self.__get_key(key, private)
execute_main = self.__get_execute_main(conn_key, None)
if execute_main.exists(real_key):
execute_main.incr(real_key, amount=amount)
return self.get(key, default='0',
private=private, conn_key=conn_key)
return None
def get_json(self, key, default='',
conn_key=const.DEFAULT_RD_KEY, private=True):
result = self.get(key, default, conn_key, private)
result = base64.b64decode(result)
result = bytes_to_unicode(result)
if result:
result = json.loads(result)
return result
def delete(self, *keys, conn_key=const.DEFAULT_RD_KEY, private=True, pipeline=None):
execute_main = self.__get_execute_main(conn_key, pipeline)
_keys = [self.__get_key(key, private) for key in keys]
return execute_main.delete(*_keys)
def clear(self, conn_key=const.DEFAULT_RD_KEY):
execute_main = self.__get_execute_main(conn_key, None)
execute_main.flushdb()
def get_pipeline(self, conn_key=const.DEFAULT_RD_KEY):
return self.__redis_connections[conn_key].pipeline()
def execute_pipeline(self, pipeline):
if pipeline:
return pipeline.execute()
def get_conn(self, conn_key=const.DEFAULT_RD_KEY):
return self.__get_execute_main(conn_key)
def hgetall(self, key, default='', conn_key=const.DEFAULT_RD_KEY, private=True):
real_key = self.__get_key(key, private)
execute_main = self.__get_execute_main(conn_key, None)
if execute_main.exists(real_key):
result = execute_main.hgetall(real_key)
result = convert(result)
else:
return default
return result
@property
def redis(self):
return self.__get_execute_main()
def __get_key(self, key, private=True):
if private:
return '%s%s' % (self.__salt, key)
else:
return key
def __get_execute_main(self, conn_key=const.DEFAULT_RD_KEY, pipeline=None):
if pipeline:
return pipeline
return self.__redis_connections[conn_key]
def get_cache():
return Cache()
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Contact : 191715030@qq.com
Author : shenshuo
Date : 2018/11/26
Desc :
"""
import redis
from .consts import const
from .configs import configs
cache_conns = {}
def cache_conn(key=None, db=None):
redis_configs = configs[const.REDIS_CONFIG_ITEM]
if not key:
key = const.DEFAULT_RD_KEY
for config_key, redis_config in redis_configs.items():
auth = redis_config[const.RD_AUTH_KEY]
host = redis_config[const.RD_HOST_KEY]
port = redis_config[const.RD_PORT_KEY]
password = redis_config[const.RD_PASSWORD_KEY]
if db:
db = db
else:
db = redis_config[const.RD_DB_KEY]
return_utf8 = False
if const.RD_DECODE_RESPONSES in redis_config:
return_utf8 = redis_config[const.RD_DECODE_RESPONSES]
if auth:
redis_pool = redis.ConnectionPool(host=host, port=port, db=db, password=password,
decode_responses=return_utf8)
else:
redis_pool = redis.ConnectionPool(host=host, port=port, db=db, decode_responses=return_utf8)
cache_conns[config_key] = redis.StrictRedis(connection_pool=redis_pool)
return cache_conns[key]
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Contact : 191715030@qq.com
Author : shenshuo
Date : 2018/9/5
Desc : 配置文件
"""
# from configparser import ConfigParser
from .consts import const
from .tools import singleton
# class VMBConfig(ConfigParser):
# def optionxform(self, optionstr):
# return optionstr
@singleton
class Config(dict):
def __init__(self):
self.__can_import = True
self.__init_default()
dict.__init__(self)
def __getattr__(self, item, default=""):
if item in self:
return self[item]
return ""
@property
def can_import(self):
return self.__can_import
def import_dict(self, **kwargs):
if self.__can_import:
for k, v in kwargs.items():
self[k] = v
self.__can_import = False
else:
raise Exception('ConfigImportError')
def __init_default(self):
self['debug'] = False
self['autoreload'] = True
self[const.DB_CONFIG_ITEM] = {
const.DEFAULT_DB_KEY: {
const.DBHOST_KEY: '',
const.DBPORT_KEY: 3306,
const.DBUSER_KEY: '',
const.DBPWD_KEY: '',
const.DBNAME_KEY: '',
},
const.READONLY_DB_KEY: {
const.DBHOST_KEY: '',
const.DBPORT_KEY: 3306,
const.DBUSER_KEY: '',
const.DBPWD_KEY: '',
const.DBNAME_KEY: '',
}
}
self[const.REDIS_CONFIG_ITEM] = {
const.DEFAULT_RD_KEY: {
const.RD_HOST_KEY: '',
const.RD_PORT_KEY: 6379,
const.RD_DB_KEY: -1,
const.RD_AUTH_KEY: True,
const.RD_CHARSET_KEY: 'utf-8',
const.RD_PASSWORD_KEY: ''
}
}
self[const.MQ_CONFIG_ITEM] = {
const.DEFAULT_MQ_KEY: {
const.MQ_ADDR: '',
const.MQ_PORT: 5672,
const.MQ_VHOST: '/',
const.MQ_USER: '',
const.MQ_PWD: '',
}
}
# self[const.APP_NAME] = ''
# self[const.LOG_TO_FILE] = False
def has_item(self, item):
return item in self
def clear(self):
self.__can_import = True
dict.clear(self)
self.__init_default()
@staticmethod
def __get_key_dict(sub_set, key):
if key in sub_set:
sk_dict = sub_set[key]
else:
sk_dict = {}
sub_set[key] = sk_dict
return sk_dict
configs = Config()
#!/usr/bin/env python
# -*-coding:utf-8-*-
'''
Author : ming
date : 2017/4/11 下午1:54
role : 常量管理
'''
from enum import IntEnum as Enum
class ConstError(TypeError):
pass
class IntEnum(Enum):
@staticmethod
def find_enum(cls, value):
for k, v in cls._value2member_map_.items():
if k == value:
return v
return None
class ErrorCode(IntEnum):
""" 错误码枚举 """
not_found = 404
bad_request = 400
unauthorized = 401
forbidden = 403
not_allowed = 405
not_acceptable = 406
conflict = 409
gone = 410
precondition_failed = 412
request_entity_too_large = 413
unsupport_media_type = 415
internal_server_error = 500
service_unavailable = 503
service_not_implemented = 501
handler_uncatched_exception = 504
config_import_error = 1001
config_item_notfound_error = 1002
class _const(object):
def __setattr__(self, name, value):
if name in self.__dict__:
raise ConstError("Can't rebind const (%s)" % name)
if not name.isupper():
raise ConstError("Const must be upper.")
self.__dict__[name] = value
const = _const()
const.DB_CONFIG_ITEM = 'databases'
const.DBHOST_KEY = 'host'
const.DBPWD_KEY = 'pwd'
const.DBUSER_KEY = 'user'
const.DBNAME_KEY = 'name'
const.DBPORT_KEY = 'port'
const.SF_DB_KEY = 'vmobel'
const.DEFAULT_DB_KEY = 'default'
const.READONLY_DB_KEY = 'readonly'
const.REDIS_CONFIG_ITEM = 'redises'
const.RD_HOST_KEY = 'host'
const.RD_PORT_KEY = 'port'
const.RD_DB_KEY = 'db'
const.RD_AUTH_KEY = 'auth'
const.RD_CHARSET_KEY = 'charset'
const.RD_DECODE_RESPONSES = 'decode_responses'
const.RD_PASSWORD_KEY = 'password'
const.DEFAULT_RD_KEY = 'default'
const.MQ_CONFIG_ITEM = 'mqs'
const.MQ_ADDR = 'MQ_ADDR'
const.MQ_PORT = 'MQ_PORT'
const.MQ_VHOST = 'MQ_VHOST'
const.MQ_USER = 'MQ_USER'
const.MQ_PWD = 'MQ_PWD'
const.DEFAULT_MQ_KEY = 'default'
const.APP_NAME = 'app_name'
const.LOG_PATH = 'log_path'
const.LOG_BACKUP_COUNT = 'log_backup_count'
const.LOG_MAX_FILE_SIZE = 'log_max_filesize'
const.REQUEST_START_SIGNAL = 'request_start'
const.REQUEST_FINISHED_SIGNAL = 'request_finished'
const.NW_SALT = 'nw'
const.ALY_SALT = 'aly'
const.TX_SALT = 'tx'
const.SG_SALT = 'sg'
const.DEFAULT_SALT = 'default'
const.SALT_API = 'salt_api'
const.SALT_USER = 'salt_username'
const.SALT_PW = 'salt_password'
const.SALT_OUT = 'salt_timeout'
const.NW_INCEPTION = 'nw'
const.ALY_INCEPTION = 'aly'
const.TX_INCEPTION = 'tx'
const.DEFAULT_INCEPTION = 'default'
const.REGION = "cn-hangzhou"
const.PRODUCT_NAME = "Dysmsapi"
const.DOMAIN = "dysmsapi.aliyuncs.com"
### app settings
const.APP_SETTINGS = 'APP_SETTINGS'
##### API GW
const.WEBSITE_API_GW_URL = 'WEBSITE_API_GW_URL'
const.EMAILLOGIN_DOMAIN = 'EMAILLOGIN_DOMAIN'
const.EMAILLOGIN_SERVER = 'EMAILLOGIN_SERVER'
##### e-mail
const.EMAIL_SUBJECT_PREFIX = "EMAIL_SUBJECT_PREFIX"
const.EMAIL_HOST = "EMAIL_HOST"
const.EMAIL_PORT = "EMAIL_PORT"
const.EMAIL_HOST_USER = "EMAIL_HOST_USER"
const.EMAIL_HOST_PASSWORD = "EMAIL_HOST_PASSWORD"
const.EMAIL_USE_SSL = "EMAIL_USE_SSL"
const.EMAIL_USE_TLS = "EMAIL_USE_TLS"
### 短信配置
const.SMS_REGION = "SMS_REGION"
const.SMS_PRODUCT_NAME = "SMS_PRODUCT_NAME"
const.SMS_DOMAIN = "SMS_DOMAIN"
const.SMS_ACCESS_KEY_ID = 'SMS_ACCESS_KEY_ID'
const.SMS_ACCESS_KEY_SECRET = 'SMS_ACCESS_KEY_SECRET'
### 钉钉
const.DING_TALK_WEBHOOK = "DING_TALK_WEBHOOK"
### 存储
const.STORAGE_REGION = "STORAGE_REGION"
const.STORAGE_NAME = "STORAGE_NAME"
const.STORAGE_PATH = "STORAGE_PATH"
const.STORAGE_KEY_ID = "STORAGE_KEY_ID"
const.STORAGE_KEY_SECRET = "STORAGE_KEY_SECRET"
# -*-coding:utf-8-*-
"""
Author : shenshuo
date : 2017年10月17日17:23:19
role : 数据库连接
"""
import pymysql
from urllib.parse import quote_plus
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from .consts import const
from .configs import configs
engines = {}
def init_engine(**settings):
if settings:
databases = settings[const.DB_CONFIG_ITEM]
else:
databases = configs[const.DB_CONFIG_ITEM]
for dbkey, db_conf in databases.items():
dbuser = db_conf[const.DBUSER_KEY]
dbpwd = db_conf[const.DBPWD_KEY]
dbhost = db_conf[const.DBHOST_KEY]
dbport = db_conf[const.DBPORT_KEY]
dbname = db_conf[const.DBNAME_KEY]
engine = create_engine('mysql+pymysql://{user}:{pwd}@{host}:{port}/{dbname}?charset=utf8'
.format(user=dbuser, pwd=quote_plus(dbpwd), host=dbhost, port=dbport, dbname=dbname),
logging_name=dbkey, pool_size=50, pool_timeout=120)
engines[dbkey] = engine
def get_db_url(dbkey):
databases = configs[const.DB_CONFIG_ITEM]
db_conf = databases[dbkey]
dbuser = db_conf['user']
dbpwd = db_conf['pwd']
dbhost = db_conf['host']
dbport = db_conf.get('port', 0)
dbname = db_conf['name']
url = 'mysql+pymysql://{user}:{pwd}@{host}:{port}/{dbname}?charset=utf8'.format(user=dbuser, pwd=quote_plus(dbpwd),
host=dbhost, port=dbport,
dbname=dbname)
return url
class DBContext(object):
def __init__(self, rw='r', db_key=None, need_commit=False, **settings):
self.__db_key = db_key
if not self.__db_key:
if rw == 'w':
self.__db_key = const.DEFAULT_DB_KEY
elif rw == 'r':
self.__db_key = const.READONLY_DB_KEY
engine = self.__get_db_engine(self.__db_key, **settings)
self.__engine = engine
self.need_commit = need_commit
@property
def db_key(self):
return self.__db_key
@staticmethod
def __get_db_engine(db_key, **settings):
if len(engines) == 0:
init_engine(**settings)
return engines[db_key]
@property
def session(self):
return self.__session
def __enter__(self):
self.__session = sessionmaker(bind=self.__engine)()
return self.__session
def __exit__(self, exc_type, exc_val, exc_tb):
if self.need_commit:
if exc_type:
self.__session.rollback()
else:
self.__session.commit()
self.__session.close()
def get_session(self):
return self.__session
from enum import IntEnum
from .consts import ErrorCode
class BaseError(Exception):
""" 错误基类,所有错误必须从该类继承 """
def __init__(self, errorcode, *args, **kwargs):
"""
初始化错误基类
:param errorcode: 错误码
:param args:
:param kwargs:
"""
if isinstance(errorcode, IntEnum):
self._errorcode = errorcode
self.kwargs = kwargs
super(BaseError, self).__init__(*args)
else:
raise TypeError(
'Error code must be vmbsdk.constants.enums.ErrorCode type.')
@property
def errorcode(self):
return self._errorcode
class BizError(BaseError):
""" 业务错误 """
def __init__(self, errorcode, *args, **kwargs):
self.__subcode = int(args[1]) if len(args) > 1 else 0
super(BizError, self).__init__(errorcode, *args, **kwargs)
@property
def subcode(self):
"""
获取
:return:
"""
return self.__subcode
class BadRequestError(BizError):
""" 错误的请求 """
def __init__(self, *args, **kwargs):
super(BadRequestError, self).__init__(ErrorCode.bad_request,
*args, **kwargs)
class ConfigError(Exception):
def __init__(self, config_key, *args, **kwargs):
self.config_key = config_key
super(ConfigError, self).__init__(*args, **kwargs)
\ No newline at end of file
import json
from tornado.httpclient import HTTPRequest, AsyncHTTPClient
from tornado.gen import coroutine
@coroutine
def fetch_coroutine(url, method='GET', body=None, **kwargs):
request = HTTPRequest(url, method=method, body=body, connect_timeout=5, request_timeout=10)
http_client = AsyncHTTPClient(**kwargs)
response = yield http_client.fetch(request)
body = json.loads(response.body)
return body
\ No newline at end of file
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import jwt, datetime,hashlib
from .configs import configs as my_configs
class AuthToken:
def __init__(self):
self.token_secret = my_configs.get('token_secret', '3AIiOq18i~H=WWTIGq4ODQyMzcsIdfghs')
def encode_auth_token(self, **kargs):
"""
生成认证Token
:param user_id: string
:param username: string
:param nickname: string
:return: string
"""
try:
payload = {
'exp': datetime.datetime.utcnow() + datetime.timedelta(days=1, seconds=10),
'nbf': datetime.datetime.utcnow() - datetime.timedelta(seconds=10),
'iat': datetime.datetime.utcnow(),
'iss': 'auth: ss',
'sub': 'my token',
'id': '15618718060',
'data': {
'user_id': kargs.get('user_id',''),
'username': kargs.get('username',''),
'nickname': kargs.get('nickname',''),
'is_superuser': kargs.get('is_superuser', False)
}
}
return jwt.encode(
payload,
self.token_secret,
algorithm='HS256'
)
except Exception as e:
return e
def decode_auth_token(self, auth_token):
"""
验证Token
:param auth_token:
:return: dict
"""
try:
payload = jwt.decode(auth_token, self.token_secret, algorithms=['HS256'],
leeway=datetime.timedelta(seconds=10))
if 'data' in payload and 'user_id' in payload['data']:
return payload['data']
else:
raise jwt.InvalidTokenError
except jwt.ExpiredSignatureError:
return dict(status=-1, msg='Token过期')
except jwt.InvalidTokenError:
return dict(status=-2, msg='无效Token')
def gen_md5(pd):
m2 = hashlib.md5()
m2.update(pd.encode("utf-8"))
return m2.hexdigest()
#!/usr/bin/env python
# -*-coding:utf-8-*-
"""
Author : ming
date : 2017/3/3 下午9:31
role : rabbitMQ 操作类
"""
import traceback
import pika
from .consts import const
from .configs import configs
from .web_logs import ins_log
from .error import ConfigError
class MessageQueueBase(object):
def __init__(self, exchange, exchange_type, routing_key='', queue_name='', no_ack=False, mq_key=''):
mq_config = configs[const.MQ_CONFIG_ITEM][const.DEFAULT_MQ_KEY]
if const.MQ_ADDR not in mq_config:
raise ConfigError(const.MQ_ADDR)
if const.MQ_PORT not in mq_config:
raise ConfigError(const.MQ_PORT)
if const.MQ_VHOST not in mq_config:
raise ConfigError(const.MQ_VHOST)
if const.MQ_USER not in mq_config:
raise ConfigError(const.MQ_USER)
if const.MQ_PWD not in mq_config:
raise ConfigError(const.MQ_PWD)
self.addr = mq_config[const.MQ_ADDR]
self.port = mq_config[const.MQ_PORT]
self.vhost = mq_config[const.MQ_VHOST]
self.user = mq_config[const.MQ_USER]
self.pwd = mq_config[const.MQ_PWD]
self.__exchange = exchange
self.__exchange_type = exchange_type
self.__routing_key = routing_key
self.__queue_name = queue_name
self.__no_ack = no_ack
def start_consuming(self):
channel = self.create_channel()
channel.exchange_declare(exchange=self.__exchange, exchange_type=self.__exchange_type)
if self.__queue_name:
result = channel.queue_declare(queue=self.__queue_name, durable=True)
else:
result = channel.queue_declare(exclusive=True)
channel.queue_bind(exchange=self.__exchange, queue=result.method.queue, routing_key=self.__routing_key)
channel.basic_qos(prefetch_count=1)
channel.basic_consume(self.call_back, queue=result.method.queue, no_ack=self.__no_ack)
ins_log.read_log('info', '[*]Queue %s started.' % (result.method.queue))
channel.start_consuming()
def __enter__(self):
self.__channel = self.create_channel()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.__connection.close()
def create_channel(self):
credentials = pika.PlainCredentials(self.user, self.pwd)
self.__connection = pika.BlockingConnection(
pika.ConnectionParameters(self.addr, self.port, self.vhost, credentials=credentials))
channel = self.__connection.channel()
return channel
def call_back(self, ch, method, properties, body):
try:
ins_log.read_log('info', 'get message')
self.on_message(body)
if not self.__no_ack:
ch.basic_ack(delivery_tag=method.delivery_tag)
except:
ins_log.read_log('error', traceback.format_exc())
if not self.__no_ack:
ch.basic_nack(delivery_tag=method.delivery_tag)
def on_message(self, body):
pass
def publish_message(self, body, durable=True):
self.__channel.exchange_declare(exchange=self.__exchange, exchange_type=self.__exchange_type)
if self.__queue_name:
result = self.__channel.queue_declare(queue=self.__queue_name)
else:
result = self.__channel.queue_declare(exclusive=True)
self.__channel.queue_bind(exchange=self.__exchange, queue=result.method.queue)
if durable:
properties = pika.BasicProperties(delivery_mode=2)
self.__channel.basic_publish(exchange=self.__exchange, routing_key=self.__routing_key, body=body,
properties=properties)
else:
self.__channel.basic_publish(exchange=self.__exchange, routing_key=self.__routing_key, body=body)
ins_log.read_log('info', 'Publish message %s sucessfuled.' % body)
#!/usr/bin/env python
# -*-coding:utf-8-*-
'''
Author : ming
date : 2017/4/11 下午3:21
desc :
'''
import fire
class MainProgram(object):
def __init__(self, progressid=''):
print(progressid)
@staticmethod
def run(cls_inst):
if issubclass(cls_inst, MainProgram):
fire.Fire(cls_inst)
else:
raise Exception('')
\ No newline at end of file
#!/usr/bin/env python
# -*-coding:utf-8-*-
'''
Author : SS
date : 2017年12月29日14:43:24
role : 集中化管理工具的使用
'''
import requests
import json
import time
try:
import cookielib
except:
import http.cookiejar as cookielib
import ssl
context = ssl._create_unverified_context()
import urllib3
urllib3.disable_warnings()
class SaltApi:
"""
定义salt api接口的类
初始化获得token
"""
def __init__(self, url='https://127.0.0.1:8001/', username="saltapi", password="shenshuo"):
self.__url = url
self.__username = username
self.__password = password
self.headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36",
"Content-type": "application/json"
# "Content-type": "application/x-yaml"
}
self.params = {'client': 'local', 'fun': '', 'tgt': ''}
self.login_url = self.__url + "login"
self.login_params = {'username': self.__username, 'password': self.__password, 'eauth': 'pam'}
self.token = self.get_data(self.login_url, self.login_params)['token']
self.headers['X-Auth-Token'] = self.token
def get_data(self, url, params):
send_data = json.dumps(params)
request = requests.post(url, data=send_data, headers=self.headers, verify=False)
response = request.json()
result = dict(response)
return result['return'][0]
def salt_command(self, tgt, method, arg=None):
"""远程执行命令,相当于salt 'client1' cmd.run 'free -m'"""
if arg:
params = {'client': 'local', 'fun': method, 'tgt': tgt, 'arg': arg}
else:
params = {'client': 'local', 'fun': method, 'tgt': tgt}
result = self.get_data(self.__url, params)
return result
def salt_async_command(self, tgt, method, arg=None): # 异步执行salt命令,根据jid查看执行结果
"""远程异步执行命令"""
if arg:
params = {'client': 'local_async', 'fun': method, 'tgt': tgt, 'arg': arg}
else:
params = {'client': 'local_async', 'fun': method, 'tgt': tgt}
jid = self.get_data(self.__url, params).get('jid', None)
return jid
def look_jid(self, jid): # 根据异步执行命令返回的jid查看事件结果
params = {'client': 'runner', 'fun': 'jobs.lookup_jid', 'jid': jid}
result = self.get_data(self.__url, params)
return result
def run(self, salt_client='*', salt_method='cmd.run_all', salt_params='w', timeout=1800):
try:
if not self.salt_command(salt_client, 'test.ping')[salt_client]:
return -98, 'test.ping error 98', ''
except Exception as e:
return -99, 'test.ping error 99', str(e)
t = 0
jid = self.salt_async_command(salt_client, salt_method, salt_params)
if not jid:
return -100, '连接失败', '连接失败或主机不存在'
while True:
time.sleep(5)
if t == timeout:
print('exec timeout!')
break
else:
t += 5
result = self.look_jid(jid)
for i in result.keys():
return result[i]['retcode'], result[i]['stdout'], result[i]['stderr']
if __name__ == '__main__':
pass
# salt1 = SaltApi()
# req = salt1.run('*', 'cmd.run_all', 'w')
# status, stdout, stderr = req[0], req[1], req[2]
# print(status, stdout, stderr)
#!/usr/bin/env python
# -*-coding:utf-8-*-
"""
author : shenshuo
date : 2018年5月22日
role :发送短信
pip install --upgrade setuptools
pip install aliyun-python-sdk-core
pip install aliyun-python-sdk-dysmsapi
"""
import sys, json
from libs.consts import const
from aliyunsdkdysmsapi.request.v20170525 import SendSmsRequest
from aliyunsdkcore.client import AcsClient
import uuid
from aliyunsdkcore.profile import region_provider
try:
reload(sys)
sys.setdefaultencoding('utf8')
except NameError:
pass
except Exception as err:
raise err
class SmsApi:
def __init__(self, sms_access_key_id, sms_access_key_secret, REGION=const.REGION, DOMAIN=const.DOMAIN,
PRODUCT_NAME=const.PRODUCT_NAME):
self.acs_client = AcsClient(sms_access_key_id, sms_access_key_secret, REGION)
region_provider.add_endpoint(PRODUCT_NAME, REGION, DOMAIN)
def send_sms(self, phone_numbers, template_param=None, sign_name="自动化", template_code="SMS_136397944"):
business_id = uuid.uuid1()
sms_request = SendSmsRequest.SendSmsRequest()
# 申请的短信模板编码,必填
sms_request.set_TemplateCode(template_code)
# 短信模板变量参数
if template_param is not None:
sms_request.set_TemplateParam(template_param)
# 设置业务请求流水号,必填。
sms_request.set_OutId(business_id)
# 短信签名
sms_request.set_SignName(sign_name)
# 短信发送的号码列表,必填。
sms_request.set_PhoneNumbers(phone_numbers)
# 调用短信发送接口,返回json
sms_response = self.acs_client.do_action_with_exception(sms_request)
##业务处理
return sms_response
if __name__ == '__main__':
pass
#!/usr/bin/env python
# -*-coding:utf-8-*-
"""
Author : ss
date : 2018年4月12日
role : 工具类
"""
import sys
import re
import subprocess
from concurrent.futures import ThreadPoolExecutor
def singleton(class_):
instances = {}
def getinstance(*args, **kwargs):
if class_ not in instances:
instances[class_] = class_(*args, **kwargs)
return instances[class_]
return getinstance
def bytes_to_unicode(input_bytes):
if sys.version_info.major >= 3:
return str(input_bytes, encoding='utf-8')
else:
return (input_bytes).decode('utf-8')
def convert(data):
if isinstance(data, bytes): return data.decode('utf8')
if isinstance(data, dict): return dict(map(convert, data.items()))
if isinstance(data, tuple): return map(convert, data)
return data
def check_password(data):
return True if re.search("^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).*$", data) and len(data) >= 8 else False
def is_mail(text, login_mail=None):
if login_mail:
if re.match(r'[0-9a-zA-Z_]{0,19}@%s' % login_mail, text):
return True
else:
return False
if re.match(r'^[0-9a-zA-Z_]{0,19}@[0-9a-zA-Z]{1,13}\.[com,cn,net]{1,3}$', text):
return True
else:
return False
class Executor(ThreadPoolExecutor):
""" 线程执行类 """
_instance = None
def __new__(cls, *args, **kwargs):
if not getattr(cls, '_instance', None):
cls._instance = ThreadPoolExecutor(max_workers=10)
return cls._instance
def exec_shell(cmd):
'''执行shell命令函数'''
sub = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, stderr = sub.communicate()
ret = sub.returncode
if ret == 0:
return ret, stdout.decode('utf-8').split('\n')
else:
return ret, stdout.decode('utf-8').replace('\n', '')
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Contact : 191715030@qq.com
Author : shenshuo
Date : 2018/12/11
Desc :
"""
import os
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from aliyunsdkdysmsapi.request.v20170525 import SendSmsRequest, QuerySendDetailsRequest
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.profile import region_provider
import uuid
class SendMail(object):
def __init__(self, mail_host, mail_port, mail_user, mail_password, mail_ssl):
"""
:param mail_host: SMTP主机
:param mail_port: SMTP端口
:param mail_user: SMTP账号
:param mail_password: SMTP密码
:param mail_ssl: SSL=True, 如果SMTP端口是465,通常需要启用SSL, 如果SMTP端口是587,通常需要启用TLS
"""
self.mail_host = mail_host
self.mail_port = mail_port
self.__mail_user = mail_user
self.__mail_password = mail_password
self.mail_ssl = mail_ssl
def send_mail(self, to_list, subject, content, subtype='plain', att=None):
"""
:param to_list: 收件人,多收件人半角逗号分割, 必填
:param subject: 标题, 必填
:param content: 内容, 必填
:param subtype: 格式,默认:plain, 可选html
:param att: 附件,支持单附件,选填
"""
msg = MIMEMultipart()
msg['Subject'] = subject ## 标题
msg['From'] = self.__mail_user ## 发件人
msg['To'] = to_list # 收件人,必须是一个字符串
# 邮件正文内容
msg.attach(MIMEText(content, subtype, 'utf-8'))
if att:
if not os.path.isfile(att):
raise FileNotFoundError('{0} file does not exist'.format(att))
dirname, filename = os.path.split(att)
# 构造附件1,传送当前目录下的 test.txt 文件
att1 = MIMEText(open(att, 'rb').read(), 'base64', 'utf-8')
att1["Content-Type"] = 'application/octet-stream'
# 这里的filename可以任意写,写什么名字,邮件中显示什么名字
att1["Content-Disposition"] = 'attachment; filename="{0}"'.format(filename)
msg.attach(att1)
try:
if self.mail_ssl:
'''SSL加密方式,通信过程加密,邮件数据安全, 使用端口465'''
# print('Use SSL SendMail')
server = smtplib.SMTP_SSL()
server.connect(self.mail_host, self.mail_port) # 连接服务器
server.login(self.__mail_user, self.__mail_password) # 登录操作
server.sendmail(self.__mail_user, to_list.split(','), msg.as_string())
server.close()
else:
# print('Use TLS SendMail')
'''使用普通模式'''
server = smtplib.SMTP()
server.connect(self.mail_host) # 连接服务器
server.login(self.__mail_user, self.__mail_password) # 登录操作
server.sendmail(self.__mail_user, to_list.split(','), msg.as_string())
server.close()
return True
except Exception as e:
print(str(e))
return False
class SendSms(object):
def __init__(self, REGION, DOMAIN, PRODUCT_NAME, sms_access_key_id, sms_access_key_secret, ):
self.acs_client = AcsClient(sms_access_key_id, sms_access_key_secret, REGION)
region_provider.add_endpoint(PRODUCT_NAME, REGION, DOMAIN)
def send_sms(self, phone_numbers, template_param=None, sign_name="ops", template_code=""):
business_id = uuid.uuid1()
sms_request = SendSmsRequest.SendSmsRequest()
# 申请的短信模板编码,必填
sms_request.set_TemplateCode(template_code)
# 短信模板变量参数
if template_param is not None:
sms_request.set_TemplateParam(template_param)
# 设置业务请求流水号,必填。
sms_request.set_OutId(business_id)
# 短信签名
sms_request.set_SignName(sign_name)
# 短信发送的号码列表,必填。
sms_request.set_PhoneNumbers(phone_numbers)
# 调用短信发送接口,返回json
sms_response = self.acs_client.do_action_with_exception(sms_request)
##业务处理
return sms_response
def query_send_detail(self, biz_id, phone_number, page_size, current_page, send_date):
query_request = QuerySendDetailsRequest.QuerySendDetailsRequest()
# 查询的手机号码
query_request.set_PhoneNumber(phone_number)
# 可选 - 流水号
query_request.set_BizId(biz_id)
# 必填 - 发送日期 支持30天内记录查询,格式yyyyMMdd
query_request.set_SendDate(send_date)
# 必填-当前页码从1开始计数
query_request.set_CurrentPage(current_page)
# 必填-页大小
query_request.set_PageSize(page_size)
# 数据提交方式
# queryRequest.set_method(MT.POST)
# 数据提交格式
# queryRequest.set_accept_format(FT.JSON)
# 调用短信记录查询接口,返回json
query_response = self.acs_client.do_action_with_exception(query_request)
# print(query_response.decode('utf-8'))
return query_response
def mail_login(user, password, mail_server='smtp.exmail.qq.com'):
### 模拟登录来验证邮箱
try:
server = smtplib.SMTP()
server.connect(mail_server)
server.login(user, password)
return True
except Exception as e:
print(user, e)
return False
if __name__ == '__main__':
pass
#!/usr/bin/env python
# -*-coding:utf-8-*-
'''
Author : ss
date : 2018-3-19
role : web log
'''
import logging
import os
import time
from shortuuid import uuid
log_fmt = ''.join(('PROGRESS:%(progress_id) -5s %(levelname) ', '-10s %(asctime)s %(name) -25s %(funcName) '
'-30s LINE.NO:%(lineno) -5d : %(message)s'))
log_key = 'logger_key'
def singleton(class_):
instances = {}
def getinstance(*args, **kwargs):
if class_ not in instances:
instances[class_] = class_(*args, **kwargs)
return instances[class_]
return getinstance
class ProgressLogFilter(logging.Filter):
def filter(self, record):
record.progress_id = Logger().progress_id
return True
@singleton
class Logger(object):
def __init__(self, progress_id='', log_file='/tmp/xxx.log'):
self.__log_key = log_key
self.progress_id = progress_id
self.log_file = log_file
def read_log(self, log_level, log_message):
###创建一个logger
if self.progress_id == '':
Logger().progress_id = str(uuid())
else:
Logger().progress_id = self.progress_id
logger = logging.getLogger(self.__log_key)
logger.addFilter(ProgressLogFilter())
logger.setLevel(logging.DEBUG)
###创建一个handler用于输出到终端
th = logging.StreamHandler()
th.setLevel(logging.DEBUG)
###定义handler的输出格式
formatter = logging.Formatter(log_fmt)
th.setFormatter(formatter)
###给logger添加handler
logger.addHandler(th)
###记录日志
level_dic = {'debug': logger.debug, 'info': logger.info, 'warning': logger.warning, 'error': logger.error,
'critical': logger.critical}
level_dic[log_level](log_message)
th.flush()
logger.removeHandler(th)
def write_log(self, log_level, log_message):
###创建一个logger
###创建一个logger
if self.progress_id == '':
Logger().progress_id = str(uuid())
else:
Logger().progress_id = self.progress_id
logger = logging.getLogger(self.__log_key)
logger.addFilter(ProgressLogFilter())
logger.setLevel(logging.DEBUG)
###建立日志目录
log_dir = os.path.dirname(self.log_file)
if not os.path.isdir(log_dir):
os.makedirs(log_dir)
###创建一个handler用于写入日志文件
fh = logging.FileHandler(self.log_file)
fh.setLevel(logging.DEBUG)
###定义handler的输出格式
formatter = logging.Formatter(log_fmt)
fh.setFormatter(formatter)
###给logger添加handler
logger.addHandler(fh)
###记录日志
level_dic = {'debug': logger.debug, 'info': logger.info, 'warning': logger.warning, 'error': logger.error,
'critical': logger.critical}
level_dic[log_level](log_message)
###删除重复记录
fh.flush()
logger.removeHandler(fh)
ins_log = Logger()
def timeit(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
duration = end_time - start_time
ins_log.read_log('info', '%s execute duration :%.3f second' % (str(func), duration))
return result
return wrapper
ins_log.write_log('info', 'xxxx')
ins_log.read_log('info', 'xxxx')
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment