guest.py 27 KB

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