14 |
15 |
WEB API对接文档
{% if request.GET.module %}
回到模块列表页{% endif %}
16 |
17 |
18 | {% if request.GET.module %}
19 | {% for i,j in result %}
20 | {% if i == request.GET.module %}
21 |
{{ i }}模块
22 | {% for k,l in j %}
23 |
{{ k }}
24 |
接口路径:/api/api_gateway?method={{ k }}
25 |
传参形式:POST
26 |
41 | {% endfor %}
42 | {% endif %}
43 | {% endfor %}
44 | {% else %}
45 | {% for i,j in result %}
46 |
47 |
{{ i }}模块 点击进入
49 | {% endfor %}
50 | {% endif %}
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/cap/cap/api/utils/__init__.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 | # write by zhou
--------------------------------------------------------------------------------
/cap/cap/api/utils/aes.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 | # write by zhou
3 |
4 |
5 | from Crypto.Cipher import AES
6 | import sys
7 | import base64
8 | if sys.getdefaultencoding()!="utf8":
9 | reload(sys)
10 | sys.setdefaultencoding("utf8")
11 | def aes_encrypt(key,string):
12 | aes=AES.new(key)
13 | string+="Gc654321"
14 | string+=(32-len(string))*" "
15 | _u=aes.encrypt(string)
16 | return base64.b64encode(_u)
17 |
18 | def aes_decrypt(key,string):
19 | _u=base64.b64decode(string)
20 | aes=AES.new(key)
21 | _u=aes.decrypt(_u)
22 | assert _u.count("Gc654321")==1
23 | return _u.strip().replace("Gc654321","")
24 |
25 | if __name__=="__main__":
26 | a=aes_encrypt("1111111111111111","1111111111")
27 | print a
28 | print aes_decrypt("1111111111111111",a)
29 | key="1"*32
30 | key="bxapp"+key[15:]
31 | print aes_encrypt("1111111111111111",key)
--------------------------------------------------------------------------------
/cap/cap/api/utils/md5.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 | # write by zhou
3 | import hashlib
4 |
5 |
6 | def md5(str):
7 | return hashlib.md5(str).hexdigest()
--------------------------------------------------------------------------------
/cap/cap/api/views/__init__.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | __author__ = 'zhou'
3 | # --------------------------------
4 | # Created by zhou on 2017/02/20.
5 | # ---------------------------------
6 | from itertools import groupby
7 | from collections import OrderedDict
8 | from django.shortcuts import render_to_response
9 | from django.template.context import RequestContext
10 | import os
11 | from django.http import HttpResponse
12 | import json
13 | from django.views.decorators.csrf import csrf_exempt
14 | import sys
15 | from ..utils.aes import *
16 | import random
17 | import time
18 | from ..utils.md5 import *
19 |
20 | JsonResponse = lambda x: HttpResponse(json.dumps(x), mimetype="application/javascript")
21 | _modules = os.listdir(os.path.dirname(__file__))
22 | __all__ = [i.replace(".py", "") for i in _modules if i.endswith(".py") and (not i.startswith("__"))]
23 |
24 | __all__ += ["api_gateway", "api_document", "meta_test","get_session_key"]
25 |
26 |
27 | def get_session_key(request):
28 | key = md5(str(random.random()) + str(time.time()))
29 | key = aes_encrypt("1" * 16, "bxmppi" + key[16:])
30 | result = JsonResponse({"errorCode": 0, "data": key, "message": "success", "formError": {}})
31 | if request.META.get("HTTP_ORIGIN",""):
32 | result["Access-Control-Allow-Origin"] = request.META.get("HTTP_ORIGIN","")
33 | return result
34 |
35 |
36 | def meta_test(request):
37 | data = dict(
38 | [(i, j) for i, j in request.META.items() if isinstance(i, (str, unicode)) and isinstance(j, (str, unicode))])
39 | return JsonResponse(data)
40 |
41 |
42 | @csrf_exempt
43 | def api_gateway(request):
44 | method = request.GET.get("method", "")
45 | version = request.GET.get("version", "")
46 | _ = sys.api_config.get(method)
47 | if _:
48 | function = _.get(version) or _.get("")
49 | if function:
50 | return function(request)
51 | return JsonResponse({"errorCode": 404, "data": None, "message": "can not find the method!", "formError": {}})
52 |
53 |
54 | def api_document(request):
55 | if hasattr(sys, "api_config"):
56 | info = sys.api_config.items()
57 | else:
58 | info = []
59 | info.sort(key=lambda x: x[0])
60 | result = OrderedDict()
61 | for module_name, _iter in groupby(info, key=lambda x: ".".join(x[0].split(".")[:-1])):
62 | result[module_name] = []
63 | for j in _iter:
64 | ver_list = []
65 | for k, l in sorted(j[1].items(), key=lambda x: x[0]):
66 | ver_list.append([k, l.__doc__ or ''])
67 | result[module_name].append((j[0], ver_list))
68 | result = result.items()
69 | return render_to_response("api_document.html", locals(), context_instance=RequestContext(request))
70 |
71 |
--------------------------------------------------------------------------------
/cap/cap/api/views/cron_task.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 | # write by zhou
3 |
4 | from ..decorators import *
5 | from cap.models import *
6 | from django.core.paginator import Paginator,EmptyPage,InvalidPage
7 | from txscheduling.cron import CronSchedule
8 |
9 |
10 | @web_api(True)
11 | def cron_all(request):
12 | '''获取所有的计划任务
13 | 参数:
14 | worker_id int, worker的id,【非必选】,
15 | group_id int,group 的id,【非必选】
16 | status int,状态 ,【非必选】 -1 禁用 1 启用 0 待部署 2正在部署 3部署失败
17 | owner string,创建人,【非必选】,
18 | page 页数, 默认为 1
19 | num 每页的个数,默认为10
20 | '''
21 | post_info = request.POST
22 | page = post_info.get("page","1")
23 | num = post_info.get('num',"10")
24 | worker_id = post_info.get("worker_id","")
25 | group_id = post_info.get("group_id","")
26 | status = post_info.get("status","")
27 | owner = post_info.get("owner","")
28 | query_params = {}
29 | if worker_id:
30 | query_params["worker_id"] = int(worker_id)
31 | if group_id:
32 | query_params["group_id"] = int(group_id)
33 | if status:
34 | query_params["status"] = int(status)
35 | if owner:
36 | query_params["owner"] = owner
37 | page = int(page)
38 | num = int(num)
39 | all_info = CronTask.objects.filter(**query_params).order_by("-tid")
40 | paginator = Paginator(all_info,num)
41 | try:
42 | info = paginator.page(page)
43 | except EmptyPage:
44 | page = 1
45 | info = paginator.page(1)
46 | result = {"data_list":[],"total_page":paginator.num_pages,"current_page":page,
47 | "total_count":paginator.count
48 | }
49 | for i in info:
50 | _ = {}
51 | group = i.group
52 | worker = i.worker
53 | load = worker.cpu_mem_load_now()
54 | _["tid"] = i.tid
55 | _["name"] = i.name
56 | _["uptime"] = i.uptime
57 | _["run_times"] = i.run_times
58 | _["rule"] = i.rule
59 | _["status"] = i.get_status()
60 | _["group"] = {"id":group.id,"name":group.name}
61 | _["info"] = i.info
62 | _["owner"] = i.owner
63 | _["worker"] = {"ip":worker.ip,
64 | "is_alive":worker.is_alive(),
65 | "load":load,
66 | "total_cpu":worker.total_cpu,
67 | "total_mem":worker.total_mem,
68 | "id":worker.id}
69 | _["worker_id"] = worker.id
70 | result["data_list"].append(_)
71 | return result
72 |
73 |
74 | @web_api(True)
75 | def cron_one_info(request):
76 | '''获取单个计划任务的信息
77 | 参数:
78 | tid int, 任务的id,【必选】,
79 | '''
80 | post_info = request.POST
81 | tid = post_info.get("tid")
82 | tid = int(tid)
83 | try:
84 | i = CronTask.objects.get(tid=tid)
85 | except CronTask.DoesNotExist:
86 | raise FieldError("tid","该任务已被删除!")
87 | else:
88 | _ = {}
89 | group = i.group
90 | worker = i.worker
91 | load = worker.cpu_mem_load_now()
92 | _["tid"] = i.tid
93 | _["name"] = i.name
94 | _["uptime"] = i.uptime
95 | _["run_times"] = i.run_times
96 | _["rule"] = i.rule
97 | _["status"] = i.get_status()
98 | _["group"] = {"id":group.id,"name":group.name}
99 | _["info"] = i.info
100 | _["owner"] = i.owner
101 | _["worker"] = {"ip":worker.ip,
102 | "is_alive":worker.is_alive(),
103 | "load":load,
104 | "total_cpu":worker.total_cpu,
105 | "total_mem":worker.total_mem,
106 | "id":worker.id}
107 | _["repo_id"] = i.repo_id
108 | _["version"] = i.version
109 | _["pre_build"] = i.pre_build
110 | _["run_cmd"] = i.run_cmd
111 | _["worker_id"] = i.worker_id
112 | _["group_id"] = i.group_id
113 | return _
114 |
115 |
116 | @web_api(True)
117 | def cron_add(request):
118 | '''
119 | 创建计划任务
120 | 参数:
121 | name 名称
122 | rule 计划任务规则
123 | repo_id 代码库id
124 | version 代码库的版本
125 | pre_build 预构建命令
126 | info 说明
127 | run_cmd 运行命令
128 | worker_id worker的id
129 | group_id 分组的id
130 | '''
131 | post_info = request.POST
132 | name = post_info.get("name","")
133 | rule = post_info.get("rule","").strip()
134 | repo_id = post_info.get("repo_id","")
135 | version = post_info.get("version","").strip()
136 | pre_build = post_info.get("pre_build","")
137 | info = post_info.get("info","")
138 | run_cmd = post_info.get("run_cmd","").strip()
139 | worker_id = post_info.get("worker_id")
140 | group_id = post_info.get("group_id")
141 | if not name:
142 | raise FieldError("name","名称不能为空")
143 | if not rule:
144 | raise FieldError("rule","时间规则不能为空")
145 | try:
146 | CronSchedule(rule)
147 | except:
148 | raise FieldError("rule","时间规则不合法!")
149 | if not repo_id:
150 | raise FieldError("repo_id","请选择一个代码库")
151 | repo_id = int(repo_id)
152 | Repo.objects.get(id=int(repo_id))
153 | if not version:
154 | raise FieldError("version","版本不能为空!")
155 | if not run_cmd:
156 | raise FieldError("run_cmd","执行命令不能为空!")
157 | if not worker_id:
158 | raise FieldError("worker_id","请选择一个worker节点")
159 | work_id = int(worker_id)
160 | _worker = Worker.objects.get(id=int(work_id))
161 | if not group_id:
162 | raise FieldError("groupid","请选择一个分组")
163 | if not _worker.is_alive():
164 | raise FieldError("worker_id","worker节点已经下线!")
165 | group_id = int(group_id)
166 | Group.objects.get(id=group_id)
167 | _ = CronTask(name=name,rule=rule,repo_id=repo_id,version=version,pre_build=pre_build,info=info,
168 | owner=request.user.username,run_cmd=run_cmd,worker_id=work_id,group_id=group_id)
169 | _.save()
170 | _.pure_init()
171 | return True
172 |
173 |
174 | @web_api(True)
175 | def cron_edit(request):
176 | '''修改计划任务
177 | 参数:
178 | tid 计划任务的ID
179 | name 名称
180 | rule 计划任务规则
181 | repo_id 代码库id
182 | version 代码库的版本
183 | pre_build 预构建命令
184 | info 说明
185 | run_cmd 运行命令
186 | worker_id worker的id
187 | group_id 分组的id
188 | '''
189 | post_info = request.POST
190 | tid = post_info.get("tid").strip()
191 | name = post_info.get("name","").strip()
192 | rule = post_info.get("rule","").strip()
193 | repo_id = post_info.get("repo_id","")
194 | version = post_info.get("version","").strip()
195 | pre_build = post_info.get("pre_build","")
196 | info = post_info.get("info","")
197 | run_cmd = post_info.get("run_cmd","").strip()
198 | worker_id = post_info.get("worker_id")
199 | group_id = post_info.get("group_id")
200 | tid = int(tid)
201 | cron = CronTask.objects.get(tid=tid)
202 | if not name:
203 | raise FieldError("name","名称不能为空")
204 | if not rule:
205 | raise FieldError("rule","时间规则不能为空")
206 | try:
207 | CronSchedule(rule)
208 | except:
209 | raise FieldError("rule","时间规则不合法!")
210 | if not repo_id:
211 | raise FieldError("repo_id","请选择一个代码库")
212 | repo_id = int(repo_id)
213 | Repo.objects.get(id=int(repo_id))
214 | if not version:
215 | raise FieldError("version","版本不能为空!")
216 | if not run_cmd:
217 | raise FieldError("run_cmd","执行命令不能为空!")
218 | if not worker_id:
219 | raise FieldError("work_id","请选择一个worker节点")
220 | work_id = int(worker_id)
221 | _worker =Worker.objects.get(id=int(work_id))
222 | if work_id != cron.worker_id:
223 | raise FieldError("work_id","不允许修改所在的worker节点")
224 | if not group_id:
225 | raise FieldError("groupid","请选择一个分组")
226 | if not _worker.is_alive():
227 | raise FieldError("worker_id","worker节点已经下线!")
228 | group_id = int(group_id)
229 | Group.objects.get(id=group_id)
230 | if repo_id != cron.repo_id or version != cron.version or pre_build != cron.pre_build:
231 | cron.name = name
232 | cron.rule = rule
233 | cron.repo_id = repo_id
234 | cron.uptime = int(time.time())
235 | cron.version = version
236 | cron.pre_build = pre_build
237 | cron.info = info
238 | cron.run_cmd = run_cmd
239 | cron.group_id = group_id
240 | cron.save()
241 | cron.pure_init()
242 | return True
243 | else:
244 | cron.name = name
245 | cron.rule = rule
246 | cron.repo_id = repo_id
247 | cron.uptime = int(time.time())
248 | cron.version = version
249 | cron.pre_build = pre_build
250 | cron.info = info
251 | cron.run_cmd = run_cmd
252 | cron.group_id = group_id
253 | cron.enable()
254 | return True
255 |
256 |
257 | @web_api(True)
258 | def cron_delete(request):
259 | '''删除计划任务
260 | 参数:
261 | tid 任务的id
262 |
263 | '''
264 | post_info = request.POST
265 | tid = post_info.get("tid","")
266 | tid = int(tid)
267 | try:
268 | _ =CronTask.objects.get(tid=tid)
269 | except CronTask.DoesNotExist:
270 | #raise FieldError("tid","该任务已不存在!")
271 | return True
272 | else:
273 | _.disable(True)
274 | return True
275 |
276 |
277 |
278 | @web_api(True)
279 | def cron_disable(request):
280 | '''禁用计划任务
281 | 参数:
282 | tid 任务的id
283 | '''
284 | post_info = request.POST
285 | tid = post_info.get("tid")
286 | tid = int(tid)
287 | try:
288 | _ = CronTask.objects.get(tid=tid)
289 | except CronTask.DoesNotExist:
290 | raise FieldError("tid","该任务已不存在!")
291 | else:
292 | if _.worker.is_alive():
293 | try:
294 | _.disable()
295 | except Exception as e:
296 | raise FieldError("tid", str(e))
297 | else:
298 | if _.get_status() != "启用":
299 | raise FieldError("tid","该任务的状态为%s,不可禁用!"%_.get_status())
300 | _.status = -1
301 | _.save()
302 | #_.delete()
303 | return True
304 |
305 |
306 |
307 | @web_api(True)
308 | def cron_enable(request):
309 | '''启用计划任务
310 | 参数:
311 | tid 任务的id
312 | '''
313 | post_info = request.POST
314 | tid = post_info.get("tid")
315 | tid = int(tid)
316 | try:
317 | _ = CronTask.objects.get(tid=tid)
318 | except CronTask.DoesNotExist:
319 | raise FieldError("tid", "该任务已不存在!")
320 | else:
321 | if not _.worker.is_alive():
322 | raise FieldError("tid","该任务所在节点已离线!无法启用")
323 | else:
324 | if _.get_status() != "禁用":
325 | raise FieldError("tid","该任务的状态为%s,不可启用!"%_.get_status())
326 | _.enable()
327 | return True
328 |
329 |
330 |
331 | @web_api(True)
332 | def cron_publog(request):
333 | '''计划任务的代码拉取日志
334 | 参数:
335 | tid 任务的id
336 | '''
337 | post_info = request.POST
338 | tid = post_info.get("tid")
339 | try:
340 | _ = CronTask.objects.get(tid=tid)
341 | except CronTask.DoesNotExist:
342 | raise FieldError("tid","该任务不存在")
343 | else:
344 | info = PubLog.objects.filter(target_id=tid,target_type="cron").order_by("-pubid")[:10]
345 | result = []
346 | for i in info:
347 | result.append({"pubid":i.pubid,
348 | "addtime":i.addtime,
349 | "finishtime":i.finishtime,
350 | "stdout":i.stdout,
351 | "stderr":i.stderr,
352 | "state":i.get_state()})
353 | #result.reverse()
354 | return result
355 |
356 |
357 |
358 | @web_api(True)
359 | def cron_runlog(request):
360 | '''计划任务的运行日志
361 | 参数:
362 | tid 任务的id
363 | page 页数, 默认为 1
364 | num 每页的个数,默认为10
365 | '''
366 | post_info = request.POST
367 | tid = post_info.get("tid")
368 | page = post_info.get("page","1")
369 | num = post_info.get("num","10")
370 | page = int(page)
371 | num = int(num)
372 | all_info = RunLog.objects.filter(tid=tid,type="cron").order_by("-rid")
373 | paginator = Paginator(all_info,num)
374 | try:
375 | info = paginator.page(page)
376 | except EmptyPage:
377 | page = 1
378 | info = paginator.page(1)
379 | result = {"data_list":[],"total_page":paginator.num_pages,"current_page":page,
380 | # "total_num":paginator.count
381 | }
382 | for i in info:
383 | item = {}
384 | item["repo_url"] = i.repo_url
385 | item["version"] = i.version
386 | item["begintime"] = i.begintime
387 | item["endtime"] = i.endtime
388 | item["status"] = i.get_status()
389 | item["stdout"] = i.stdout
390 | item["stderror"] = i.stderror
391 | result["data_list"].append(item)
392 | return result
393 |
394 |
395 |
396 | @web_api(True)
397 | def cron_run_once(request):
398 | '''执行一次计划任务
399 | 参数:
400 | tid 任务的id
401 | '''
402 | post_info = request.POST
403 | tid = post_info.get("tid")
404 | tid = int(tid)
405 | try:
406 | _ = CronTask.objects.get(tid=tid)
407 | except CronTask.DoesNotExist:
408 | raise FieldError("tid", "该任务已不存在!")
409 | else:
410 | if not _.worker.is_alive():
411 | raise FieldError("tid","该任务所在节点已离线!无法启用")
412 | else:
413 | if _.get_status() != "启用":
414 | raise FieldError("tid","该任务的状态为%s,不可执行!"%_.get_status())
415 | else:
416 | _.run_once()
417 | return True
418 |
--------------------------------------------------------------------------------
/cap/cap/api/views/deamon_task.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 | # write by zhou
3 |
4 | from ..decorators import *
5 | from cap.models import *
6 | from django.core.paginator import Paginator,EmptyPage,InvalidPage
7 | from txscheduling.cron import CronSchedule
8 |
9 |
10 | @web_api(True)
11 | def deamon_all(request):
12 | '''获取所有的后台任务
13 | 参数:
14 | worker_id int, worker的id,【非必选】,
15 | group_id int,group 的id,【非必选】
16 | status int,状态 ,【非必选】 -1 禁用 1 启用 0 待部署 2正在部署 3部署失败
17 | owner string,创建人,【非必选】,
18 | page 页数, 默认为 1
19 | num 每页的个数,默认为10
20 | '''
21 | post_info = request.POST
22 | page = post_info.get("page","1")
23 | num = post_info.get('num',"10")
24 | worker_id = post_info.get("worker_id","")
25 | group_id = post_info.get("group_id","")
26 | status = post_info.get("status","")
27 | owner = post_info.get("owner","")
28 | query_params = {}
29 | if worker_id:
30 | query_params["worker_id"] = int(worker_id)
31 | if group_id:
32 | query_params["group_id"] = int(group_id)
33 | if status:
34 | query_params["status"] = int(status)
35 | if owner:
36 | query_params["owner"] = int(owner)
37 | page = int(page)
38 | num = int(num)
39 | all_info = DeamonTask.objects.filter(**query_params).order_by("-tid")
40 | paginator = Paginator(all_info,num)
41 | try:
42 | info = paginator.page(page)
43 | except EmptyPage:
44 | page = 1
45 | info = paginator.page(1)
46 | result = {"data_list":[],"total_page":paginator.num_pages,"current_page":page,
47 | "total_count":paginator.count
48 | }
49 | for i in info:
50 | _ = {}
51 | group = i.group
52 | worker = i.worker
53 | load = worker.cpu_mem_load_now()
54 | _["tid"] = i.tid
55 | _["name"] = i.name
56 | _["uptime"] = i.uptime
57 | _["run_times"] = i.run_times
58 | _["is_running"] = i.is_running()
59 | _["status"] = i.get_status()
60 | _["group"] = {"id":group.id,"name":group.name}
61 | _["info"] = i.info
62 | _["owner"] = i.owner
63 | _["worker"] = {"ip":worker.ip,
64 | "is_alive":worker.is_alive(),
65 | "load":load,
66 | "total_cpu":worker.total_cpu,
67 | "total_mem":worker.total_mem,
68 | "id":worker.id}
69 | _["is_running"] = i.is_running()
70 | _["worker_id"] = worker.id
71 | result["data_list"].append(_)
72 | return result
73 |
74 |
75 | @web_api(True)
76 | def deamon_one_info(request):
77 | '''获取单个后台任务的信息
78 | 参数:
79 | tid int, 任务的id,【必选】,
80 | '''
81 | post_info = request.POST
82 | tid = post_info.get("tid")
83 | tid = int(tid)
84 | try:
85 | i = DeamonTask.objects.get(tid=tid)
86 | except DeamonTask.DoesNotExist:
87 | raise FieldError("tid","该任务已被删除!")
88 | else:
89 | _ = {}
90 | group = i.group
91 | worker = i.worker
92 | load = worker.cpu_mem_load_now()
93 | _["tid"] = i.tid
94 | _["name"] = i.name
95 | _["uptime"] = i.uptime
96 | _["run_times"] = i.run_times
97 | _["status"] = i.get_status()
98 | _["group"] = {"id":group.id,"name":group.name}
99 | _["info"] = i.info
100 | _["owner"] = i.owner
101 | _["worker"] = {"ip":worker.ip,
102 | "is_alive":worker.is_alive(),
103 | "load":load,
104 | "total_cpu":worker.total_cpu,
105 | "total_mem":worker.total_mem,
106 | "id":worker.id}
107 | _["is_running"] = i.is_running()
108 | _["repo_id"] = i.repo_id
109 | _["version"] = i.version
110 | _["pre_build"] = i.pre_build
111 | _["run_cmd"] = i.run_cmd
112 | _["worker_id"] = i.worker_id
113 | _["group_id"] = i.group_id
114 | return _
115 |
116 |
117 | @web_api(True)
118 | def deamon_add(request):
119 | '''
120 | 创建后台任务
121 | 参数:
122 | name 名称
123 | repo_id 代码库id
124 | version 代码库的版本
125 | pre_build 预构建命令
126 | info 说明
127 | run_cmd 运行命令
128 | worker_id worker的id
129 | group_id 分组的id
130 | '''
131 | post_info = request.POST
132 | name = post_info.get("name","")
133 | repo_id = post_info.get("repo_id","")
134 | version = post_info.get("version","").strip()
135 | pre_build = post_info.get("pre_build","")
136 | info = post_info.get("info","")
137 | run_cmd = post_info.get("run_cmd","").strip()
138 | work_id = post_info.get("worker_id")
139 | group_id = post_info.get("group_id")
140 | if not name:
141 | raise FieldError("name","名称不能为空")
142 | if not repo_id:
143 | raise FieldError("repo_id","请选择一个代码库")
144 | repo_id = int(repo_id)
145 | Repo.objects.get(id=int(repo_id))
146 | if not version:
147 | raise FieldError("version","版本不能为空!")
148 | if not run_cmd:
149 | raise FieldError("run_cmd","执行命令不能为空!")
150 | if not work_id:
151 | raise FieldError("work_id","请选择一个worker节点")
152 | work_id = int(work_id)
153 | _worker = Worker.objects.get(id=int(work_id))
154 | if not group_id:
155 | raise FieldError("groupid","请选择一个分组")
156 | group_id = int(group_id)
157 | Group.objects.get(id=group_id)
158 | if not _worker.is_alive():
159 | raise FieldError("worker_id","worker节点已经下线!")
160 | _ = DeamonTask(name=name,repo_id=repo_id,version=version,pre_build=pre_build,info=info,
161 | owner=request.user.username,run_cmd=run_cmd,worker_id=work_id,group_id=group_id)
162 | _.save()
163 | _.pure_init()
164 | return True
165 |
166 |
167 | @web_api(True)
168 | def deamon_edit(request):
169 | '''修改后台任务
170 | 参数:
171 | tid 后台任务的ID
172 | name 名称
173 | repo_id 代码库id
174 | version 代码库的版本
175 | pre_build 预构建命令
176 | info 说明
177 | run_cmd 运行命令
178 | worker_id worker的id
179 | group_id 分组的id
180 | '''
181 | post_info = request.POST
182 | tid = post_info.get("tid").strip()
183 | name = post_info.get("name","").strip()
184 | repo_id = post_info.get("repo_id","")
185 | version = post_info.get("version","").strip()
186 | pre_build = post_info.get("pre_build","")
187 | info = post_info.get("info","")
188 | run_cmd = post_info.get("run_cmd","").strip()
189 | work_id = post_info.get("worker_id")
190 | group_id = post_info.get("group_id")
191 | tid = int(tid)
192 | deamon = DeamonTask.objects.get(tid=tid)
193 | if not name:
194 | raise FieldError("name","名称不能为空")
195 | if not repo_id:
196 | raise FieldError("repo_id","请选择一个代码库")
197 | repo_id = int(repo_id)
198 | Repo.objects.get(id=int(repo_id))
199 | if not version:
200 | raise FieldError("version","版本不能为空!")
201 | if not run_cmd:
202 | raise FieldError("run_cmd","执行命令不能为空!")
203 | if not work_id:
204 | raise FieldError("worker_id","请选择一个worker节点")
205 | work_id = int(work_id)
206 | _worker = Worker.objects.get(id=int(work_id))
207 | if work_id != deamon.worker_id:
208 | raise FieldError("work_id","不允许修改所在的worker节点")
209 | if not group_id:
210 | raise FieldError("groupid","请选择一个分组")
211 | if not _worker.is_alive():
212 | raise FieldError("worker_id","worker节点已经下线!")
213 | group_id = int(group_id)
214 | Group.objects.get(id=group_id)
215 | if repo_id != deamon.repo_id or version != deamon.version or pre_build != deamon.pre_build:
216 | deamon.name = name
217 | deamon.repo_id = repo_id
218 | deamon.uptime = int(time.time())
219 | deamon.version = version
220 | deamon.pre_build = pre_build
221 | deamon.info = info
222 | deamon.run_cmd = run_cmd
223 | deamon.group_id = group_id
224 | deamon.save()
225 | deamon.pure_init()
226 | return True
227 | else:
228 | deamon.name = name
229 | deamon.repo_id = repo_id
230 | deamon.uptime = int(time.time())
231 | deamon.version = version
232 | deamon.pre_build = pre_build
233 | deamon.info = info
234 | deamon.run_cmd = run_cmd
235 | deamon.group_id = group_id
236 | deamon.enable()
237 | return True
238 |
239 |
240 | @web_api(True)
241 | def deamon_delete(request):
242 | '''删除后台任务
243 | 参数:
244 | tid 任务的id
245 | '''
246 | post_info = request.POST
247 | tid = post_info.get("tid","")
248 | tid = int(tid)
249 | try:
250 | _ = DeamonTask.objects.get(tid=tid)
251 | except DeamonTask.DoesNotExist:
252 | #raise FieldError("tid","该任务已不存在!")
253 | return True
254 | else:
255 | try:
256 | _.disable(delete=True)
257 | except Exception as e :
258 | raise FieldError("tid",str(e))
259 | return True
260 |
261 |
262 |
263 | @web_api(True)
264 | def deamon_disable(request):
265 | '''禁用后台任务
266 | 参数:
267 | tid 任务的id
268 | '''
269 | post_info = request.POST
270 | tid = post_info.get("tid")
271 | tid = int(tid)
272 | try:
273 | _ = DeamonTask.objects.get(tid=tid)
274 | except DeamonTask.DoesNotExist:
275 | raise FieldError("tid","该任务已不存在!")
276 | else:
277 | if _.worker.is_alive():
278 | try:
279 | _.disable()
280 | except Exception as e:
281 | raise FieldError("tid", str(e))
282 | else:
283 | if _.get_status() != "启用":
284 | raise FieldError("tid","该任务的状态为%s,不可禁用!"%_.get_status())
285 | _.status = -1
286 | _.save()
287 | return True
288 |
289 |
290 |
291 | @web_api(True)
292 | def deamon_enable(request):
293 | '''启用后台任务
294 | 参数:
295 | tid 任务的id
296 | '''
297 | post_info = request.POST
298 | tid = post_info.get("tid")
299 | tid = int(tid)
300 | try:
301 | _ = DeamonTask.objects.get(tid=tid)
302 | except DeamonTask.DoesNotExist:
303 | raise FieldError("tid", "该任务已不存在!")
304 | else:
305 | if not _.worker.is_alive():
306 | raise FieldError("tid","该任务所在节点已离线!无法启用")
307 | else:
308 | if _.get_status() != "禁用":
309 | raise FieldError("tid","该任务的状态为%s,不可启用!"%_.get_status())
310 | _.enable()
311 | return True
312 |
313 |
314 |
315 | @web_api(True)
316 | def deamon_publog(request):
317 | '''后台任务的代码拉取日志
318 | 参数:
319 | tid 任务的id
320 | '''
321 | post_info = request.POST
322 | tid = post_info.get("tid")
323 | try:
324 | _ = DeamonTask.objects.get(tid=tid)
325 | except DeamonTask.DoesNotExist:
326 | raise FieldError("tid","该任务不存在")
327 | else:
328 | info = PubLog.objects.filter(target_id=tid,target_type="deamon").order_by("-pubid")[:10]
329 | result = []
330 | for i in info:
331 | result.append({"pubid":i.pubid,
332 | "addtime":i.addtime,
333 | "finishtime":i.finishtime,
334 | "stdout":i.stdout,
335 | "stderr":i.stderr,
336 | "state":i.get_state()})
337 | return result
338 |
339 |
340 |
341 | @web_api(True)
342 | def deamon_runlog(request):
343 | '''后台任务的运行日志
344 | 参数:
345 | tid 任务的id
346 | page 页数, 默认为 1
347 | num 每页的个数,默认为10
348 | '''
349 | post_info = request.POST
350 | tid = post_info.get("tid")
351 | page = post_info.get("page","1")
352 | num = post_info.get("num","10")
353 | page = int(page)
354 | num = int(num)
355 | all_info = RunLog.objects.filter(tid=tid,type="deamon").order_by("-rid")
356 | paginator = Paginator(all_info,num)
357 | try:
358 | info = paginator.page(page)
359 | except EmptyPage:
360 | page = 1
361 | info = paginator.page(1)
362 | result = {"data_list":[],"total_page":paginator.num_pages,"current_page":page,
363 | # "total_num":paginator.count
364 | }
365 | for i in info:
366 | item = {}
367 | item["repo_url"] = i.repo_url
368 | item["version"] = i.version
369 | item["begintime"] = i.begintime
370 | item["endtime"] = i.endtime
371 | item["status"] = i.get_status()
372 | item["stdout"] = i.stdout
373 | item["stderror"] = i.stderror
374 | result["data_list"].append(item)
375 | return result
376 |
377 |
378 | @web_api(True)
379 | def deamon_restart_now(request):
380 | '''立刻重启后台任务
381 | 参数:
382 | tid 任务的id
383 | '''
384 | post_info = request.POST
385 | tid = post_info.get("tid")
386 | tid = int(tid)
387 | try:
388 | _ = DeamonTask.objects.get(tid=tid)
389 | except DeamonTask.DoesNotExist:
390 | raise FieldError("tid", "该任务已不存在!")
391 | else:
392 | if not _.worker.is_alive():
393 | raise FieldError("tid","该任务所在节点已离线!无法重启任务!")
394 | else:
395 | if _.get_status() != "启用":
396 | raise FieldError("tid","该任务的状态为%s,不可重启任务!"%_.get_status())
397 | else:
398 | _.run_now()
399 | return True
400 |
401 |
--------------------------------------------------------------------------------
/cap/cap/api/views/group.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 | # write by zhou
3 |
4 | from ..decorators import *
5 | from cap.models import *
6 |
7 |
8 | @web_api(True)
9 | def group_all(request):
10 | '''获取所有分组
11 | 参数:
12 | 无
13 | '''
14 | info = Group.objects.all().order_by("-id")
15 | result = []
16 | for i in info:
17 | result.append({"id":i.id,"name":i.name,
18 | "addtime":i.addtime})
19 | return result
20 |
21 |
22 | @web_api(True)
23 | def group_add(request):
24 | '''
25 | 添加分组
26 | 参数:
27 | name 分组名
28 | '''
29 | post_info = request.POST
30 | name = post_info.get("name")
31 | info = Group.objects.filter(name=name)
32 | if info.count():
33 | raise FieldError("name","该分组已经存在!不可重复添加")
34 | else:
35 | _ = Group(name=name)
36 | _.save()
37 | return True
38 |
39 |
40 | @web_api(True)
41 | def group_edit(request):
42 | '''
43 | 修改分组
44 | 参数:
45 | id
46 | name
47 | '''
48 | post_info = request.POST
49 | name = post_info.get("name")
50 | id = post_info.get("id")
51 | id = int(id)
52 | if id == Group.objects.get(name="默认").id:
53 | raise FieldError("id","默认分组不允许修改!")
54 | try:
55 | _ = Group.objects.get(id=id)
56 | except:
57 | raise FieldError("id","该分组已经被删除!无法修改。")
58 | else:
59 | query_set = Group.objects.filter(name=name)
60 | if query_set.count() > 0 and query_set[0].id != id:
61 | raise FieldError("name","该分组名已存在!")
62 | else:
63 | _.name = name
64 | _.save()
65 | return True
66 |
67 |
68 | @web_api(True)
69 | def group_delete(request):
70 | '''
71 | 删除分组
72 | 参数:
73 | id
74 | '''
75 | post_info = request.POST
76 | id = post_info.get("id","")
77 | id = int(id)
78 | if id == Group.objects.get(name="默认").id:
79 | raise FieldError("id","默认分组不允许删除!")
80 | _ = Group.objects.filter(id=id)
81 | if not _.count():
82 | raise FieldError("id","该分组不存在!")
83 | if CronTask.objects.filter(group_id=id).count() or DeamonTask.objects.filter(group_id=id).count():
84 | raise FieldError("id","该分组正在被使用,不允许删除!")
85 | else:
86 | _.delete()
87 | return True
88 |
--------------------------------------------------------------------------------
/cap/cap/api/views/login.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 | # write by zhou
3 |
4 | from ..decorators import *
5 | from cap.models import *
6 | from django.contrib.admin.models import User
7 | from django.contrib.auth.views import auth_login,auth_logout
8 | from django.contrib.auth import authenticate,login,logout
9 |
10 |
11 | @web_api()
12 | def login(request):
13 | '''
14 | 用户登录接口
15 | 测试用户: admin gc895316
16 | 参数说明:
17 | username
18 | password
19 | '''
20 | post_info = request.POST
21 | username = post_info.get("username",'')
22 | password = post_info.get('password','')
23 | if not username:
24 | raise FieldError("username","username不能为空")
25 | if not password:
26 | raise FieldError("password","password不能为空")
27 | try:
28 | user = User.objects.get(username=username)
29 | except:
30 | raise FieldError("username","用户不存在")
31 | else:
32 | if user.check_password(password):
33 | request.apisession["uid"] = user.id
34 | return True
35 | else:
36 | raise FieldError("password","密码不正确")
37 |
38 |
39 | @web_api()
40 | def logout(request):
41 | '''
42 | 用户退出登录
43 | 参数说明:
44 | 无
45 |
46 | '''
47 | if request.user:
48 | #auth_logout(request)
49 | del request.apisession["uid"]
50 | return True
--------------------------------------------------------------------------------
/cap/cap/api/views/my.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 | # write by zhou
3 |
4 | from ..decorators import *
5 |
6 |
7 | @web_api(True)
8 | def get_my_uid(request):
9 | '''获取当前登录用户的id
10 | 参数:
11 | 无
12 | '''
13 | return request.user.id
14 |
15 |
16 |
17 | @web_api(True)
18 | def get_my_info(request):
19 | '''获取当前登录用户的详细信息
20 | 参数:
21 | 无
22 | '''
23 | return {"id":request.user.id,
24 | "username":request.user.username,
25 | }
26 |
27 |
28 | @web_api(True)
29 | def change_my_password(request):
30 | '''修改我的密码
31 | 参数:
32 | password_old 老密码
33 | password 新密码
34 | password_again 再次输入新密码
35 | '''
36 | post_info = request.POST
37 | password = post_info.get("password","")
38 | old_password = post_info.get("password_old","")
39 | password_again = post_info.get("password_again","")
40 | user = request.user
41 | if not user.check_password(old_password):
42 | raise FieldError("password_old","旧密码不正确!")
43 | if user.username == "admin":
44 | raise FieldError("username","admin用户的密码禁止修改")
45 | if not password:
46 | raise FieldError("password","密码不能为空")
47 | if len(password)<6:
48 | raise FieldError("password","密码长度不能小于6位")
49 | if password != password_again:
50 | raise FieldError("password_again","两次输入的密码不一致")
51 | user.set_password(password)
52 | user.save()
53 | return True
54 |
--------------------------------------------------------------------------------
/cap/cap/api/views/repo.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 | # write by zhou
3 |
4 | from ..decorators import *
5 | from cap.models import *
6 |
7 |
8 |
9 | @web_api(True)
10 | def repo_all(request):
11 | '''
12 | 获取所有代码库
13 | 参数:
14 | '''
15 | total_count = Repo.objects.all().count()
16 | all = Repo.objects.all().order_by("-id")
17 | result = []
18 | for i in all:
19 | result.append({"id":i.id,
20 | "addtime":i.addtime,
21 | "type":i.type,
22 | "repo_url":i.repo_url,
23 | "user":i.user,
24 | "password":i.password})
25 | return {"total_count":total_count,"repo_list":result}
26 |
27 |
28 | @web_api(True)
29 | def repo_add(request):
30 | '''
31 | 增加代码库
32 | 参数:
33 | type 类型 , 必传, int, 1 svn 2 git
34 | repo_url 代码仓库地址 ,必传,https://开头 或者svn://开头
35 | user 代码仓库用户, 必传
36 | password 代码仓库密码 ,必传,
37 | '''
38 | post_info = request.POST
39 | type = post_info.get("type","")
40 | type = int(type)
41 | assert type in (1,2)
42 | repo_url = post_info.get("repo_url","")
43 | if not repo_url:
44 | raise FieldError("repo_url","repo_url不能为空")
45 | user = post_info.get("user","")
46 | password = post_info.get("password","")
47 | if user:
48 | if not password:
49 | raise FieldError("password","password不能为空!")
50 | if password:
51 | if not user:
52 | raise FieldError('user',"user不能为空!")
53 | try:
54 | Repo.objects.get(repo_url=repo_url)
55 | except:
56 | repo = Repo(type=int(type),repo_url=repo_url,user=user,password=password)
57 | repo.save()
58 | repo.pure_init()
59 | return repo.id
60 | else:
61 | raise FieldError("repo_url","该代码仓库已存在!请勿重复添加!")
62 |
63 |
64 | @web_api(True)
65 | def repo_edit(request):
66 | '''
67 | 更新代码库
68 | 参数:
69 | id 代码库的id 必传, int
70 | type 类型 , 必传, int, 1 svn 2 git
71 | repo_url 代码仓库地址 ,必传,https://开头 或者svn://开头
72 | user 代码仓库用户, 必传
73 | password 代码仓库密码 ,必传,
74 | '''
75 | post_info = request.POST
76 | id = post_info.get("id","")
77 | id = int(id)
78 | repo = Repo.objects.get(id=id)
79 | type = post_info.get("type","")
80 | type = int(type)
81 | assert type in (1,2)
82 | repo_url = post_info.get("repo_url","")
83 | try:
84 | _ = Repo.objects.get(repo_url=repo_url)
85 | assert _.id != id
86 | except:
87 | pass
88 | else:
89 | raise FieldError("repo_url","repo_url和现有的代码库重复!")
90 | if not repo_url:
91 | raise FieldError("repo_url","repo_url不能为空")
92 | user = post_info.get("user","")
93 | password = post_info.get("password","")
94 | if user:
95 | if not password:
96 | raise FieldError("password","password不能为空!")
97 | if password:
98 | if not user:
99 | raise FieldError('user',"user不能为空!")
100 | repo.type = type
101 | repo.repo_url = repo_url
102 | repo.user = user
103 | repo.password = password
104 | repo.save()
105 | repo.pure_init()
106 | return True
107 |
108 |
109 | @web_api(True)
110 | def repo_delete(request):
111 | '''
112 | 删除代码库
113 | 参数:
114 | id 代码库的id 必传, int
115 | '''
116 | post_info = request.POST
117 | id = post_info.get("id")
118 | id = int(id)
119 | try:
120 | repo = Repo.objects.get(id=id)
121 | except Repo.DoesNotExist:
122 | return True
123 | else:
124 | if CronTask.objects.filter(repo_id=id).count() or DeamonTask.objects.filter(repo_id=id).count():
125 | raise FieldError("id","该代码库正在被使用,无法删除!")
126 | else:
127 | repo.disable()
128 | repo.delete()
129 | return True
130 |
131 |
132 | @web_api(True)
133 | def repo_commit_log(request):
134 | '''
135 | 查询代码库的所有提交记录
136 | 参数:
137 | id
138 | '''
139 | post_info = request.POST
140 | id = post_info.get("id")
141 | try:
142 | repo = Repo.objects.get(id=id)
143 | except Repo.DoesNotExist:
144 | return []
145 | else:
146 | repo_id = repo.id
147 | commit_logs = RepoCommitLog.objects.filter(repo_id=repo_id).order_by("-committime")[:100]
148 | result = []
149 | for i in commit_logs:
150 | result.append({"id":i.id,"ver":i.ver,
151 | "author":i.author,
152 | "committime":i.committime,
153 | "message":i.message})
154 | return result
155 |
156 |
157 | @web_api(True)
158 | def repo_monitor_log(reqeust):
159 | '''
160 | 获取代码库的更新日志
161 | '''
162 | post_info = reqeust.POST
163 | id = post_info.get("id")
164 | try:
165 | repo = Repo.objects.get(id=id)
166 | except Repo.DoesNotExist:
167 | return ''
168 | else:
169 | repo_id = repo.id
170 | try:
171 | track_log = RepoMonitorLog.objects.filter(repo_id=repo_id)[0].log
172 | except:
173 | track_log = ''
174 | return track_log
175 |
176 |
177 |
--------------------------------------------------------------------------------
/cap/cap/api/views/user.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 | # write by zhou
3 |
4 | from ..decorators import *
5 | from cap.models import *
6 | from django.contrib.admin.models import User
7 |
8 |
9 |
10 | @web_api(True)
11 | def user_list(request):
12 | '''用户列表
13 | 所需参数:
14 | 无
15 | 返回数据说明:
16 | id 用户id
17 | username 用户名
18 | addtime 用户创建时间
19 | is_admin 是否是超级用户
20 | '''
21 | post_info = request.POST
22 | total_count = User.objects.all().order_by("-id").count()
23 | info = User.objects.all().order_by("-id")
24 | result = []
25 | for i in info:
26 | print dir(i.date_joined)
27 | result.append({"id":i.id,
28 | "username":i.username,
29 | "addtime":int(i.date_joined.strftime("%s")),
30 | "is_admin":i.is_superuser,
31 | })
32 | return {"total_count":total_count,"user_list":result}
33 |
34 |
35 |
36 | @web_api(True)
37 | def user_add(request):
38 | '''添加用户
39 | 所需参数:
40 | username 用户名
41 | password 密码
42 | password_again 再次输入密码
43 | '''
44 | post_info = request.POST
45 | username = post_info.get("username","")
46 | password = post_info.get("password","")
47 | password_again = post_info.get("password_again","")
48 | if not username:
49 | raise FieldError("username","用户名不能为空")
50 | try:
51 | User.objects.get(username=username)
52 | except:
53 | pass
54 | else:
55 | raise FieldError("username", '该用户已存在!')
56 |
57 | if not password:
58 | raise FieldError("password","密码不能为空")
59 | if len(password) < 6:
60 | raise FieldError("password","密码长度不能小于6位")
61 | if password != password_again:
62 | raise FieldError("password_again","两次输入的密码不一致")
63 | _p = User(username=username,password='')
64 | _p.save()
65 | _p.set_password(password)
66 | _p.save()
67 | return True
68 |
69 |
70 | @web_api(True)
71 | def user_resetpwd(request):
72 | '''添加用户
73 | 所需参数:
74 | username 用户名
75 | password 密码
76 | password_again 再次输入密码
77 | '''
78 | post_info = request.POST
79 | username = post_info.get("username","")
80 | password = post_info.get("password","")
81 | password_again = post_info.get("password_again","")
82 | user = User.objects.get(username=username)
83 | if request.user.username != "admin" and request.user.username!=user.username:
84 | raise FieldError("username","非admin用户不能修改其他用户的密码!")
85 | if user.username == "admin":
86 | raise FieldError("username","禁止修改admin用户的密码")
87 | if not password:
88 | raise FieldError("password","密码不能为空")
89 | if len(password)<6:
90 | raise FieldError("password","密码长度不能小于6位")
91 | if password != password_again:
92 | raise FieldError("password_again","两次输入的密码不一致")
93 | user.set_password(password)
94 | user.save()
95 | return True
96 |
97 |
98 | @web_api(True)
99 | def user_delete(request):
100 | '''
101 | 删除用户
102 | 所需参数:
103 | username
104 | '''
105 | post_info = request.POST
106 | username = post_info.get("username","")
107 | user = User.objects.get(username=username)
108 | if request.user.username != "admin":
109 | raise FieldError("username","非admin用户不能删除用户!")
110 | if user.username == "admin":
111 | raise FieldError("username","禁止删除admin用户!")
112 | user.delete()
113 | return True
114 |
115 |
116 |
117 |
--------------------------------------------------------------------------------
/cap/cap/api/views/worker.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 | # write by zhou
3 | from ..decorators import *
4 | from cap.models import *
5 | from django.core.paginator import Paginator,EmptyPage,InvalidPage
6 |
7 |
8 | @web_api(True)
9 | def worker_all(request):
10 | '''获取所有的worker (此部分不会太多,不用考虑分页)
11 | 参数:
12 | 无
13 | 返回值说明:
14 | id worker的ID
15 | ip worker的IP
16 | addtime worker的加入时间
17 | is_alive worker当前是否存活
18 | last_connect_time worker上次活跃时间
19 | total_cpu worker cpu个数
20 | total_mem worker 内存大小(MB)
21 | '''
22 | all_info = Worker.objects.all().order_by("-id")
23 | result = []
24 | for i in all_info:
25 | result.append({"id":i.id,
26 | "ip":i.ip,
27 | "addtime":i.addtime,
28 | "is_alive":i.is_alive(),
29 | "last_connect_time":i.heartbeat,
30 | "total_cpu":i.total_cpu,
31 | "total_mem":i.total_mem})
32 | return result
33 |
34 |
35 | @web_api(True)
36 | def worker_info(request):
37 | '''获取单个worker的信息
38 | 参数:
39 | id worker的id
40 | 返回值说明:
41 | id worker的ID
42 | ip worker的IP
43 | addtime worker的加入时间
44 | is_alive worker当前是否存活
45 | last_connect_time worker上次活跃时间
46 | total_cpu worker cpu个数
47 | total_mem worker内存大小(MB)
48 | '''
49 | post_info = request.POST
50 | id = post_info.get("id")
51 | id = int(id)
52 | worker = Worker.objects.get(id=id)
53 | return {"id":worker.id,
54 | "ip":worker.ip,
55 | "addtime":worker.addtime,
56 | "is_alive":worker.is_alive(),
57 | "last_connect_time":worker.heartbeat,
58 | "total_cpu":worker.total_cpu,
59 | "total_mem":worker.total_mem}
60 |
61 |
62 | @web_api(True)
63 | def worker_cpu_mem_log(request):
64 | '''获取单个worker的cpu内存负载信息
65 | 参数:
66 | id worker的id
67 |
68 | '''
69 | post_info = request.POST
70 | id = post_info.get("id")
71 | id = int(id)
72 | worker = Worker.objects.get(id=id)
73 | info = WorkerCpuMemLog.objects.filter(work_id=worker.id).order_by("-id")[:200]
74 | result = []
75 | for i in info:
76 | result.append({"time":i.addtime,
77 | "cpu_percent":i.cpu_percent,
78 | "mem_percent":i.mem_percent})
79 | result.reverse()
80 | return result
--------------------------------------------------------------------------------
/cap/cap/core_api/__init__.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 | # write by zhou
3 | from sites import site
--------------------------------------------------------------------------------
/cap/cap/core_api/sites.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | # write by zhou
3 |
4 | from django.conf.urls import include, url, patterns
5 |
6 |
7 | class CoreApi(object):
8 | def __init__(self, name="core_api", app_name="core_api"):
9 | self.name = name
10 | self.app_name = app_name
11 |
12 | def get_urls(self):
13 | return patterns("cap.core_api",
14 | url(r"^work_heartbeat/$", "views.worker.worker_heartbeat"),
15 |
16 | )
17 |
18 | @property
19 | def urls(self):
20 | return self.get_urls(), self.app_name, self.name
21 |
22 | @urls.setter
23 | def urls(self, value):
24 | pass
25 |
26 | @urls.deleter
27 | def urls(self):
28 | pass
29 |
30 |
31 | site = CoreApi()
32 |
--------------------------------------------------------------------------------
/cap/cap/core_api/views/__init__.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 | # write by zhou
--------------------------------------------------------------------------------
/cap/cap/core_api/views/worker.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 | # write by zhou
3 | from django.http import HttpResponse
4 | import json
5 | from cap.models import *
6 | from django.conf import settings
7 |
8 | buff = {}
9 |
10 | def worker_heartbeat(request):
11 | get_info = request.GET
12 | post_info = request.POST
13 | ip = request.GET.get("ip","") or request.META["REMOTE_ADDR"]
14 | work_dir = get_info.get("work_dir","")
15 | num = get_info.get("num","")
16 | num = int(num)
17 | worker = Worker.worker_heartbeat(ip,work_dir)
18 | if num == 1 or not buff.has_key(ip):
19 | buff[ip] = ip
20 | worker.pure_init()
21 | all_cron_task = CronTask.objects.filter(worker_id=worker.id)
22 | for i in all_cron_task:
23 | if i.status == 1:
24 | i.enable()
25 | all_deamon_task = DeamonTask.objects.filter(worker_id=worker.id)
26 | for i in all_deamon_task:
27 | if i.status == 1:
28 | i.enable()
29 | if ip == settings.HOST:
30 | all_repo = Repo.objects.all()
31 | for i in all_repo:
32 | i.pure_init()
33 | else:
34 | pass
35 | return HttpResponse("success")
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/cap/cap/rpc.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 | # write by zhou
3 |
4 | #coding:utf-8
5 | # write by zhou
6 |
7 |
8 |
9 | class Ping(object):
10 |
11 | def __init__(self, ip):
12 | import xmlrpclib
13 | self.ip = ip
14 | self.server = xmlrpclib.ServerProxy("http://%s:9913" % ip, allow_none=True)
15 | def ping(self):
16 | try:
17 | self.server.ping()
18 | return True
19 | except:
20 | raise Exception("[%s]:Exception:%s" % (self.ip, "该节点已经离线"))
21 |
22 |
23 | class Cache(object):
24 |
25 | def __init__(self, ip):
26 | import xmlrpclib
27 | self.ip = ip
28 | self.server = xmlrpclib.ServerProxy("http://%s:9913" % ip, allow_none=True)
29 |
30 | def set(self,key,value):
31 | try:
32 | self.server.cache_set(key,value)
33 | return True
34 | except Exception as e :
35 | raise Exception("[%s]:Exception:%s" % (self.ip, str(e)))
36 |
37 | def get(self,key):
38 | try:
39 | return self.server.cache_get(key)
40 | except Exception as e :
41 | raise Exception("[%s]:Exception:%s" % (self.ip, str(e)))
42 |
43 | def delete(self,key):
44 | try:
45 | return self.server.cache_del(key)
46 | except Exception as e :
47 | raise Exception("[%s]:Exception:%s" % (self.ip, str(e)))
48 |
49 |
50 | class Cron(object):
51 | def __init__(self,ip):
52 | import xmlrpclib
53 | self.ip = ip
54 | self.server = xmlrpclib.ServerProxy("http://%s:9913"%ip,allow_none=True)
55 |
56 | def get(self,key):
57 | try:
58 | result = self.server.cron_get(key)
59 | if isinstance(result,(list,tuple)):
60 | raise Exception(result[1])
61 | else:
62 | return result
63 | except Exception as e :
64 | raise Exception("[%s]:Exception:%s" % (self.ip, str(e)))
65 |
66 |
67 | def set(self,key,cron_mode,cron_function,cron_callback,cron_errback,stdout_callback,
68 | stderr_callback):
69 | import xmlrpclib,cloudpickle
70 | #cron_function.__module__ = "__main__"
71 | cron_function = cloudpickle.dumps(cron_function)
72 | cron_callback = cloudpickle.dumps(cron_callback)
73 | cron_errback = cloudpickle.dumps(cron_errback)
74 | stdout_callback = cloudpickle.dumps(stdout_callback)
75 | stderr_callback = cloudpickle.dumps(stderr_callback)
76 | try:
77 | result = self.server.cron_set(key,cron_mode,xmlrpclib.Binary(cron_function),
78 | xmlrpclib.Binary(cron_callback),xmlrpclib.Binary(cron_errback),
79 | xmlrpclib.Binary(stdout_callback),xmlrpclib.Binary(stderr_callback))
80 | if isinstance(result,(list,tuple)):
81 | raise Exception(result[1])
82 | else:
83 | return result
84 | except Exception as e :
85 | raise Exception("[%s]:Exception:%s" % (self.ip, str(e)))
86 |
87 | def delete(self,key):
88 | try:
89 | result = self.server.cron_del(key)
90 | if isinstance(result,(list,tuple)):
91 | raise Exception(result[1])
92 | else:
93 | return result
94 | except Exception as e :
95 | raise Exception("[%s]:Exception:%s" % (self.ip, str(e)))
96 |
97 | def is_running(self,key):
98 | try:
99 | result = self.server.cron_is_running(key)
100 | if isinstance(result,(list,tuple)):
101 | raise Exception(result[1])
102 | else:
103 | return result
104 | except Exception as e :
105 | raise Exception("[%s]:Exception:%s" % (self.ip, str(e)))
106 |
107 | def run_now(self,key):
108 | try:
109 | result = self.server.cron_run_now(key)
110 | if isinstance(result,(list,tuple)):
111 | raise Exception(result[1])
112 | else:
113 | return result
114 | except Exception as e :
115 | raise Exception("[%s]:Exception:%s" % (self.ip, str(e)))
116 |
117 |
118 | class Deamon(object):
119 | def __init__(self,ip):
120 | import xmlrpclib
121 | self.ip = ip
122 | self.server = xmlrpclib.ServerProxy("http://%s:9913"%ip,allow_none=True)
123 |
124 | def set(self,key,function,callback,errback,stdout_callback,
125 | stderr_callback):
126 | import xmlrpclib,cloudpickle
127 | function=cloudpickle.dumps(function)
128 | callback=cloudpickle.dumps(callback)
129 | errback=cloudpickle.dumps(errback)
130 | stdout_callback=cloudpickle.dumps(stdout_callback)
131 | stderr_callback=cloudpickle.dumps(stderr_callback)
132 | try:
133 | result = self.server.deamon_set(key,xmlrpclib.Binary(function),
134 | xmlrpclib.Binary(callback),xmlrpclib.Binary(errback),
135 | xmlrpclib.Binary(stdout_callback),xmlrpclib.Binary(stderr_callback))
136 | if isinstance(result, (list, tuple)):
137 | raise Exception(result[1])
138 | else:
139 | return result
140 | except Exception as e:
141 | raise Exception("[%s]:Exception:%s" % (self.ip, str(e)))
142 |
143 |
144 | def delete(self,key):
145 | try:
146 | result = self.server.deamon_del(key)
147 | if isinstance(result, (list, tuple)):
148 | raise Exception(result[1])
149 | else:
150 | return result
151 | except Exception as e:
152 | raise Exception("[%s]:Exception:%s" % (self.ip, str(e)))
153 |
154 |
155 | def is_running(self,key):
156 | try:
157 | result = self.server.deamon_is_running(key)
158 | if isinstance(result, (list, tuple)):
159 | raise Exception(result[1])
160 | else:
161 | return result
162 | except Exception as e:
163 | raise Exception("[%s]:Exception:%s" % (self.ip, str(e)))
164 |
165 | def get(self,key):
166 | try:
167 | result = self.server.deamon_get(key)
168 | if isinstance(result, (list, tuple)):
169 | raise Exception(result[1])
170 | else:
171 | return result
172 | except Exception as e:
173 | raise Exception("[%s]:Exception:%s" % (self.ip, str(e)))
174 |
175 |
176 | class Task(object):
177 | def __init__(self, ip):
178 | import xmlrpclib
179 | self.ip = ip
180 | self.server = xmlrpclib.ServerProxy("http://%s:9913" % ip, allow_none=True)
181 |
182 | def set(self, key, function, callback, errback, stdout_callback,
183 | stderr_callback,timeout_callback=lambda *x:None,timeout=60):
184 | import xmlrpclib,cloudpickle
185 | function = cloudpickle.dumps(function)
186 | callback = cloudpickle.dumps(callback)
187 | errback = cloudpickle.dumps(errback)
188 | stdout_callback = cloudpickle.dumps(stdout_callback)
189 | stderr_callback = cloudpickle.dumps(stderr_callback)
190 | timeout_callback = cloudpickle.dumps(timeout_callback)
191 | try:
192 | result = self.server.task_set(key, xmlrpclib.Binary(function),
193 | xmlrpclib.Binary(callback), xmlrpclib.Binary(errback),
194 | xmlrpclib.Binary(stdout_callback), xmlrpclib.Binary(stderr_callback),
195 | xmlrpclib.Binary(timeout_callback),timeout)
196 | if isinstance(result,(list,tuple)):
197 | raise Exception(result[1])
198 | else:
199 | return result
200 | except Exception as e :
201 | raise Exception("[%s]:Exception:%s" % (self.ip, str(e)))
202 |
203 | def delete(self, key):
204 | try:
205 | result = self.server.task_del(key)
206 | if isinstance(result,(list,tuple)):
207 | raise Exception(result[1])
208 | else:
209 | return result
210 | except Exception as e :
211 | raise Exception("[%s]:Exception:%s" % (self.ip, str(e)))
212 |
213 | def is_running(self, key):
214 | try:
215 | result = self.server.task_is_running(key)
216 | if isinstance(result,(list,tuple)):
217 | raise Exception(result[1])
218 | else:
219 | return result
220 | except Exception as e :
221 | raise Exception("[%s]:Exception:%s" % (self.ip, str(e)))
222 |
223 | def get(self, key):
224 | try:
225 | result = self.server.task_get(key)
226 | if isinstance(result,(list,tuple)):
227 | raise Exception(result[1])
228 | else:
229 | return result
230 | except Exception as e :
231 | raise Exception("[%s]:Exception:%s" % (self.ip, str(e)))
232 |
233 | if __name__ == "__main__":
234 | import time
235 | task = Task("192.168.8.185")
236 | def test():
237 | import redis
238 | conn=redis.Redis("192.168.8.185",6379)
239 | conn.incr("testabc",10)
240 |
241 |
242 | _task = Task("192.168.8.185")
243 |
244 | def incr():
245 | import redis
246 | conn=redis.Redis("192.168.8.185",6379)
247 | conn.incr("zhou",10)
248 | import time
249 | time.sleep(2)
250 | _task = Task("192.168.8.185")
251 | _task.set("testabcd",test,lambda x:None,lambda x:None,lambda *x:None,lambda *x:None)
252 |
253 | # deamon.set("test",incr,lambda x:None,lambda x:None,lambda *x:None,lambda *x:None)
254 | # while 1:
255 | # time.sleep(0.1)
256 | # print deamon.is_running("test")
257 | task.set("test",incr,lambda x:None,lambda x:None,lambda *x:None,lambda *x:None)
258 | while 1:
259 | time.sleep(0.3)
260 | print task.is_running("test")
261 | # print cron.set("test","* * * * *",incr,lambda X:None,lambda x:None,lambda *x:None,lambda *x:None)
262 | # print cron.get("test")
263 | # import time
264 | # while 1:
265 | # time.sleep(1)
266 | # print cron.is_running("test")
267 | # print cron.is_running("test")
268 |
269 |
--------------------------------------------------------------------------------
/cap/cap/settings.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 | # Django settings for cap project.
3 | import os
4 | #import cap.urls
5 | #print [cap.urls]
6 | print __file__
7 |
8 |
9 | DEBUG = True
10 | TEMPLATE_DEBUG = DEBUG
11 | LOGIN_URL="/login/"
12 | LANGUAGE_CODE="zh-CN"
13 | if getattr(os,"config",None):
14 | config = os.config
15 | else:
16 | config = ["192.168.14.90",3306,"cap_test","spider","123456"]
17 |
18 | WORK_DIR = os.work_dir
19 | HOST = os.host
20 | DATABASES = {
21 | 'default': {
22 | 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
23 | 'NAME': config[2], # Or path to database file if using sqlite3.
24 | 'USER': config[3], # Not used with sqlite3.
25 | 'PASSWORD': config[4], # Not used with sqlite3.
26 | 'HOST': config[0], # Set to empty string for localhost. Not used with sqlite3.
27 | 'PORT': '%s'%config[1], # Set to empty string for default. Not used with sqlite3.
28 | },
29 | }
30 | print DATABASES
31 |
32 |
33 | # Hosts/domain names that are valid for this site; required if DEBUG is False
34 | # See https://docs.djangoproject.com/en/1.4/ref/settings/#allowed-hosts
35 | ALLOWED_HOSTS = ["*"]
36 |
37 | # Local time zone for this installation. Choices can be found here:
38 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
39 | # although not all choices may be available on all operating systems.
40 | # In a Windows environment this must be set to your system time zone.
41 | TIME_ZONE = 'Asia/Shanghai'
42 |
43 | # Language code for this installation. All choices can be found here:
44 | # http://www.i18nguy.com/unicode/language-identifiers.html
45 |
46 |
47 | SITE_ID = 1
48 |
49 | # If you set this to False, Django will make some optimizations so as not
50 | # to load the internationalization machinery.
51 | USE_I18N = True
52 |
53 | # If you set this to False, Django will not format dates, numbers and
54 | # calendars according to the current locale.
55 | USE_L10N = True
56 |
57 | # If you set this to False, Django will not use timezone-aware datetimes.
58 | USE_TZ = False
59 |
60 | # Absolute filesystem path to the directory that will hold user-uploaded files.
61 | # Example: "/home/media/media.lawrence.com/media/"
62 | MEDIA_ROOT = ''
63 |
64 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a
65 | # trailing slash.
66 | # Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
67 | MEDIA_URL = ''
68 |
69 | # Absolute path to the directory static files should be collected to.
70 | # Don't put anything in this directory yourself; store your static files
71 | # in apps' "static/" subdirectories and in STATICFILES_DIRS.
72 | # Example: "/home/media/media.lawrence.com/static/"
73 | STATIC_ROOT =''
74 |
75 | # URL prefix for static files.
76 | # Example: "http://media.lawrence.com/static/"
77 | STATIC_URL = '/abcdefgh/'
78 |
79 | # Additional locations of static files
80 | STATICFILES_DIRS = (
81 | # Put strings here, like "/home/html/static" or "C:/www/django/static".
82 | # Always use forward slashes, even on Windows.
83 | # Don't forget to use absolute paths, not relative paths.
84 | os.path.join(os.path.dirname(__file__), '..', 'static').replace('\\','/'),
85 | )
86 |
87 | # List of finder classes that know how to find static files in
88 | # various locations.
89 | STATICFILES_FINDERS = (
90 | 'django.contrib.staticfiles.finders.FileSystemFinder',
91 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
92 | # 'django.contrib.staticfiles.finders.DefaultStorageFinder',
93 | )
94 |
95 | # Make this unique, and don't share it with anybody.
96 | SECRET_KEY = '))ye65id1n#94^w68tpii41gq__&)gi&)&mlw55sgpi7frpm36'
97 |
98 | # List of callables that know how to import templates from various sources.
99 | TEMPLATE_LOADERS = (
100 | 'django.template.loaders.filesystem.Loader',
101 | 'django.template.loaders.app_directories.Loader',
102 | # 'django.template.loaders.eggs.Loader',
103 | )
104 |
105 | MIDDLEWARE_CLASSES = (
106 | 'django.middleware.common.CommonMiddleware',
107 | 'django.contrib.sessions.middleware.SessionMiddleware',
108 | 'django.middleware.csrf.CsrfViewMiddleware',
109 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
110 | 'django.contrib.messages.middleware.MessageMiddleware',
111 | # Uncomment the next line for simple clickjacking protection:
112 | # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
113 | )
114 |
115 | ROOT_URLCONF = 'cap.urls'
116 |
117 | # Python dotted path to the WSGI application used by Django's runserver.
118 | WSGI_APPLICATION = 'cap.wsgi.application'
119 |
120 | TEMPLATE_DIRS = (os.path.join(os.path.dirname(__file__), '..', 'templates').replace('\\','/'),)
121 |
122 | INSTALLED_APPS = (
123 | 'django.contrib.auth',
124 | 'django.contrib.contenttypes',
125 | 'django.contrib.sessions',
126 | 'django.contrib.sites',
127 | 'django.contrib.messages',
128 | 'django.contrib.staticfiles',
129 | # Uncomment the next line to enable the admin:
130 | 'django.contrib.admin',
131 | # Uncomment the next line to enable admin documentation:
132 | # 'django.contrib.admindocs',
133 | 'cap', #主项目
134 | "cap.api"
135 |
136 | )
137 |
138 |
139 | TEMPLATE_CONTEXT_PROCESSORS = (
140 | "django.contrib.auth.context_processors.auth",
141 | "django.core.context_processors.debug",
142 | "django.core.context_processors.i18n",
143 | "django.core.context_processors.media",
144 | "django.core.context_processors.static",
145 | "django.contrib.messages.context_processors.messages",
146 | "django.core.context_processors.request",
147 | )
148 | # A sample logging configuration. The only tangible logging
149 | # performed by this configuration is to send an email to
150 | # the site admins on every HTTP 500 error when DEBUG=False.
151 | # See http://docs.djangoproject.com/en/dev/topics/logging for
152 | # more details on how to customize your logging configuration.
153 | LOGGING = {
154 | 'version': 1,
155 | 'disable_existing_loggers': True,
156 | 'formatters':{
157 | 'simple': {
158 | 'format': '%(levelname)s %(message)s'
159 | },
160 | },
161 | 'filters': {
162 | 'require_debug_false': {
163 | '()': 'django.utils.log.RequireDebugFalse'
164 | }
165 | },
166 | 'handlers': {
167 | 'mail_admins': {
168 | 'level': 'ERROR',
169 | "filters":[],
170 | 'class': 'django.utils.log.AdminEmailHandler',
171 | 'include_html':True
172 | },
173 | 'console':{
174 | 'level':'DEBUG',
175 | 'class':'logging.StreamHandler',
176 | }
177 | },
178 | 'loggers': {
179 | 'django.request': {
180 | 'handlers': ['mail_admins'],
181 | 'level': 'ERROR',
182 | 'propagate': True,
183 | },
184 | 'django.db.backends': {
185 | 'handlers': ['console'],
186 | 'propagate': True,
187 | 'level':'DEBUG',
188 | }
189 | }
190 | }
191 | SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 999 # Age of cookie, in seconds (default: 2 weeks).
192 |
--------------------------------------------------------------------------------
/cap/cap/urls.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | from django.conf.urls import patterns, include, url
3 |
4 | # Uncomment the next two lines to enable the admin:
5 | from django.contrib import admin
6 | from django.contrib.auth.views import login, logout
7 | from django.http import HttpResponse, HttpResponseRedirect
8 | import core_api
9 | import api
10 | import views
11 | import os
12 |
13 | admin.autodiscover()
14 |
15 | urlpatterns = patterns('',
16 | # Examples:
17 | # url(r'^$', 'cap.views.home', name='home'),
18 | # url(r'^cap/', include('cap.foo.urls')),
19 |
20 | # Uncomment the admin/doc line below to enable admin documentation:
21 | (r"^robots\.txt$",
22 | lambda request: HttpResponse("User-agent: *\nDisallow: /", mimetype="text/plain")),
23 | # robots
24 | url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
25 | url(r"^login/$", login, {"template_name": "login.html"}),
26 | url(r"^logout/$", logout, {"next_page": "/"}),
27 | # url(r'^static/(?P