guest.py 25 KB

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