codosdk 1.0.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- codosdk-1.0.0.data/data/share/doc/codo_sdk/README.md +50 -0
- codosdk-1.0.0.dist-info/LICENSE +674 -0
- codosdk-1.0.0.dist-info/METADATA +35 -0
- codosdk-1.0.0.dist-info/RECORD +45 -0
- codosdk-1.0.0.dist-info/WHEEL +6 -0
- codosdk-1.0.0.dist-info/top_level.txt +2 -0
- opssdk/__init__.py +0 -0
- opssdk/utils/__init__.py +24 -0
- websdk2/__init__.py +0 -0
- websdk2/api_set.py +43 -0
- websdk2/apis/__init__.py +9 -0
- websdk2/apis/admin_apis.py +160 -0
- websdk2/apis/agent_apis.py +44 -0
- websdk2/apis/cmdb_apis.py +22 -0
- websdk2/apis/kerrigan_apis.py +21 -0
- websdk2/apis/mgv4_apis.py +95 -0
- websdk2/apis/task_apis.py +80 -0
- websdk2/application.py +77 -0
- websdk2/base_handler.py +275 -0
- websdk2/cache.py +128 -0
- websdk2/cache_context.py +38 -0
- websdk2/client.py +173 -0
- websdk2/cloud/__init__.py +0 -0
- websdk2/cloud/qcloud_api.py +57 -0
- websdk2/cloud/ucloud_api.py +73 -0
- websdk2/cloud_utils.py +26 -0
- websdk2/configs.py +97 -0
- websdk2/consts.py +212 -0
- websdk2/db_context.py +150 -0
- websdk2/error.py +50 -0
- websdk2/fetch_coroutine.py +12 -0
- websdk2/jwt_token.py +135 -0
- websdk2/ldap.py +117 -0
- websdk2/logger.py +42 -0
- websdk2/model_utils.py +156 -0
- websdk2/mqhelper.py +120 -0
- websdk2/program.py +20 -0
- websdk2/salt_api.py +107 -0
- websdk2/sqlalchemy_pagination.py +73 -0
- websdk2/tools.py +198 -0
- websdk2/utils/__init__.py +257 -0
- websdk2/utils/cc_crypto.py +85 -0
- websdk2/utils/date_format.py +35 -0
- websdk2/utils/pydantic_utils.py +55 -0
- websdk2/web_logs.py +127 -0
websdk2/application.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*-coding:utf-8-*-
|
|
3
|
+
"""
|
|
4
|
+
Author : ming
|
|
5
|
+
date : 2018年1月12日13:43:27
|
|
6
|
+
role : 定制 Application
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
import logging
|
|
11
|
+
from shortuuid import uuid
|
|
12
|
+
from tornado import httpserver, ioloop
|
|
13
|
+
from tornado import options as tnd_options
|
|
14
|
+
from tornado.options import options, define
|
|
15
|
+
from tornado.web import Application as tornadoApp
|
|
16
|
+
from tornado.web import RequestHandler
|
|
17
|
+
from .configs import configs
|
|
18
|
+
from .logger import init_logging
|
|
19
|
+
|
|
20
|
+
# options.log_file_prefix = "/tmp/codo.log"
|
|
21
|
+
define("addr", default='0.0.0.0', help="run on the given ip address", type=str)
|
|
22
|
+
define("port", default=8000, help="run on the given port", type=int)
|
|
23
|
+
define("progid", default=str(uuid()), help="tornado progress id", type=str)
|
|
24
|
+
init_logging()
|
|
25
|
+
urls_meta_list = []
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Application(tornadoApp):
|
|
29
|
+
""" 定制 Tornado Application 集成日志、sqlalchemy 等功能 """
|
|
30
|
+
|
|
31
|
+
def __init__(self, handlers=None, default_host="", transforms=None, **settings):
|
|
32
|
+
tnd_options.parse_command_line()
|
|
33
|
+
if configs.can_import: configs.import_dict(**settings)
|
|
34
|
+
# ins_log.read_log('info', '%s' % options.progid)
|
|
35
|
+
handlers.extend([(r"/v1/probe/meta/urls/", MetaProbe), ])
|
|
36
|
+
self.urls_meta_handle(handlers)
|
|
37
|
+
max_buffer_size = configs.get('max_buffer_size')
|
|
38
|
+
max_body_size = configs.get('max_body_size')
|
|
39
|
+
super(Application, self).__init__(handlers, default_host, transforms, **configs)
|
|
40
|
+
http_server = httpserver.HTTPServer(self, max_buffer_size=max_buffer_size, max_body_size=max_body_size)
|
|
41
|
+
http_server.listen(options.port, address=options.addr)
|
|
42
|
+
self.io_loop = ioloop.IOLoop.instance()
|
|
43
|
+
|
|
44
|
+
def start_server(self):
|
|
45
|
+
"""
|
|
46
|
+
启动 tornado 服务
|
|
47
|
+
:return:
|
|
48
|
+
"""
|
|
49
|
+
try:
|
|
50
|
+
logging.info('server address: %(addr)s:%(port)d' % dict(addr=options.addr, port=options.port))
|
|
51
|
+
logging.info('web server start sucessfuled.')
|
|
52
|
+
self.io_loop.start()
|
|
53
|
+
except KeyboardInterrupt:
|
|
54
|
+
self.io_loop.stop()
|
|
55
|
+
except:
|
|
56
|
+
import traceback
|
|
57
|
+
logging.error('%(tra)s' % dict(tra=traceback.format_exc()))
|
|
58
|
+
|
|
59
|
+
def urls_meta_handle(self, urls):
|
|
60
|
+
# 数据写入内存,启动的时候上报至权限管理
|
|
61
|
+
urls_meta_list.extend([{"url": u[0], "name": u[2].get('handle_name')[0:30] if u[2].get('handle_name') else "",
|
|
62
|
+
"method": u[2].get('method') if u[2].get('method') and len(
|
|
63
|
+
u[2].get('method')) < 100 else [],
|
|
64
|
+
"status": u[2].get('handle_status')[0:2] if u[2].get('handle_status') else "y"} if len(
|
|
65
|
+
u) > 2 else {"url": u[0], "name": "暂无", "status": "y"} for u in urls])
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class MetaProbe(RequestHandler):
|
|
69
|
+
def head(self, *args, **kwargs):
|
|
70
|
+
self.write(dict(code=0, msg="Get success", count=len(urls_meta_list), data=urls_meta_list))
|
|
71
|
+
|
|
72
|
+
def get(self, *args, **kwargs):
|
|
73
|
+
self.write(dict(code=0, msg="Get success", count=len(urls_meta_list), data=urls_meta_list))
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
if __name__ == '__main__':
|
|
77
|
+
pass
|
websdk2/base_handler.py
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*-coding:utf-8-*-
|
|
3
|
+
""""
|
|
4
|
+
Contact : 191715030@qq.com
|
|
5
|
+
Author : shenshuo
|
|
6
|
+
Date : 2018年2月5日13:37:54
|
|
7
|
+
Desc : 处理API请求
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
import base64
|
|
12
|
+
import hmac
|
|
13
|
+
import logging
|
|
14
|
+
import traceback
|
|
15
|
+
from shortuuid import uuid
|
|
16
|
+
# from .cache_context import cache_conn
|
|
17
|
+
from tornado.escape import utf8, _unicode
|
|
18
|
+
from tornado.web import RequestHandler, HTTPError
|
|
19
|
+
from .jwt_token import AuthToken, jwt
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class BaseHandler(RequestHandler):
|
|
23
|
+
def __init__(self, *args, **kwargs):
|
|
24
|
+
self.new_csrf_key = str(uuid())
|
|
25
|
+
self.business_id, self.resource_group = None, None
|
|
26
|
+
self.user_id, self.username, self.nickname, self.email, self.is_super = None, None, None, None, False
|
|
27
|
+
self.is_superuser = self.is_super
|
|
28
|
+
self.token_verify = False
|
|
29
|
+
self.tenant_filter = False
|
|
30
|
+
self.params = {}
|
|
31
|
+
self.req_data = {}
|
|
32
|
+
super(BaseHandler, self).__init__(*args, **kwargs)
|
|
33
|
+
|
|
34
|
+
def initialize(self, *args, **kwargs):
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
def get_params_dict(self):
|
|
38
|
+
self.params = {k: self.get_argument(k) for k in self.request.arguments}
|
|
39
|
+
if "filter_map" in self.params:
|
|
40
|
+
try:
|
|
41
|
+
import json
|
|
42
|
+
filter_map = self.params.get('filter_map')
|
|
43
|
+
filter_map = json.loads(filter_map)
|
|
44
|
+
except:
|
|
45
|
+
filter_map = {}
|
|
46
|
+
else:
|
|
47
|
+
filter_map = {}
|
|
48
|
+
self.params['filter_map'] = filter_map
|
|
49
|
+
|
|
50
|
+
if self.tenant_filter and self.request_tenant_map and isinstance(self.request_tenant_map, dict):
|
|
51
|
+
self.params['filter_map'] = {**filter_map, **self.request_tenant_map}
|
|
52
|
+
|
|
53
|
+
if "auth_key" in self.params: self.params.pop('auth_key')
|
|
54
|
+
|
|
55
|
+
def get_req_body_dict(self):
|
|
56
|
+
if self.request.method in ("POST", "PUT", "PATCH", "DELETE"):
|
|
57
|
+
try:
|
|
58
|
+
self.req_data = json.loads(self.request.body.decode("utf-8"))
|
|
59
|
+
except json.JSONDecodeError as err:
|
|
60
|
+
logging.error(f"Error parsing JSON data in request {self.request.method} at {self.request.path}: {err}")
|
|
61
|
+
except Exception as err:
|
|
62
|
+
logging.error(f"Unexpected error in request {self.request.method} at {self.request.path}: {err}")
|
|
63
|
+
|
|
64
|
+
def codo_csrf(self):
|
|
65
|
+
pass
|
|
66
|
+
|
|
67
|
+
def check_xsrf_cookie(self):
|
|
68
|
+
if not self.settings.get('xsrf_cookies'): return
|
|
69
|
+
if self.request.method in ("GET", "HEAD", "OPTIONS") or self.request.headers.get('Sdk-Method'):
|
|
70
|
+
pass
|
|
71
|
+
else:
|
|
72
|
+
token = (
|
|
73
|
+
self.get_argument("_xsrf", None)
|
|
74
|
+
or self.request.headers.get("X-Xsrftoken")
|
|
75
|
+
or self.request.headers.get("X-Csrftoken")
|
|
76
|
+
)
|
|
77
|
+
if not token: raise HTTPError(402, "'_xsrf' argument missing from POST")
|
|
78
|
+
_, token, _ = self._decode_xsrf_token(token)
|
|
79
|
+
_, expected_token, _ = self._get_raw_xsrf_token()
|
|
80
|
+
if not token:
|
|
81
|
+
raise HTTPError(402, "'_xsrf' argument has invalid format")
|
|
82
|
+
if not hmac.compare_digest(utf8(token), utf8(expected_token)):
|
|
83
|
+
raise HTTPError(402, "XSRF cookie does not match POST argument")
|
|
84
|
+
|
|
85
|
+
def codo_login(self):
|
|
86
|
+
### 登陆验证
|
|
87
|
+
auth_key = self.get_cookie('auth_key') if self.get_cookie("auth_key") else self.request.headers.get('auth-key')
|
|
88
|
+
if not auth_key: auth_key = self.get_argument('auth_key', default=None, strip=True)
|
|
89
|
+
|
|
90
|
+
if not auth_key: raise HTTPError(401, 'auth failed')
|
|
91
|
+
|
|
92
|
+
if self.token_verify:
|
|
93
|
+
auth_token = AuthToken()
|
|
94
|
+
user_info = auth_token.decode_auth_token(auth_key)
|
|
95
|
+
else:
|
|
96
|
+
user_info = jwt.decode(auth_key, options={"verify_signature": False}).get('data')
|
|
97
|
+
|
|
98
|
+
if not user_info: raise HTTPError(401, 'auth failed')
|
|
99
|
+
|
|
100
|
+
self.user_id = user_info.get('user_id', None)
|
|
101
|
+
self.username = user_info.get('username', None)
|
|
102
|
+
self.nickname = user_info.get('nickname', None)
|
|
103
|
+
self.email = user_info.get('email', None)
|
|
104
|
+
self.is_super = user_info.get('is_superuser', False)
|
|
105
|
+
|
|
106
|
+
if not self.user_id: raise HTTPError(401, 'auth failed')
|
|
107
|
+
|
|
108
|
+
self.user_id = str(self.user_id)
|
|
109
|
+
self.set_secure_cookie("user_id", self.user_id)
|
|
110
|
+
self.set_secure_cookie("nickname", self.nickname)
|
|
111
|
+
self.set_secure_cookie("username", self.username)
|
|
112
|
+
self.set_secure_cookie("email", str(self.email))
|
|
113
|
+
self.is_superuser = self.is_super
|
|
114
|
+
|
|
115
|
+
def prepare(self):
|
|
116
|
+
### 获取url参数为字典
|
|
117
|
+
self.get_params_dict()
|
|
118
|
+
### 验证客户端CSRF
|
|
119
|
+
self.codo_csrf()
|
|
120
|
+
self.xsrf_token
|
|
121
|
+
|
|
122
|
+
### 登陆验证
|
|
123
|
+
self.codo_login()
|
|
124
|
+
|
|
125
|
+
def get_current_user(self):
|
|
126
|
+
return self.username
|
|
127
|
+
|
|
128
|
+
def get_current_id(self):
|
|
129
|
+
return self.user_id
|
|
130
|
+
|
|
131
|
+
def get_current_nickname(self):
|
|
132
|
+
return self.nickname
|
|
133
|
+
|
|
134
|
+
def get_current_email(self):
|
|
135
|
+
return self.email
|
|
136
|
+
|
|
137
|
+
def is_superuser(self):
|
|
138
|
+
return self.is_superuser
|
|
139
|
+
|
|
140
|
+
@property
|
|
141
|
+
def request_resource_group(self):
|
|
142
|
+
if not self.resource_group:
|
|
143
|
+
self.resource_group = self.get_secure_cookie("resource_group") if self.get_secure_cookie(
|
|
144
|
+
"resource_group") else self.request.headers.get('resource-group')
|
|
145
|
+
|
|
146
|
+
if not self.resource_group: return None
|
|
147
|
+
if isinstance(self.resource_group, bytes): self.resource_group = bytes.decode(self.resource_group)
|
|
148
|
+
return self.resource_group
|
|
149
|
+
|
|
150
|
+
return self.resource_group
|
|
151
|
+
|
|
152
|
+
@property
|
|
153
|
+
def request_resource_map(self):
|
|
154
|
+
if self.request_resource_group in [None, 'all', '所有项目']:
|
|
155
|
+
return dict()
|
|
156
|
+
else:
|
|
157
|
+
return dict(resource_group=self.request_resource_group)
|
|
158
|
+
|
|
159
|
+
@property
|
|
160
|
+
def request_business_id(self):
|
|
161
|
+
if not self.business_id:
|
|
162
|
+
self.business_id = self.get_secure_cookie("business_id") if self.get_secure_cookie("business_id") else \
|
|
163
|
+
self.request.headers.get('biz-id')
|
|
164
|
+
if not self.business_id: return None
|
|
165
|
+
if isinstance(self.business_id, bytes): self.business_id = bytes.decode(self.business_id)
|
|
166
|
+
return self.business_id
|
|
167
|
+
|
|
168
|
+
return self.business_id
|
|
169
|
+
|
|
170
|
+
### 新添加
|
|
171
|
+
@property
|
|
172
|
+
def request_tenant(self):
|
|
173
|
+
if self.request.headers.get('tenant'):
|
|
174
|
+
return str(base64.b64decode(self.request.headers.get('tenant')), "utf-8")
|
|
175
|
+
if self.get_secure_cookie('tenant'):
|
|
176
|
+
tenant = self.get_secure_cookie('tenant')
|
|
177
|
+
return bytes.decode(tenant) if isinstance(tenant, bytes) else tenant
|
|
178
|
+
if self.get_secure_cookie('resource_group'):
|
|
179
|
+
tenant = self.get_secure_cookie('resource_group')
|
|
180
|
+
return bytes.decode(tenant) if isinstance(tenant, bytes) else tenant
|
|
181
|
+
return None
|
|
182
|
+
|
|
183
|
+
@property
|
|
184
|
+
def request_tenantid(self):
|
|
185
|
+
if self.request.headers.get('tenantid'): return self.request.headers.get('tenantid')
|
|
186
|
+
if self.get_secure_cookie('tenantid'):
|
|
187
|
+
tenantid = self.get_secure_cookie('tenantid')
|
|
188
|
+
return bytes.decode(tenantid) if isinstance(tenantid, bytes) else tenantid
|
|
189
|
+
if self.get_secure_cookie('business_id'):
|
|
190
|
+
tenantid = self.get_secure_cookie('business_id')
|
|
191
|
+
return bytes.decode(tenantid) if isinstance(tenantid, bytes) else tenantid
|
|
192
|
+
return None
|
|
193
|
+
|
|
194
|
+
@property
|
|
195
|
+
def request_tenant_map(self):
|
|
196
|
+
if self.request_tenantid in [None, '500'] or self.request_tenant in [None, 'all', '所有项目']:
|
|
197
|
+
return dict()
|
|
198
|
+
else:
|
|
199
|
+
return dict(tenantid=self.request_tenantid)
|
|
200
|
+
|
|
201
|
+
@property
|
|
202
|
+
def biz_info_map(self):
|
|
203
|
+
from .cache_context import cache_conn
|
|
204
|
+
redis_conn = cache_conn()
|
|
205
|
+
try:
|
|
206
|
+
biz_info_str = redis_conn.get("BIZ_INFO_STR")
|
|
207
|
+
biz_info_dict = json.loads(biz_info_str.decode())
|
|
208
|
+
except Exception as err:
|
|
209
|
+
return {}
|
|
210
|
+
return biz_info_dict
|
|
211
|
+
|
|
212
|
+
@property
|
|
213
|
+
def request_username(self):
|
|
214
|
+
return self.username
|
|
215
|
+
|
|
216
|
+
@property
|
|
217
|
+
def request_user_id(self):
|
|
218
|
+
return self.user_id
|
|
219
|
+
|
|
220
|
+
@property
|
|
221
|
+
def request_nickname(self):
|
|
222
|
+
return self.nickname
|
|
223
|
+
|
|
224
|
+
@property
|
|
225
|
+
def request_email(self):
|
|
226
|
+
return self.email
|
|
227
|
+
|
|
228
|
+
@property
|
|
229
|
+
def request_is_superuser(self):
|
|
230
|
+
return self.is_superuser
|
|
231
|
+
|
|
232
|
+
def request_fullname(self):
|
|
233
|
+
return f'{self.request_username}({self.request_nickname})'
|
|
234
|
+
|
|
235
|
+
def write_error(self, status_code, **kwargs):
|
|
236
|
+
error_trace_list = traceback.format_exception(*kwargs.get("exc_info"))
|
|
237
|
+
if status_code == 404:
|
|
238
|
+
self.set_status(status_code)
|
|
239
|
+
return self.finish('找不到相关路径-404')
|
|
240
|
+
|
|
241
|
+
elif status_code == 400:
|
|
242
|
+
self.set_status(status_code)
|
|
243
|
+
return self.finish('bad request...')
|
|
244
|
+
|
|
245
|
+
elif status_code == 402:
|
|
246
|
+
self.set_status(status_code)
|
|
247
|
+
return self.finish('csrf error...')
|
|
248
|
+
|
|
249
|
+
elif status_code == 403:
|
|
250
|
+
self.set_status(status_code)
|
|
251
|
+
return self.finish('Sorry, you have no permission. Please contact the administrator')
|
|
252
|
+
|
|
253
|
+
if status_code == 500:
|
|
254
|
+
self.set_status(status_code)
|
|
255
|
+
for line in error_trace_list:
|
|
256
|
+
self.write(str(line))
|
|
257
|
+
self.finish()
|
|
258
|
+
|
|
259
|
+
elif status_code == 401:
|
|
260
|
+
self.set_status(status_code)
|
|
261
|
+
return self.finish('你没有登录')
|
|
262
|
+
|
|
263
|
+
else:
|
|
264
|
+
self.set_status(status_code)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
class LivenessProbe(RequestHandler):
|
|
268
|
+
def initialize(self, *args, **kwargs):
|
|
269
|
+
pass
|
|
270
|
+
|
|
271
|
+
def head(self, *args, **kwargs):
|
|
272
|
+
self.write(dict(code=0, msg="I'm OK"))
|
|
273
|
+
|
|
274
|
+
def get(self, *args, **kwargs):
|
|
275
|
+
self.write(dict(code=0, msg="I'm OK"))
|
websdk2/cache.py
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*-coding:utf-8-*-
|
|
3
|
+
"""
|
|
4
|
+
Author : ss
|
|
5
|
+
date : 2018年4月11日
|
|
6
|
+
role : 缓存
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import base64
|
|
10
|
+
import json
|
|
11
|
+
# import pickle
|
|
12
|
+
from .consts import const
|
|
13
|
+
import redis
|
|
14
|
+
from shortuuid import uuid
|
|
15
|
+
from .configs import configs as my_configs
|
|
16
|
+
from .tools import singleton, bytes_to_unicode, convert
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@singleton
|
|
20
|
+
class Cache(object):
|
|
21
|
+
def __init__(self):
|
|
22
|
+
self.__redis_connections = {}
|
|
23
|
+
redis_configs = my_configs[const.REDIS_CONFIG_ITEM]
|
|
24
|
+
for config_key, redis_config in redis_configs.items():
|
|
25
|
+
auth = redis_config[const.RD_AUTH_KEY]
|
|
26
|
+
host = redis_config[const.RD_HOST_KEY]
|
|
27
|
+
port = redis_config[const.RD_PORT_KEY]
|
|
28
|
+
db = redis_config[const.RD_DB_KEY]
|
|
29
|
+
return_utf8 = False
|
|
30
|
+
if const.RD_DECODE_RESPONSES in redis_config:
|
|
31
|
+
return_utf8 = redis_config[const.RD_DECODE_RESPONSES]
|
|
32
|
+
password = redis_config[const.RD_PASSWORD_KEY]
|
|
33
|
+
|
|
34
|
+
if auth:
|
|
35
|
+
redis_conn = redis.Redis(host=host, port=port, db=db, password=password, decode_responses=return_utf8)
|
|
36
|
+
else:
|
|
37
|
+
redis_conn = redis.Redis(host=host, port=port, db=db, decode_responses=return_utf8)
|
|
38
|
+
self.__redis_connections[config_key] = redis_conn
|
|
39
|
+
|
|
40
|
+
self.__salt = str(uuid())
|
|
41
|
+
|
|
42
|
+
def set(self, key, value, expire=-1, conn_key=const.DEFAULT_RD_KEY, private=True, pipeline=None):
|
|
43
|
+
real_key = self.__get_key(key, private)
|
|
44
|
+
execute_main = self.__get_execute_main(conn_key, pipeline)
|
|
45
|
+
if expire > 0:
|
|
46
|
+
execute_main.set(real_key, value, ex=expire)
|
|
47
|
+
else:
|
|
48
|
+
execute_main.set(real_key, value)
|
|
49
|
+
|
|
50
|
+
def set_json(self, key, value, expire=-1, conn_key=const.DEFAULT_RD_KEY, private=True, pipeline=None):
|
|
51
|
+
value = json.dumps(value)
|
|
52
|
+
value = base64.b64encode(value.encode('utf-8'))
|
|
53
|
+
self.set(key, value, expire, conn_key, private, pipeline)
|
|
54
|
+
|
|
55
|
+
def get(self, key, default='', conn_key=const.DEFAULT_RD_KEY, private=True, pipeline=None):
|
|
56
|
+
real_key = self.__get_key(key, private)
|
|
57
|
+
execute_main = self.__get_execute_main(conn_key, pipeline)
|
|
58
|
+
if execute_main.exists(real_key):
|
|
59
|
+
result = execute_main.get(real_key)
|
|
60
|
+
return bytes_to_unicode(result)
|
|
61
|
+
return default
|
|
62
|
+
|
|
63
|
+
def incr(self, key, private=True,
|
|
64
|
+
conn_key=const.DEFAULT_RD_KEY, amount=1):
|
|
65
|
+
real_key = self.__get_key(key, private)
|
|
66
|
+
execute_main = self.__get_execute_main(conn_key, None)
|
|
67
|
+
if execute_main.exists(real_key):
|
|
68
|
+
execute_main.incr(real_key, amount=amount)
|
|
69
|
+
return self.get(key, default='0',
|
|
70
|
+
private=private, conn_key=conn_key)
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
def get_json(self, key, default='',
|
|
74
|
+
conn_key=const.DEFAULT_RD_KEY, private=True):
|
|
75
|
+
result = self.get(key, default, conn_key, private)
|
|
76
|
+
result = base64.b64decode(result)
|
|
77
|
+
result = bytes_to_unicode(result)
|
|
78
|
+
if result:
|
|
79
|
+
result = json.loads(result)
|
|
80
|
+
return result
|
|
81
|
+
|
|
82
|
+
def delete(self, *keys, conn_key=const.DEFAULT_RD_KEY, private=True, pipeline=None):
|
|
83
|
+
execute_main = self.__get_execute_main(conn_key, pipeline)
|
|
84
|
+
_keys = [self.__get_key(key, private) for key in keys]
|
|
85
|
+
return execute_main.delete(*_keys)
|
|
86
|
+
|
|
87
|
+
def clear(self, conn_key=const.DEFAULT_RD_KEY):
|
|
88
|
+
execute_main = self.__get_execute_main(conn_key, None)
|
|
89
|
+
execute_main.flushdb()
|
|
90
|
+
|
|
91
|
+
def get_pipeline(self, conn_key=const.DEFAULT_RD_KEY):
|
|
92
|
+
return self.__redis_connections[conn_key].pipeline()
|
|
93
|
+
|
|
94
|
+
def execute_pipeline(self, pipeline):
|
|
95
|
+
if pipeline:
|
|
96
|
+
return pipeline.execute()
|
|
97
|
+
|
|
98
|
+
def get_conn(self, conn_key=const.DEFAULT_RD_KEY):
|
|
99
|
+
return self.__get_execute_main(conn_key)
|
|
100
|
+
|
|
101
|
+
def hgetall(self, key, default='', conn_key=const.DEFAULT_RD_KEY, private=True):
|
|
102
|
+
real_key = self.__get_key(key, private)
|
|
103
|
+
execute_main = self.__get_execute_main(conn_key, None)
|
|
104
|
+
if execute_main.exists(real_key):
|
|
105
|
+
result = execute_main.hgetall(real_key)
|
|
106
|
+
result = convert(result)
|
|
107
|
+
else:
|
|
108
|
+
return default
|
|
109
|
+
return result
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def redis(self):
|
|
113
|
+
return self.__get_execute_main()
|
|
114
|
+
|
|
115
|
+
def __get_key(self, key, private=True):
|
|
116
|
+
if private:
|
|
117
|
+
return '%s%s' % (self.__salt, key)
|
|
118
|
+
else:
|
|
119
|
+
return key
|
|
120
|
+
|
|
121
|
+
def __get_execute_main(self, conn_key=const.DEFAULT_RD_KEY, pipeline=None):
|
|
122
|
+
if pipeline:
|
|
123
|
+
return pipeline
|
|
124
|
+
return self.__redis_connections[conn_key]
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def get_cache():
|
|
128
|
+
return Cache()
|
websdk2/cache_context.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Contact : 191715030@qq.com
|
|
5
|
+
Author : shenshuo
|
|
6
|
+
Date : 2018/11/26
|
|
7
|
+
Desc :
|
|
8
|
+
"""
|
|
9
|
+
import redis
|
|
10
|
+
from .consts import const
|
|
11
|
+
from .configs import configs
|
|
12
|
+
|
|
13
|
+
cache_conns = {}
|
|
14
|
+
|
|
15
|
+
def cache_conn(key=None, db=None):
|
|
16
|
+
redis_configs = configs[const.REDIS_CONFIG_ITEM]
|
|
17
|
+
if not key:
|
|
18
|
+
key = const.DEFAULT_RD_KEY
|
|
19
|
+
for config_key, redis_config in redis_configs.items():
|
|
20
|
+
auth = redis_config[const.RD_AUTH_KEY]
|
|
21
|
+
host = redis_config[const.RD_HOST_KEY]
|
|
22
|
+
port = redis_config[const.RD_PORT_KEY]
|
|
23
|
+
password = redis_config[const.RD_PASSWORD_KEY]
|
|
24
|
+
if db:
|
|
25
|
+
db = db
|
|
26
|
+
else:
|
|
27
|
+
db = redis_config[const.RD_DB_KEY]
|
|
28
|
+
return_utf8 = False
|
|
29
|
+
if const.RD_DECODE_RESPONSES in redis_config:
|
|
30
|
+
return_utf8 = redis_config[const.RD_DECODE_RESPONSES]
|
|
31
|
+
|
|
32
|
+
if auth:
|
|
33
|
+
redis_pool = redis.ConnectionPool(host=host, port=port, db=db, password=password,
|
|
34
|
+
decode_responses=return_utf8)
|
|
35
|
+
else:
|
|
36
|
+
redis_pool = redis.ConnectionPool(host=host, port=port, db=db, decode_responses=return_utf8)
|
|
37
|
+
cache_conns[config_key] = redis.StrictRedis(connection_pool=redis_pool)
|
|
38
|
+
return cache_conns[key]
|
websdk2/client.py
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
""""
|
|
4
|
+
Contact : 191715030@qq.com
|
|
5
|
+
Author : shenshuo
|
|
6
|
+
Date : 2018年2月5日13:37:54
|
|
7
|
+
Desc : 处理API请求
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
import requests
|
|
12
|
+
from urllib.parse import urlencode
|
|
13
|
+
import logging
|
|
14
|
+
from .consts import const
|
|
15
|
+
from .configs import configs
|
|
16
|
+
from tornado.httpclient import AsyncHTTPClient
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class AcsClient:
|
|
22
|
+
def __init__(self, request=None, auth_key=None, headers=None, endpoint='http://gw.opendevops.cn',
|
|
23
|
+
request_timeout=10):
|
|
24
|
+
if request:
|
|
25
|
+
self.headers = request.headers
|
|
26
|
+
elif headers:
|
|
27
|
+
self.headers = headers
|
|
28
|
+
elif auth_key:
|
|
29
|
+
self.headers = {"Cookie": 'auth_key={}'.format(auth_key)}
|
|
30
|
+
else:
|
|
31
|
+
self.headers = {"Cookie": 'auth_key={}'.format(configs.get(const.API_AUTH_KEY))}
|
|
32
|
+
|
|
33
|
+
if 'If-None-Match' in self.headers: del self.headers['If-None-Match']
|
|
34
|
+
self.endpoint = endpoint
|
|
35
|
+
if configs.get(const.WEBSITE_API_GW_URL) and endpoint == 'http://gw.opendevops.cn':
|
|
36
|
+
self.endpoint = configs.get(const.WEBSITE_API_GW_URL)
|
|
37
|
+
self.headers['Sdk-Method'] = 'zQtY4sw7sqYspVLrqV'
|
|
38
|
+
self.request_timeout = request_timeout
|
|
39
|
+
|
|
40
|
+
# 设置返回为json
|
|
41
|
+
def do_action(self, **kwargs):
|
|
42
|
+
kwargs = self.with_params_data_url(**kwargs)
|
|
43
|
+
response = requests.request(kwargs.get('method'), kwargs.get('url'), headers=self.headers,
|
|
44
|
+
data=kwargs.get('body'), timeout=self.request_timeout)
|
|
45
|
+
|
|
46
|
+
return response.text
|
|
47
|
+
|
|
48
|
+
# 返回完整信息
|
|
49
|
+
def do_action_v2(self, **kwargs):
|
|
50
|
+
kwargs = self.with_params_data_url(**kwargs)
|
|
51
|
+
response = requests.request(kwargs.get('method'), kwargs.get('url'), headers=self.headers,
|
|
52
|
+
data=kwargs.get('body'), timeout=self.request_timeout)
|
|
53
|
+
return response
|
|
54
|
+
|
|
55
|
+
def do_action_v3(self, **kwargs):
|
|
56
|
+
kwargs = self.with_params_data_url(**kwargs)
|
|
57
|
+
|
|
58
|
+
request_params = {
|
|
59
|
+
'method': kwargs.get('method'),
|
|
60
|
+
'url': kwargs.get('url'),
|
|
61
|
+
'headers': self.headers,
|
|
62
|
+
'timeout': self.request_timeout
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if kwargs.get('json'):
|
|
66
|
+
request_params['json'] = kwargs['json']
|
|
67
|
+
else:
|
|
68
|
+
request_params['data'] = kwargs.get('body')
|
|
69
|
+
|
|
70
|
+
response = requests.request(**request_params)
|
|
71
|
+
return response
|
|
72
|
+
|
|
73
|
+
async def do_action_with_async(self, **kwargs):
|
|
74
|
+
|
|
75
|
+
body = await self._implementation_of_do_action(**kwargs)
|
|
76
|
+
return body
|
|
77
|
+
|
|
78
|
+
async def _implementation_of_do_action(self, **kwargs):
|
|
79
|
+
http_client = AsyncHTTPClient()
|
|
80
|
+
request = self.with_params_data_url(**kwargs)
|
|
81
|
+
# json=kwargs.get('json')
|
|
82
|
+
response = await http_client.fetch(request.get('url'), method=request.get('method'), raise_error=False,
|
|
83
|
+
body=request.get('body'), headers=self.headers,
|
|
84
|
+
request_timeout=self.request_timeout)
|
|
85
|
+
|
|
86
|
+
return response.body
|
|
87
|
+
|
|
88
|
+
# import aiohttp
|
|
89
|
+
# async def do_action_with_async_v2(self, **kwargs):
|
|
90
|
+
# body = await self._implementation_of_do_aiohttp(**kwargs)
|
|
91
|
+
# return body
|
|
92
|
+
#
|
|
93
|
+
# async def _implementation_of_do_aiohttp(self, **kwargs):
|
|
94
|
+
# async with aiohttp.ClientSession() as session:
|
|
95
|
+
# request = self.with_params_data_url(**kwargs)
|
|
96
|
+
# async with session.request(method=request['method'], url=request['url'],
|
|
97
|
+
# headers=self.headers, data=request.get('body'),
|
|
98
|
+
# timeout=self.request_timeout) as response:
|
|
99
|
+
# return await response.read()
|
|
100
|
+
|
|
101
|
+
def with_params_data_url(self, **kwargs):
|
|
102
|
+
# 重新组装URL
|
|
103
|
+
url = "{}{}".format(self.endpoint, kwargs['url'])
|
|
104
|
+
kwargs['url'] = url
|
|
105
|
+
|
|
106
|
+
if not kwargs['method']: kwargs['method'] = 'GET'
|
|
107
|
+
|
|
108
|
+
# logging.debug(f"with_params_data_url {kwargs}")
|
|
109
|
+
body = kwargs.get('body', {})
|
|
110
|
+
req_json = kwargs.get('json')
|
|
111
|
+
|
|
112
|
+
if kwargs['method'] in ['POST', 'post', 'PATCH', 'patch', 'PUT', 'put']:
|
|
113
|
+
if not (body or req_json):
|
|
114
|
+
raise TypeError('method {}, body can not be empty'.format(kwargs['method']))
|
|
115
|
+
else:
|
|
116
|
+
if not isinstance(body, dict):
|
|
117
|
+
json.loads(body)
|
|
118
|
+
|
|
119
|
+
if body and isinstance(body, dict): kwargs['body'] = json.dumps(body)
|
|
120
|
+
|
|
121
|
+
params = kwargs.get('params')
|
|
122
|
+
if params: kwargs['url'] = "{}?{}".format(url, urlencode(params))
|
|
123
|
+
|
|
124
|
+
if not self.headers: self.headers = kwargs.get('headers', {})
|
|
125
|
+
|
|
126
|
+
if kwargs['method'] not in ['GET', 'get']: self.headers['Content-Type'] = 'application/json'
|
|
127
|
+
|
|
128
|
+
return kwargs
|
|
129
|
+
|
|
130
|
+
@staticmethod
|
|
131
|
+
def help():
|
|
132
|
+
help_info = """
|
|
133
|
+
headers = {"Cookie": 'auth_key={}'.format(auth_key)}
|
|
134
|
+
### 三种实例化方式
|
|
135
|
+
1. client = AcsClient(endpoint=endpoint, headers=headers)
|
|
136
|
+
2. client = AcsClient(endpoint=endpoint, request=self.request)
|
|
137
|
+
3. client = AcsClient(endpoint=endpoint, auth_key=auth_key)
|
|
138
|
+
|
|
139
|
+
调用: 传入api 的参数,可以参考下面示例
|
|
140
|
+
|
|
141
|
+
同步
|
|
142
|
+
response = client.do_action(**api_set.get_users)
|
|
143
|
+
print(json.loads(response))
|
|
144
|
+
|
|
145
|
+
异步
|
|
146
|
+
# import asyncio
|
|
147
|
+
# loop = asyncio.get_event_loop()
|
|
148
|
+
# ### 使用gather或者wait可以同时注册多个任务,实现并发
|
|
149
|
+
# # task1 = asyncio.ensure_future(coroutine1)
|
|
150
|
+
# # task2 = asyncio.ensure_future(coroutine2)
|
|
151
|
+
# # tasks = asyncio.gather(*[task1, task2])
|
|
152
|
+
# # loop.run_until_complete(tasks)
|
|
153
|
+
# ### 单个使用
|
|
154
|
+
# response = loop.run_until_complete(client.do_action_with_async(**api_set.get_users))
|
|
155
|
+
# response = json.loads(response)
|
|
156
|
+
# print(response)
|
|
157
|
+
# loop.close()
|
|
158
|
+
|
|
159
|
+
tornado 项目内必须使用异步,不过可以直接使用
|
|
160
|
+
from websdk2.client import AcsClient
|
|
161
|
+
from websdk2.api_set import api_set
|
|
162
|
+
async def get(self):
|
|
163
|
+
endpoint = ''
|
|
164
|
+
client = AcsClient(endpoint=endpoint, headers=self.request.headers)
|
|
165
|
+
response = await client.do_action_with_async(**api_set.get_users)
|
|
166
|
+
return self.write(response)
|
|
167
|
+
|
|
168
|
+
"""
|
|
169
|
+
return help_info
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
if __name__ == '__main__':
|
|
173
|
+
pass
|
|
File without changes
|