guest_performance.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. from flask import Blueprint
  4. import json
  5. import jimit as ji
  6. from jimvc.api.base import Base
  7. from jimvc.models import GuestCPUMemory, GuestTraffic, GuestDiskIO, Utils, Rules
  8. __author__ = 'James Iter'
  9. __date__ = '2017/7/2'
  10. __contact__ = 'james.iter.cn@gmail.com'
  11. __copyright__ = '(c) 2017 by James Iter.'
  12. blueprint = Blueprint(
  13. 'api_guest_performance',
  14. __name__,
  15. url_prefix='/api/guest_performance'
  16. )
  17. blueprints = Blueprint(
  18. 'api_guest_performances',
  19. __name__,
  20. url_prefix='/api/guest_performances'
  21. )
  22. guest_cpu_memory = Base(the_class=GuestCPUMemory, the_blueprint=blueprint, the_blueprints=blueprints)
  23. guest_traffic = Base(the_class=GuestTraffic, the_blueprint=blueprint, the_blueprints=blueprints)
  24. guest_disk_io = Base(the_class=GuestDiskIO, the_blueprint=blueprint, the_blueprints=blueprints)
  25. @Utils.dumps2response
  26. def r_cpu_memory_get_by_filter():
  27. return guest_cpu_memory.get_by_filter()
  28. @Utils.dumps2response
  29. def r_traffic_get_by_filter():
  30. return guest_traffic.get_by_filter()
  31. @Utils.dumps2response
  32. def r_disk_io_get_by_filter():
  33. return guest_disk_io.get_by_filter()
  34. def get_performance_data(uuid, uuid_field, the_class=None, granularity='hour'):
  35. args_rules = [
  36. Rules.UUID.value,
  37. ]
  38. try:
  39. ji.Check.previewing(args_rules, {'uuid': uuid})
  40. uuids_str = ':'.join([uuid_field, 'in', uuid])
  41. ret = dict()
  42. ret['state'] = ji.Common.exchange_state(20000)
  43. ret['data'] = list()
  44. max_limit = 10080
  45. ts = ji.Common.ts()
  46. _boundary = ts - 60 * 60
  47. if granularity == 'hour':
  48. _boundary = ts - 60 * 60
  49. elif granularity == 'six_hours':
  50. _boundary = ts - 60 * 60 * 6
  51. elif granularity == 'day':
  52. _boundary = ts - 60 * 60 * 24
  53. elif granularity == 'seven_days':
  54. _boundary = ts - 60 * 60 * 24 * 7
  55. else:
  56. pass
  57. filter_str = ';'.join([uuids_str, 'timestamp:gt:' + _boundary.__str__()])
  58. _rows, _rows_count = the_class.get_by_filter(
  59. offset=0, limit=max_limit, order_by='id', order='asc', filter_str=filter_str)
  60. def smooth_data(boundary=0, interval=60, now_ts=ji.Common.ts(), rows=None):
  61. needs = list()
  62. data = list()
  63. for t in range(boundary + interval, now_ts, interval):
  64. needs.append(t - t % interval)
  65. for row in rows:
  66. if row['timestamp'] % interval != 0:
  67. continue
  68. if needs.__len__() > 0:
  69. t = needs.pop(0)
  70. else:
  71. t = now_ts
  72. while t < row['timestamp']:
  73. data.append({
  74. 'timestamp': t,
  75. 'cpu_load': None,
  76. 'memory_available': None,
  77. 'memory_unused': None,
  78. 'rx_packets': None,
  79. 'rx_bytes': None,
  80. 'tx_packets': None,
  81. 'tx_bytes': None,
  82. 'rd_req': None,
  83. 'rd_bytes': None,
  84. 'wr_req': None,
  85. 'wr_bytes': None
  86. })
  87. if needs.__len__() > 0:
  88. t = needs.pop(0)
  89. else:
  90. t = now_ts
  91. data.append(row)
  92. return data
  93. if granularity == 'day':
  94. ret['data'] = smooth_data(boundary=_boundary, interval=600, now_ts=ts, rows=_rows)
  95. elif granularity == 'seven_days':
  96. ret['data'] = smooth_data(boundary=_boundary, interval=600, now_ts=ts, rows=_rows)
  97. else:
  98. ret['data'] = smooth_data(boundary=_boundary, interval=60, now_ts=ts, rows=_rows)
  99. return ret
  100. except ji.PreviewingError, e:
  101. return json.loads(e.message)
  102. @Utils.dumps2response
  103. def r_cpu_memory_last_hour(uuid):
  104. return get_performance_data(uuid=uuid, uuid_field='guest_uuid', the_class=GuestCPUMemory, granularity='hour')
  105. @Utils.dumps2response
  106. def r_cpu_memory_last_six_hours(uuid):
  107. return get_performance_data(uuid=uuid, uuid_field='guest_uuid', the_class=GuestCPUMemory, granularity='six_hours')
  108. @Utils.dumps2response
  109. def r_cpu_memory_last_day(uuid):
  110. return get_performance_data(uuid=uuid, uuid_field='guest_uuid', the_class=GuestCPUMemory, granularity='day')
  111. @Utils.dumps2response
  112. def r_cpu_memory_last_seven_days(uuid):
  113. return get_performance_data(uuid=uuid, uuid_field='guest_uuid', the_class=GuestCPUMemory, granularity='seven_days')
  114. @Utils.dumps2response
  115. def r_traffic_last_hour(uuid):
  116. return get_performance_data(uuid=uuid, uuid_field='guest_uuid', the_class=GuestTraffic, granularity='hour')
  117. @Utils.dumps2response
  118. def r_traffic_last_six_hours(uuid):
  119. return get_performance_data(uuid=uuid, uuid_field='guest_uuid', the_class=GuestTraffic, granularity='six_hours')
  120. @Utils.dumps2response
  121. def r_traffic_last_day(uuid):
  122. return get_performance_data(uuid=uuid, uuid_field='guest_uuid', the_class=GuestTraffic, granularity='day')
  123. @Utils.dumps2response
  124. def r_traffic_last_seven_days(uuid):
  125. return get_performance_data(uuid=uuid, uuid_field='guest_uuid', the_class=GuestTraffic, granularity='seven_days')
  126. @Utils.dumps2response
  127. def r_disk_io_last_hour(uuid):
  128. return get_performance_data(uuid=uuid, uuid_field='disk_uuid', the_class=GuestDiskIO, granularity='hour')
  129. @Utils.dumps2response
  130. def r_disk_io_last_six_hours(uuid):
  131. return get_performance_data(uuid=uuid, uuid_field='disk_uuid', the_class=GuestDiskIO, granularity='six_hours')
  132. @Utils.dumps2response
  133. def r_disk_io_last_day(uuid):
  134. return get_performance_data(uuid=uuid, uuid_field='disk_uuid', the_class=GuestDiskIO, granularity='day')
  135. @Utils.dumps2response
  136. def r_disk_io_last_seven_days(uuid):
  137. return get_performance_data(uuid=uuid, uuid_field='disk_uuid', the_class=GuestDiskIO, granularity='seven_days')
  138. @Utils.dumps2response
  139. def r_current_top_10():
  140. # JimV 设计的 Guests 容量为 4000 个
  141. volume = 4000
  142. limit = volume
  143. length = 10
  144. end_ts = ji.Common.ts() - 60
  145. start_ts = end_ts - 60
  146. # 避免落在时间边界上,导致过滤条件的范围落空
  147. if start_ts % 60 == 0:
  148. start_ts -= 1
  149. ret = dict()
  150. ret['state'] = ji.Common.exchange_state(20000)
  151. ret['data'] = {
  152. 'cpu_load': list(),
  153. 'memory_rate': list(),
  154. 'rw_bytes': list(),
  155. 'rw_req': list(),
  156. 'rt_bytes': list(),
  157. 'rt_packets': list()
  158. }
  159. filter_str = ';'.join([':'.join(['timestamp', 'gt', start_ts.__str__()]),
  160. ':'.join(['timestamp', 'lt', end_ts.__str__()])])
  161. rows, _ = GuestCPUMemory.get_by_filter(limit=limit, filter_str=filter_str)
  162. rows.sort(key=lambda k: k['cpu_load'], reverse=True)
  163. effective_range = length
  164. if rows.__len__() < length:
  165. effective_range = rows.__len__()
  166. for i in range(effective_range):
  167. if rows[i]['cpu_load'] == 0:
  168. break
  169. ret['data']['cpu_load'].append(rows[i])
  170. rows.sort(key=lambda k: k['memory_rate'], reverse=True)
  171. for i in range(effective_range):
  172. if rows[i]['memory_rate'] == 0:
  173. break
  174. ret['data']['memory_rate'].append(rows[i])
  175. rows, _ = GuestDiskIO.get_by_filter(limit=limit, filter_str=filter_str)
  176. for i in range(rows.__len__()):
  177. rows[i]['rw_bytes'] = rows[i]['rd_bytes'] + rows[i]['wr_bytes']
  178. rows[i]['rw_req'] = rows[i]['rd_req'] + rows[i]['wr_req']
  179. effective_range = length
  180. if rows.__len__() < length:
  181. effective_range = rows.__len__()
  182. rows.sort(key=lambda k: k['rw_bytes'], reverse=True)
  183. for i in range(effective_range):
  184. if rows[i]['rw_req'] == 0:
  185. break
  186. ret['data']['rw_bytes'].append(rows[i])
  187. rows.sort(key=lambda k: k['rw_req'], reverse=True)
  188. for i in range(effective_range):
  189. if rows[i]['rw_req'] == 0:
  190. break
  191. ret['data']['rw_req'].append(rows[i])
  192. rows, _ = GuestTraffic.get_by_filter(limit=limit, filter_str=filter_str)
  193. for i in range(rows.__len__()):
  194. rows[i]['rt_bytes'] = rows[i]['rx_bytes'] + rows[i]['tx_bytes']
  195. rows[i]['rt_packets'] = rows[i]['rx_packets'] + rows[i]['tx_packets']
  196. effective_range = length
  197. if rows.__len__() < length:
  198. effective_range = rows.__len__()
  199. rows.sort(key=lambda k: k['rt_bytes'], reverse=True)
  200. for i in range(effective_range):
  201. if rows[i]['rt_packets'] == 0:
  202. break
  203. ret['data']['rt_bytes'].append(rows[i])
  204. rows.sort(key=lambda k: k['rt_packets'], reverse=True)
  205. for i in range(effective_range):
  206. if rows[i]['rt_packets'] == 0:
  207. break
  208. ret['data']['rt_packets'].append(rows[i])
  209. return ret
  210. @Utils.dumps2response
  211. def r_last_the_range_minutes_top_10(_range):
  212. volume = 4000
  213. limit = volume * _range
  214. length = 10
  215. end_ts = ji.Common.ts() - 60
  216. start_ts = end_ts - 60 * _range
  217. # 避免落在时间边界上,导致过滤条件的范围落空
  218. if start_ts % 60 == 0:
  219. start_ts -= 1
  220. ret = dict()
  221. ret['state'] = ji.Common.exchange_state(20000)
  222. ret['data'] = {
  223. 'cpu_load': list(),
  224. 'rw_bytes': list(),
  225. 'rw_req': list(),
  226. 'rt_bytes': list(),
  227. 'rt_packets': list()
  228. }
  229. filter_str = ';'.join([':'.join(['timestamp', 'gt', start_ts.__str__()]),
  230. ':'.join(['timestamp', 'lt', end_ts.__str__()])])
  231. # cpu 负载
  232. guests_uuid_mapping = dict()
  233. rows, _ = GuestCPUMemory.get_by_filter(limit=limit, filter_str=filter_str)
  234. for row in rows:
  235. if row['guest_uuid'] not in guests_uuid_mapping:
  236. guests_uuid_mapping[row['guest_uuid']] = {'cpu_load': 0, 'count': 0}
  237. guests_uuid_mapping[row['guest_uuid']]['cpu_load'] += row['cpu_load']
  238. guests_uuid_mapping[row['guest_uuid']]['count'] += 1.0
  239. rows = list()
  240. for k, v in guests_uuid_mapping.items():
  241. # 忽略除数为 0 的情况
  242. if v['cpu_load'] == 0:
  243. continue
  244. rows.append({'guest_uuid': k, 'cpu_load': v['cpu_load'] / v['count']})
  245. effective_range = length
  246. if rows.__len__() < length:
  247. effective_range = rows.__len__()
  248. rows.sort(key=lambda _k: _k['cpu_load'], reverse=True)
  249. ret['data']['cpu_load'] = rows[0:effective_range]
  250. # 磁盘使用统计
  251. guests_uuid_mapping.clear()
  252. rows, _ = GuestDiskIO.get_by_filter(limit=limit, filter_str=filter_str)
  253. for row in rows:
  254. if row['disk_uuid'] not in guests_uuid_mapping:
  255. guests_uuid_mapping[row['disk_uuid']] = {'rw_bytes': 0, 'rw_req': 0}
  256. guests_uuid_mapping[row['disk_uuid']]['rw_bytes'] += row['rd_bytes'] + row['wr_bytes']
  257. guests_uuid_mapping[row['disk_uuid']]['rw_req'] += row['rd_req'] + row['wr_req']
  258. rows = list()
  259. for k, v in guests_uuid_mapping.items():
  260. # 过滤掉无操作的数据
  261. if v['rw_req'] == 0:
  262. continue
  263. rows.append({'disk_uuid': k, 'rw_bytes': v['rw_bytes'] * 60 * _range, 'rw_req': v['rw_req'] * 60 * _range})
  264. effective_range = length
  265. if rows.__len__() < length:
  266. effective_range = rows.__len__()
  267. rows.sort(key=lambda _k: _k['rw_bytes'], reverse=True)
  268. ret['data']['rw_bytes'] = rows[0:effective_range]
  269. rows.sort(key=lambda _k: _k['rw_req'], reverse=True)
  270. ret['data']['rw_req'] = rows[0:effective_range]
  271. # 网络流量
  272. guests_uuid_mapping.clear()
  273. rows, _ = GuestTraffic.get_by_filter(limit=limit, filter_str=filter_str)
  274. for row in rows:
  275. if row['guest_uuid'] not in guests_uuid_mapping:
  276. guests_uuid_mapping[row['guest_uuid']] = {'rt_bytes': 0, 'rt_packets': 0}
  277. guests_uuid_mapping[row['guest_uuid']]['rt_bytes'] += row['rx_bytes'] + row['tx_bytes']
  278. guests_uuid_mapping[row['guest_uuid']]['rt_packets'] += row['rx_packets'] + row['tx_packets']
  279. rows = list()
  280. for k, v in guests_uuid_mapping.items():
  281. # 过滤掉无流量的数据
  282. if v['rt_packets'] == 0:
  283. continue
  284. rows.append({'guest_uuid': k, 'rt_bytes': v['rt_bytes'] * 60 * _range,
  285. 'rt_packets': v['rt_packets'] * 60 * _range})
  286. effective_range = length
  287. if rows.__len__() < length:
  288. effective_range = rows.__len__()
  289. rows.sort(key=lambda _k: _k['rt_bytes'], reverse=True)
  290. ret['data']['rt_bytes'] = rows[0:effective_range]
  291. rows.sort(key=lambda _k: _k['rt_packets'], reverse=True)
  292. ret['data']['rt_packets'] = rows[0:effective_range]
  293. return ret
  294. @Utils.dumps2response
  295. def r_last_10_minutes_top_10():
  296. return r_last_the_range_minutes_top_10(_range=10)
  297. @Utils.dumps2response
  298. def r_last_hour_top_10():
  299. return r_last_the_range_minutes_top_10(_range=60)
  300. @Utils.dumps2response
  301. def r_last_six_hours_top_10():
  302. return r_last_the_range_minutes_top_10(_range=60 * 6)
  303. @Utils.dumps2response
  304. def r_last_day_top_10():
  305. return r_last_the_range_minutes_top_10(_range=60 * 24)