guest.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. import copy
  4. from flask import Blueprint
  5. from flask import request
  6. import json
  7. from uuid import uuid4
  8. import jimit as ji
  9. from api.base import Base
  10. from models import DiskState
  11. from models import OperateRule
  12. from models.initialize import app, dev_table
  13. from models import Database as db
  14. from models import Config
  15. from models import Disk
  16. from models import Rules
  17. from models import Utils
  18. from models import Guest
  19. from models import OSTemplate
  20. from models import GuestXML
  21. from models import status
  22. __author__ = 'James Iter'
  23. __date__ = '2017/3/22'
  24. __contact__ = 'james.iter.cn@gmail.com'
  25. __copyright__ = '(c) 2017 by James Iter.'
  26. blueprint = Blueprint(
  27. 'api_guest',
  28. __name__,
  29. url_prefix='/api/guest'
  30. )
  31. blueprints = Blueprint(
  32. 'api_guests',
  33. __name__,
  34. url_prefix='/api/guests'
  35. )
  36. guest_base = Base(the_class=Guest, the_blueprint=blueprint, the_blueprints=blueprints)
  37. @Utils.dumps2response
  38. def r_create():
  39. args_rules = [
  40. Rules.CPU.value,
  41. Rules.MEMORY.value,
  42. Rules.OS_TEMPLATE_ID.value,
  43. Rules.QUANTITY.value,
  44. Rules.REMARK.value,
  45. Rules.PASSWORD.value,
  46. Rules.LEASE_TERM.value
  47. ]
  48. try:
  49. ret = dict()
  50. ret['state'] = ji.Common.exchange_state(20000)
  51. ji.Check.previewing(args_rules, request.json)
  52. config = Config()
  53. config.id = 1
  54. config.get()
  55. os_template = OSTemplate()
  56. os_template.id = request.json.get('os_template_id')
  57. if not os_template.exist():
  58. ret['state'] = ji.Common.exchange_state(40450)
  59. ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], ': ', os_template.id.__str__()])
  60. return ret
  61. os_template.get()
  62. # 重置密码的 boot job id 固定为 1
  63. boot_jobs_id = [1, os_template.boot_job_id]
  64. boot_jobs, boot_jobs_count = OperateRule.get_by_filter(
  65. filter_str='boot_job_id:in:' +
  66. ','.join(['{0}'.format(boot_job_id) for boot_job_id in boot_jobs_id]).__str__())
  67. if db.r.scard(app.config['ip_available_set']) < 1:
  68. ret['state'] = ji.Common.exchange_state(50350)
  69. return ret
  70. available_hosts = Guest.get_available_hosts()
  71. if available_hosts.__len__() == 0:
  72. ret['state'] = ji.Common.exchange_state(50351)
  73. return ret
  74. quantity = request.json.get('quantity')
  75. while quantity:
  76. quantity -= 1
  77. guest = Guest()
  78. guest.uuid = uuid4().__str__()
  79. guest.cpu = request.json.get('cpu')
  80. # 虚拟机内存单位,模板生成方法中已置其为GiB
  81. guest.memory = request.json.get('memory')
  82. guest.os_template_id = request.json.get('os_template_id')
  83. guest.label = ji.Common.generate_random_code(length=8)
  84. guest.remark = request.json.get('remark', '')
  85. guest.password = request.json.get('password')
  86. if guest.password is None or guest.password.__len__() < 1:
  87. guest.password = ji.Common.generate_random_code(length=16)
  88. guest.ip = db.r.spop(app.config['ip_available_set'])
  89. db.r.sadd(app.config['ip_used_set'], guest.ip)
  90. guest.network = config.vm_network
  91. guest.manage_network = config.vm_manage_network
  92. guest.vnc_port = db.r.spop(app.config['vnc_port_available_set'])
  93. db.r.sadd(app.config['vnc_port_used_set'], guest.vnc_port)
  94. guest.vnc_password = ji.Common.generate_random_code(length=16)
  95. disk = Disk()
  96. disk.uuid = guest.uuid
  97. disk.remark = guest.label.__str__() + '_SystemImage'
  98. disk.format = 'qcow2'
  99. disk.sequence = 0
  100. disk.size = 0
  101. disk.path = config.storage_path + '/' + disk.uuid + '.' + disk.format
  102. disk.guest_uuid = ''
  103. disk.quota(config=config)
  104. disk.create()
  105. guest_xml = GuestXML(guest=guest, disk=disk, config=config, os_type=os_template.os_type)
  106. guest.xml = guest_xml.get_domain()
  107. # 在可用计算节点中平均分配任务
  108. chosen_host = available_hosts[quantity % available_hosts.__len__()]
  109. guest.on_host = chosen_host['hostname']
  110. guest.create()
  111. # 替换占位符为有效内容
  112. _boot_jobs = copy.deepcopy(boot_jobs)
  113. for k, v in enumerate(_boot_jobs):
  114. _boot_jobs[k]['content'] = v['content'].replace('{IP}', guest.ip).\
  115. replace('{HOSTNAME}', guest.label). \
  116. replace('{PASSWORD}', guest.password). \
  117. replace('{NETMASK}', config.netmask).\
  118. replace('{GATEWAY}', config.gateway).\
  119. replace('{DNS1}', config.dns1).\
  120. replace('{DNS2}', config.dns2)
  121. _boot_jobs[k]['command'] = v['command'].replace('{IP}', guest.ip). \
  122. replace('{HOSTNAME}', guest.label). \
  123. replace('{PASSWORD}', guest.password). \
  124. replace('{NETMASK}', config.netmask). \
  125. replace('{GATEWAY}', config.gateway). \
  126. replace('{DNS1}', config.dns1). \
  127. replace('{DNS2}', config.dns2)
  128. message = {
  129. '_object': 'guest',
  130. 'action': 'create',
  131. 'uuid': guest.uuid,
  132. 'storage_mode': config.storage_mode,
  133. 'dfs_volume': config.dfs_volume,
  134. 'hostname': guest.on_host,
  135. 'name': guest.label,
  136. 'template_path': os_template.path,
  137. 'os_type': os_template.os_type,
  138. 'disk': disk.__dict__,
  139. # disk 将被废弃,由 disks 代替,暂时保留它的目的,是为了保持与 JimV-N 的兼容性
  140. 'disks': [disk.__dict__],
  141. 'xml': guest_xml.get_domain(),
  142. 'boot_jobs': _boot_jobs,
  143. 'passback_parameters': {'boot_jobs_id': boot_jobs_id}
  144. }
  145. Guest.emit_instruction(message=json.dumps(message, ensure_ascii=False))
  146. return ret
  147. except ji.PreviewingError, e:
  148. return json.loads(e.message)
  149. @Utils.dumps2response
  150. def r_reboot(uuids):
  151. args_rules = [
  152. Rules.UUIDS.value
  153. ]
  154. try:
  155. ji.Check.previewing(args_rules, {'uuids': uuids})
  156. guest = Guest()
  157. for uuid in uuids.split(','):
  158. guest.uuid = uuid
  159. guest.get_by('uuid')
  160. for uuid in uuids.split(','):
  161. guest.uuid = uuid
  162. guest.get_by('uuid')
  163. message = {
  164. '_object': 'guest',
  165. 'action': 'reboot',
  166. 'uuid': uuid,
  167. 'hostname': guest.on_host
  168. }
  169. Guest.emit_instruction(message=json.dumps(message))
  170. ret = dict()
  171. ret['state'] = ji.Common.exchange_state(20000)
  172. return ret
  173. except ji.PreviewingError, e:
  174. return json.loads(e.message)
  175. @Utils.dumps2response
  176. def r_force_reboot(uuids):
  177. args_rules = [
  178. Rules.UUIDS.value
  179. ]
  180. try:
  181. ji.Check.previewing(args_rules, {'uuids': uuids})
  182. guest = Guest()
  183. for uuid in uuids.split(','):
  184. guest.uuid = uuid
  185. guest.get_by('uuid')
  186. for uuid in uuids.split(','):
  187. guest.uuid = uuid
  188. guest.get_by('uuid')
  189. disks = Disk.get_by_filter(filter_str=':'.join(['guest_uuid', 'eq', guest.uuid]))
  190. message = {
  191. '_object': 'guest',
  192. 'action': 'force_reboot',
  193. 'uuid': uuid,
  194. 'hostname': guest.on_host,
  195. 'disks': disks
  196. }
  197. Guest.emit_instruction(message=json.dumps(message))
  198. ret = dict()
  199. ret['state'] = ji.Common.exchange_state(20000)
  200. return ret
  201. except ji.PreviewingError, e:
  202. return json.loads(e.message)
  203. @Utils.dumps2response
  204. def r_shutdown(uuids):
  205. args_rules = [
  206. Rules.UUIDS.value
  207. ]
  208. try:
  209. ji.Check.previewing(args_rules, {'uuids': uuids})
  210. guest = Guest()
  211. for uuid in uuids.split(','):
  212. guest.uuid = uuid
  213. guest.get_by('uuid')
  214. for uuid in uuids.split(','):
  215. guest.uuid = uuid
  216. guest.get_by('uuid')
  217. message = {
  218. '_object': 'guest',
  219. 'action': 'shutdown',
  220. 'uuid': uuid,
  221. 'hostname': guest.on_host
  222. }
  223. Guest.emit_instruction(message=json.dumps(message))
  224. ret = dict()
  225. ret['state'] = ji.Common.exchange_state(20000)
  226. return ret
  227. except ji.PreviewingError, e:
  228. return json.loads(e.message)
  229. @Utils.dumps2response
  230. def r_force_shutdown(uuids):
  231. args_rules = [
  232. Rules.UUIDS.value
  233. ]
  234. try:
  235. ji.Check.previewing(args_rules, {'uuids': uuids})
  236. guest = Guest()
  237. for uuid in uuids.split(','):
  238. guest.uuid = uuid
  239. guest.get_by('uuid')
  240. for uuid in uuids.split(','):
  241. guest.uuid = uuid
  242. guest.get_by('uuid')
  243. message = {
  244. '_object': 'guest',
  245. 'action': 'force_shutdown',
  246. 'uuid': uuid,
  247. 'hostname': guest.on_host
  248. }
  249. Guest.emit_instruction(message=json.dumps(message))
  250. ret = dict()
  251. ret['state'] = ji.Common.exchange_state(20000)
  252. return ret
  253. except ji.PreviewingError, e:
  254. return json.loads(e.message)
  255. @Utils.dumps2response
  256. def r_boot(uuids):
  257. # TODO: 做好关系依赖判断,比如boot不可以对suspend的实例操作。
  258. args_rules = [
  259. Rules.UUIDS.value
  260. ]
  261. try:
  262. ji.Check.previewing(args_rules, {'uuids': uuids})
  263. guest = Guest()
  264. for uuid in uuids.split(','):
  265. guest.uuid = uuid
  266. guest.get_by('uuid')
  267. config = Config()
  268. config.id = 1
  269. config.get()
  270. for uuid in uuids.split(','):
  271. guest.uuid = uuid
  272. guest.get_by('uuid')
  273. _, boot_jobs_id = guest.get_boot_jobs()
  274. boot_jobs = list()
  275. if boot_jobs_id.__len__() > 0:
  276. boot_jobs, count = OperateRule.get_by_filter(filter_str='boot_job_id:in:' + ','.join(boot_jobs_id))
  277. # 替换占位符为有效内容
  278. for k, v in enumerate(boot_jobs):
  279. boot_jobs[k]['content'] = v['content'].replace('{IP}', guest.ip). \
  280. replace('{HOSTNAME}', guest.label). \
  281. replace('{PASSWORD}', guest.password). \
  282. replace('{NETMASK}', config.netmask). \
  283. replace('{GATEWAY}', config.gateway). \
  284. replace('{DNS1}', config.dns1). \
  285. replace('{DNS2}', config.dns2)
  286. boot_jobs[k]['command'] = v['command'].replace('{IP}', guest.ip). \
  287. replace('{HOSTNAME}', guest.label). \
  288. replace('{PASSWORD}', guest.password). \
  289. replace('{NETMASK}', config.netmask). \
  290. replace('{GATEWAY}', config.gateway). \
  291. replace('{DNS1}', config.dns1). \
  292. replace('{DNS2}', config.dns2)
  293. disks = Disk.get_by_filter(filter_str=':'.join(['guest_uuid', 'eq', guest.uuid]))
  294. message = {
  295. '_object': 'guest',
  296. 'action': 'boot',
  297. 'uuid': uuid,
  298. 'boot_jobs': boot_jobs,
  299. 'hostname': guest.on_host,
  300. 'passback_parameters': {'boot_jobs_id': boot_jobs_id},
  301. 'disks': disks
  302. }
  303. Guest.emit_instruction(message=json.dumps(message))
  304. ret = dict()
  305. ret['state'] = ji.Common.exchange_state(20000)
  306. return ret
  307. except ji.PreviewingError, e:
  308. return json.loads(e.message)
  309. @Utils.dumps2response
  310. def r_suspend(uuids):
  311. args_rules = [
  312. Rules.UUIDS.value
  313. ]
  314. try:
  315. ji.Check.previewing(args_rules, {'uuids': uuids})
  316. guest = Guest()
  317. for uuid in uuids.split(','):
  318. guest.uuid = uuid
  319. guest.get_by('uuid')
  320. for uuid in uuids.split(','):
  321. guest.uuid = uuid
  322. guest.get_by('uuid')
  323. message = {
  324. '_object': 'guest',
  325. 'action': 'suspend',
  326. 'uuid': uuid,
  327. 'hostname': guest.on_host
  328. }
  329. Guest.emit_instruction(message=json.dumps(message))
  330. ret = dict()
  331. ret['state'] = ji.Common.exchange_state(20000)
  332. return ret
  333. except ji.PreviewingError, e:
  334. return json.loads(e.message)
  335. @Utils.dumps2response
  336. def r_resume(uuids):
  337. args_rules = [
  338. Rules.UUIDS.value
  339. ]
  340. try:
  341. ji.Check.previewing(args_rules, {'uuids': uuids})
  342. guest = Guest()
  343. for uuid in uuids.split(','):
  344. guest.uuid = uuid
  345. guest.get_by('uuid')
  346. for uuid in uuids.split(','):
  347. guest.uuid = uuid
  348. guest.get_by('uuid')
  349. message = {
  350. '_object': 'guest',
  351. 'action': 'resume',
  352. 'uuid': uuid,
  353. 'hostname': guest.on_host
  354. }
  355. Guest.emit_instruction(message=json.dumps(message))
  356. ret = dict()
  357. ret['state'] = ji.Common.exchange_state(20000)
  358. return ret
  359. except ji.PreviewingError, e:
  360. return json.loads(e.message)
  361. @Utils.dumps2response
  362. def r_delete(uuids):
  363. args_rules = [
  364. Rules.UUIDS.value
  365. ]
  366. # TODO: 加入是否删除使用的数据磁盘开关,如果为True,则顺便删除使用的磁盘。否则解除该磁盘被使用的状态。
  367. try:
  368. ji.Check.previewing(args_rules, {'uuids': uuids})
  369. guest = Guest()
  370. # 检测所指定的 UUDIs 实例都存在
  371. for uuid in uuids.split(','):
  372. guest.uuid = uuid
  373. guest.get_by('uuid')
  374. config = Config()
  375. config.id = 1
  376. config.get()
  377. # 执行删除操作
  378. for uuid in uuids.split(','):
  379. guest.uuid = uuid
  380. guest.get_by('uuid')
  381. message = {
  382. '_object': 'guest',
  383. 'action': 'delete',
  384. 'uuid': uuid,
  385. 'storage_mode': config.storage_mode,
  386. 'dfs_volume': config.dfs_volume,
  387. 'hostname': guest.on_host
  388. }
  389. Guest.emit_instruction(message=json.dumps(message))
  390. # 删除创建失败的 Guest
  391. if guest.status == status.GuestState.dirty.value:
  392. disk = Disk()
  393. disk.uuid = guest.uuid
  394. disk.get_by('uuid')
  395. if disk.state == status.DiskState.pending.value:
  396. disk.delete()
  397. guest.delete()
  398. ret = dict()
  399. ret['state'] = ji.Common.exchange_state(20000)
  400. return ret
  401. except ji.PreviewingError, e:
  402. return json.loads(e.message)
  403. @Utils.dumps2response
  404. def r_attach_disk(uuid, disk_uuid):
  405. args_rules = [
  406. Rules.UUID.value,
  407. Rules.DISK_UUID.value
  408. ]
  409. try:
  410. ji.Check.previewing(args_rules, {'uuid': uuid, 'disk_uuid': disk_uuid})
  411. guest = Guest()
  412. guest.uuid = uuid
  413. guest.get_by('uuid')
  414. disk = Disk()
  415. disk.uuid = disk_uuid
  416. disk.get_by('uuid')
  417. config = Config()
  418. config.id = 1
  419. config.get()
  420. ret = dict()
  421. ret['state'] = ji.Common.exchange_state(20000)
  422. # 判断欲挂载的磁盘是否空闲
  423. if disk.guest_uuid.__len__() > 0 or disk.state != DiskState.idle.value:
  424. ret['state'] = ji.Common.exchange_state(41258)
  425. return ret
  426. # 判断 Guest 是否处于可用状态
  427. if guest.status in (status.GuestState.no_state.value, status.GuestState.dirty.value):
  428. ret['state'] = ji.Common.exchange_state(41259)
  429. return ret
  430. # 判断 Guest 与 磁盘是否在同一宿主机上
  431. if config.storage_mode in [status.StorageMode.local.value, status.StorageMode.shared_mount.value]:
  432. if guest.on_host != disk.on_host:
  433. ret['state'] = ji.Common.exchange_state(41260)
  434. return ret
  435. # 通过检测未被使用的序列,来确定当前磁盘在目标 Guest 身上的序列
  436. disk.guest_uuid = guest.uuid
  437. disks, count = disk.get_by_filter(filter_str='guest_uuid:in:' + guest.uuid)
  438. already_used_sequence = list()
  439. for _disk in disks:
  440. already_used_sequence.append(_disk['sequence'])
  441. for sequence in range(0, dev_table.__len__()):
  442. if sequence not in already_used_sequence:
  443. disk.sequence = sequence
  444. break
  445. disk.state = DiskState.mounting.value
  446. guest_xml = GuestXML(guest=guest, disk=disk, config=config)
  447. message = {
  448. '_object': 'guest',
  449. 'action': 'attach_disk',
  450. 'uuid': uuid,
  451. 'hostname': guest.on_host,
  452. 'xml': guest_xml.get_disk(),
  453. 'passback_parameters': {'disk_uuid': disk.uuid, 'sequence': disk.sequence},
  454. 'disks': [disk.__dict__]
  455. }
  456. Guest.emit_instruction(message=json.dumps(message))
  457. disk.update()
  458. return ret
  459. except ji.PreviewingError, e:
  460. return json.loads(e.message)
  461. @Utils.dumps2response
  462. def r_detach_disk(disk_uuid):
  463. args_rules = [
  464. Rules.DISK_UUID.value
  465. ]
  466. try:
  467. ji.Check.previewing(args_rules, {'disk_uuid': disk_uuid})
  468. disk = Disk()
  469. disk.uuid = disk_uuid
  470. disk.get_by('uuid')
  471. ret = dict()
  472. ret['state'] = ji.Common.exchange_state(20000)
  473. if disk.state != DiskState.mounted.value or disk.sequence == 0:
  474. # 表示未被任何实例使用,已被分离
  475. # 序列为 0 的表示实例系统盘,系统盘不可以被分离
  476. # TODO: 系统盘单独范围其它状态
  477. return ret
  478. guest = Guest()
  479. guest.uuid = disk.guest_uuid
  480. guest.get_by('uuid')
  481. # 判断 Guest 是否处于可用状态
  482. if guest.status in (status.GuestState.no_state.value, status.GuestState.dirty.value):
  483. ret['state'] = ji.Common.exchange_state(41259)
  484. return ret
  485. config = Config()
  486. config.id = 1
  487. config.get()
  488. guest_xml = GuestXML(guest=guest, disk=disk, config=config)
  489. message = {
  490. '_object': 'guest',
  491. 'action': 'detach_disk',
  492. 'uuid': disk.guest_uuid,
  493. 'hostname': guest.on_host,
  494. 'xml': guest_xml.get_disk(),
  495. 'passback_parameters': {'disk_uuid': disk.uuid}
  496. }
  497. Guest.emit_instruction(message=json.dumps(message))
  498. disk.state = DiskState.unloading.value
  499. disk.update()
  500. return ret
  501. except ji.PreviewingError, e:
  502. return json.loads(e.message)
  503. @Utils.dumps2response
  504. def r_migrate(uuids, destination_host):
  505. args_rules = [
  506. Rules.UUIDS.value,
  507. Rules.DESTINATION_HOST.value
  508. ]
  509. try:
  510. ji.Check.previewing(args_rules, {'uuids': uuids, 'destination_host': destination_host})
  511. guest = Guest()
  512. for uuid in uuids.split(','):
  513. guest.uuid = uuid
  514. guest.get_by('uuid')
  515. config = Config()
  516. config.id = 1
  517. config.get()
  518. for uuid in uuids.split(','):
  519. guest.uuid = uuid
  520. guest.get_by('uuid')
  521. message = {
  522. '_object': 'guest',
  523. 'action': 'migrate',
  524. 'uuid': uuid,
  525. 'hostname': guest.on_host,
  526. 'storage_mode': config.storage_mode,
  527. 'duri': 'qemu+ssh://' + destination_host + '/system'
  528. }
  529. Guest.emit_instruction(message=json.dumps(message))
  530. ret = dict()
  531. ret['state'] = ji.Common.exchange_state(20000)
  532. return ret
  533. except ji.PreviewingError, e:
  534. return json.loads(e.message)
  535. @Utils.dumps2response
  536. def r_get(uuids):
  537. return guest_base.get(ids=uuids, ids_rule=Rules.UUIDS.value, by_field='uuid')
  538. @Utils.dumps2response
  539. def r_get_by_filter():
  540. return guest_base.get_by_filter()
  541. @Utils.dumps2response
  542. def r_content_search():
  543. return guest_base.content_search()
  544. @Utils.dumps2response
  545. def r_distribute_count():
  546. from models import Guest
  547. rows, count = Guest.get_all()
  548. ret = dict()
  549. ret['state'] = ji.Common.exchange_state(20000)
  550. ret['data'] = {
  551. 'os_template_id': dict(),
  552. 'status': dict(),
  553. 'on_host': dict(),
  554. 'cpu_memory': dict(),
  555. 'cpu': 0,
  556. 'memory': 0,
  557. 'guests': rows.__len__()
  558. }
  559. for guest in rows:
  560. if guest['os_template_id'] not in ret['data']['os_template_id']:
  561. ret['data']['os_template_id'][guest['os_template_id']] = 0
  562. if guest['status'] not in ret['data']['status']:
  563. ret['data']['status'][guest['status']] = 0
  564. if guest['on_host'] not in ret['data']['on_host']:
  565. ret['data']['on_host'][guest['on_host']] = 0
  566. cpu_memory = '_'.join([str(guest['cpu']), str(guest['memory'])])
  567. if cpu_memory not in ret['data']['cpu_memory']:
  568. ret['data']['cpu_memory'][cpu_memory] = 0
  569. ret['data']['os_template_id'][guest['os_template_id']] += 1
  570. ret['data']['status'][guest['status']] += 1
  571. ret['data']['on_host'][guest['on_host']] += 1
  572. ret['data']['cpu_memory'][cpu_memory] += 1
  573. ret['data']['cpu'] += guest['cpu']
  574. ret['data']['memory'] += guest['memory']
  575. return ret
  576. @Utils.dumps2response
  577. def r_update(uuid):
  578. args_rules = [
  579. Rules.UUID.value
  580. ]
  581. if 'remark' in request.json:
  582. args_rules.append(
  583. Rules.REMARK.value,
  584. )
  585. if args_rules.__len__() < 2:
  586. ret = dict()
  587. ret['state'] = ji.Common.exchange_state(20000)
  588. return ret
  589. request.json['uuid'] = uuid
  590. try:
  591. ji.Check.previewing(args_rules, request.json)
  592. guest = Guest()
  593. guest.uuid = uuid
  594. guest.get_by('uuid')
  595. guest.remark = request.json.get('remark', guest.label)
  596. guest.update()
  597. guest.get()
  598. ret = dict()
  599. ret['state'] = ji.Common.exchange_state(20000)
  600. ret['data'] = guest.__dict__
  601. return ret
  602. except ji.PreviewingError, e:
  603. return json.loads(e.message)
  604. @Utils.dumps2response
  605. def r_add_boot_jobs(uuids, boot_jobs_id):
  606. args_rules = [
  607. Rules.UUIDS.value,
  608. Rules.BOOT_JOBS_ID.value
  609. ]
  610. try:
  611. ji.Check.previewing(args_rules, {'uuids': uuids, 'boot_jobs_id': boot_jobs_id})
  612. guest = Guest()
  613. for uuid in uuids.split(','):
  614. guest.uuid = uuid
  615. guest.get_by('uuid')
  616. for uuid in uuids.split(','):
  617. guest.uuid = uuid
  618. guest.add_boot_jobs(boot_jobs_id=boot_jobs_id.split(','))
  619. ret = dict()
  620. ret['state'] = ji.Common.exchange_state(20000)
  621. if uuids.split(',').__len__() > 1:
  622. ret['data'] = dict()
  623. for uuid in uuids.split(','):
  624. guest.uuid = uuid
  625. boot_jobs = dict()
  626. boot_jobs['ttl'], boot_jobs['boot_jobs'] = guest.get_boot_jobs()
  627. ret['data'][uuid] = boot_jobs
  628. else:
  629. guest.uuid = uuids
  630. ret['data'] = dict()
  631. ret['data']['ttl'], ret['data']['boot_jobs'] = guest.get_boot_jobs()
  632. return ret
  633. except ji.PreviewingError, e:
  634. return json.loads(e.message)
  635. @Utils.dumps2response
  636. def r_get_boot_jobs(uuids):
  637. args_rules = [
  638. Rules.UUIDS.value
  639. ]
  640. try:
  641. ji.Check.previewing(args_rules, {'uuids': uuids})
  642. guest = Guest()
  643. for uuid in uuids.split(','):
  644. guest.uuid = uuid
  645. guest.get_by('uuid')
  646. ret = dict()
  647. ret['state'] = ji.Common.exchange_state(20000)
  648. if uuids.split(',').__len__() > 1:
  649. ret['data'] = dict()
  650. for uuid in uuids.split(','):
  651. guest.uuid = uuid
  652. boot_jobs = dict()
  653. boot_jobs['ttl'], boot_jobs['boot_jobs'] = guest.get_boot_jobs()
  654. ret['data'][uuid] = boot_jobs
  655. else:
  656. guest.uuid = uuids
  657. ret['data'] = dict()
  658. ret['data']['ttl'], ret['data']['boot_jobs'] = guest.get_boot_jobs()
  659. return ret
  660. except ji.PreviewingError, e:
  661. return json.loads(e.message)
  662. @Utils.dumps2response
  663. def r_delete_boot_jobs(uuids, boot_jobs_id):
  664. args_rules = [
  665. Rules.UUIDS.value,
  666. Rules.BOOT_JOBS_ID.value
  667. ]
  668. try:
  669. ji.Check.previewing(args_rules, {'uuids': uuids, 'boot_jobs_id': boot_jobs_id})
  670. guest = Guest()
  671. # 检测所指定的 UUDIs 实例都存在
  672. for uuid in uuids.split(','):
  673. guest.uuid = uuid
  674. guest.get_by('uuid')
  675. for uuid in uuids.split(','):
  676. guest.uuid = uuid
  677. guest.delete_boot_jobs(boot_jobs_id=boot_jobs_id.split(','))
  678. ret = dict()
  679. ret['state'] = ji.Common.exchange_state(20000)
  680. return ret
  681. except ji.PreviewingError, e:
  682. return json.loads(e.message)
  683. @Utils.dumps2response
  684. def r_get_uuids_of_all_had_boot_job():
  685. guest = Guest()
  686. try:
  687. ret = dict()
  688. ret['state'] = ji.Common.exchange_state(20000)
  689. ret['data'] = guest.get_uuids_of_all_had_boot_job()
  690. return ret
  691. except ji.PreviewingError, e:
  692. return json.loads(e.message)
  693. @Utils.dumps2response
  694. def r_reset_password(uuids, password):
  695. args_rules = [
  696. Rules.UUIDS.value,
  697. Rules.PASSWORD.value
  698. ]
  699. try:
  700. ji.Check.previewing(args_rules, {'uuids': uuids, 'password': password})
  701. guest = Guest()
  702. # 检测所指定的 UUDIs 实例都存在
  703. for uuid in uuids.split(','):
  704. guest.uuid = uuid
  705. guest.get_by('uuid')
  706. # 重置密码的 boot job id 固定为 1
  707. for uuid in uuids.split(','):
  708. guest.uuid = uuid
  709. guest.get_by('uuid')
  710. guest.password = password
  711. guest.update()
  712. guest.add_boot_jobs(boot_jobs_id=['1'])
  713. ret = dict()
  714. ret['state'] = ji.Common.exchange_state(20000)
  715. return ret
  716. except ji.PreviewingError, e:
  717. return json.loads(e.message)