guest.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
  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. # 负载最小的宿主机
  121. lightest_host = None
  122. for k, v in db.r.hgetall(app.config['hosts_info']).items():
  123. v = json.loads(v)
  124. if lightest_host is None:
  125. lightest_host = v
  126. if float(lightest_host['system_load'][0]) / lightest_host['cpu'] > \
  127. float(v['system_load'][0]) / v['cpu']:
  128. lightest_host = v
  129. create_vm_msg = {
  130. 'action': 'create',
  131. 'uuid': guest.uuid,
  132. 'hostname': lightest_host['hostname'],
  133. 'name': guest.label,
  134. 'glusterfs_volume': config.glusterfs_volume,
  135. 'template_path': os_template.path,
  136. 'disk': disk.__dict__,
  137. 'xml': guest_xml.get_domain(),
  138. 'boot_jobs': _boot_jobs,
  139. 'passback_parameters': {'boot_jobs_id': boot_jobs_id}
  140. }
  141. Guest.emit_instruction(message=json.dumps(create_vm_msg, ensure_ascii=False))
  142. return ret
  143. except ji.PreviewingError, e:
  144. return json.loads(e.message)
  145. @Utils.dumps2response
  146. def r_reboot(uuids):
  147. args_rules = [
  148. Rules.UUIDS.value
  149. ]
  150. try:
  151. ji.Check.previewing(args_rules, {'uuids': uuids})
  152. guest = Guest()
  153. for uuid in uuids.split(','):
  154. guest.uuid = uuid
  155. guest.get_by('uuid')
  156. for uuid in uuids.split(','):
  157. message = {'action': 'reboot', 'uuid': uuid}
  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. message = {'action': 'force_reboot', 'uuid': uuid}
  177. Guest.emit_instruction(message=json.dumps(message))
  178. ret = dict()
  179. ret['state'] = ji.Common.exchange_state(20000)
  180. return ret
  181. except ji.PreviewingError, e:
  182. return json.loads(e.message)
  183. @Utils.dumps2response
  184. def r_shutdown(uuids):
  185. args_rules = [
  186. Rules.UUIDS.value
  187. ]
  188. try:
  189. ji.Check.previewing(args_rules, {'uuids': uuids})
  190. guest = Guest()
  191. for uuid in uuids.split(','):
  192. guest.uuid = uuid
  193. guest.get_by('uuid')
  194. for uuid in uuids.split(','):
  195. message = {'action': 'shutdown', 'uuid': uuid}
  196. Guest.emit_instruction(message=json.dumps(message))
  197. ret = dict()
  198. ret['state'] = ji.Common.exchange_state(20000)
  199. return ret
  200. except ji.PreviewingError, e:
  201. return json.loads(e.message)
  202. @Utils.dumps2response
  203. def r_force_shutdown(uuids):
  204. args_rules = [
  205. Rules.UUIDS.value
  206. ]
  207. try:
  208. ji.Check.previewing(args_rules, {'uuids': uuids})
  209. guest = Guest()
  210. for uuid in uuids.split(','):
  211. guest.uuid = uuid
  212. guest.get_by('uuid')
  213. for uuid in uuids.split(','):
  214. message = {'action': 'force_shutdown', 'uuid': uuid}
  215. Guest.emit_instruction(message=json.dumps(message))
  216. ret = dict()
  217. ret['state'] = ji.Common.exchange_state(20000)
  218. return ret
  219. except ji.PreviewingError, e:
  220. return json.loads(e.message)
  221. @Utils.dumps2response
  222. def r_boot(uuids):
  223. # TODO: 做好关系依赖判断,比如boot不可以对suspend的实例操作。
  224. args_rules = [
  225. Rules.UUIDS.value
  226. ]
  227. try:
  228. ji.Check.previewing(args_rules, {'uuids': uuids})
  229. guest = Guest()
  230. for uuid in uuids.split(','):
  231. guest.uuid = uuid
  232. guest.get_by('uuid')
  233. config = Config()
  234. config.id = 1
  235. config.get()
  236. for uuid in uuids.split(','):
  237. _, boot_jobs_id = guest.get_boot_jobs()
  238. boot_jobs = list()
  239. if boot_jobs_id.__len__() > 0:
  240. boot_jobs, count = OperateRule.get_by_filter(filter_str='boot_job_id:in:' + ','.join(boot_jobs_id))
  241. # 替换占位符为有效内容
  242. for k, v in enumerate(boot_jobs):
  243. boot_jobs[k]['content'] = v['content'].replace('{IP}', guest.ip). \
  244. replace('{HOSTNAME}', guest.label). \
  245. replace('{PASSWORD}', guest.password). \
  246. replace('{NETMASK}', config.netmask). \
  247. replace('{GATEWAY}', config.gateway). \
  248. replace('{DNS1}', config.dns1). \
  249. replace('{DNS2}', config.dns2)
  250. boot_jobs[k]['command'] = v['command'].replace('{IP}', guest.ip). \
  251. replace('{HOSTNAME}', guest.label). \
  252. replace('{PASSWORD}', guest.password). \
  253. replace('{NETMASK}', config.netmask). \
  254. replace('{GATEWAY}', config.gateway). \
  255. replace('{DNS1}', config.dns1). \
  256. replace('{DNS2}', config.dns2)
  257. message = {'action': 'boot', 'uuid': uuid, 'boot_jobs': boot_jobs,
  258. 'passback_parameters': {'boot_jobs_id': boot_jobs_id}}
  259. Guest.emit_instruction(message=json.dumps(message))
  260. ret = dict()
  261. ret['state'] = ji.Common.exchange_state(20000)
  262. return ret
  263. except ji.PreviewingError, e:
  264. return json.loads(e.message)
  265. @Utils.dumps2response
  266. def r_suspend(uuids):
  267. args_rules = [
  268. Rules.UUIDS.value
  269. ]
  270. try:
  271. ji.Check.previewing(args_rules, {'uuids': uuids})
  272. guest = Guest()
  273. for uuid in uuids.split(','):
  274. guest.uuid = uuid
  275. guest.get_by('uuid')
  276. for uuid in uuids.split(','):
  277. message = {'action': 'suspend', 'uuid': uuid}
  278. Guest.emit_instruction(message=json.dumps(message))
  279. ret = dict()
  280. ret['state'] = ji.Common.exchange_state(20000)
  281. return ret
  282. except ji.PreviewingError, e:
  283. return json.loads(e.message)
  284. @Utils.dumps2response
  285. def r_resume(uuids):
  286. args_rules = [
  287. Rules.UUIDS.value
  288. ]
  289. try:
  290. ji.Check.previewing(args_rules, {'uuids': uuids})
  291. guest = Guest()
  292. for uuid in uuids.split(','):
  293. guest.uuid = uuid
  294. guest.get_by('uuid')
  295. for uuid in uuids.split(','):
  296. message = {'action': 'resume', 'uuid': uuid}
  297. Guest.emit_instruction(message=json.dumps(message))
  298. ret = dict()
  299. ret['state'] = ji.Common.exchange_state(20000)
  300. return ret
  301. except ji.PreviewingError, e:
  302. return json.loads(e.message)
  303. @Utils.dumps2response
  304. def r_delete(uuids):
  305. args_rules = [
  306. Rules.UUIDS.value
  307. ]
  308. # TODO: 加入是否删除使用的数据磁盘开关,如果为True,则顺便删除使用的磁盘。否则解除该磁盘被使用的状态。
  309. try:
  310. ji.Check.previewing(args_rules, {'uuids': uuids})
  311. guest = Guest()
  312. # 检测所指定的 UUDIs 实例都存在
  313. for uuid in uuids.split(','):
  314. guest.uuid = uuid
  315. guest.get_by('uuid')
  316. # 执行删除操作
  317. for uuid in uuids.split(','):
  318. message = {'action': 'delete_guest', 'uuid': uuid}
  319. Guest.emit_instruction(message=json.dumps(message))
  320. ret = dict()
  321. ret['state'] = ji.Common.exchange_state(20000)
  322. return ret
  323. except ji.PreviewingError, e:
  324. return json.loads(e.message)
  325. @Utils.dumps2response
  326. def r_attach_disk(uuid, disk_uuid):
  327. args_rules = [
  328. Rules.UUID.value,
  329. Rules.DISK_UUID.value
  330. ]
  331. try:
  332. ji.Check.previewing(args_rules, {'uuid': uuid, 'disk_uuid': disk_uuid})
  333. guest = Guest()
  334. guest.uuid = uuid
  335. guest.get_by('uuid')
  336. disk = Disk()
  337. disk.uuid = disk_uuid
  338. disk.get_by('uuid')
  339. ret = dict()
  340. ret['state'] = ji.Common.exchange_state(20000)
  341. # 判断欲挂载的磁盘是否空闲
  342. if disk.guest_uuid.__len__() > 0 or disk.state != DiskState.idle.value:
  343. ret['state'] = ji.Common.exchange_state(41258)
  344. return ret
  345. # 判断 Guest 是否处于可用状态
  346. if guest.status in (status.GuestState.no_state.value, status.GuestState.dirty.value):
  347. ret['state'] = ji.Common.exchange_state(41259)
  348. return ret
  349. # 通过检测未被使用的序列,来确定当前磁盘在目标 Guest 身上的序列
  350. disk.guest_uuid = guest.uuid
  351. disks, count = disk.get_by_filter(filter_str='guest_uuid:in:' + guest.uuid)
  352. already_used_sequence = list()
  353. for _disk in disks:
  354. already_used_sequence.append(_disk['sequence'])
  355. for sequence in range(0, dev_table.__len__()):
  356. if sequence not in already_used_sequence:
  357. disk.sequence = sequence
  358. break
  359. disk.state = DiskState.mounting.value
  360. config = Config()
  361. config.id = 1
  362. config.get()
  363. xml = """
  364. <disk type='network' device='disk'>
  365. <driver name='qemu' type='qcow2' cache='none'/>
  366. <source protocol='gluster' name='{0}/Images/{1}.{2}'>
  367. <host name='127.0.0.1' port='24007'/>
  368. </source>
  369. <target dev='{3}' bus='virtio'/>
  370. </disk>
  371. """.format(config.glusterfs_volume, disk.uuid, disk.format,
  372. dev_table[disk.sequence])
  373. message = {'action': 'attach_disk', 'uuid': uuid, 'xml': xml,
  374. 'passback_parameters': {'disk_uuid': disk.uuid, 'sequence': disk.sequence}}
  375. Guest.emit_instruction(message=json.dumps(message))
  376. disk.update()
  377. return ret
  378. except ji.PreviewingError, e:
  379. return json.loads(e.message)
  380. @Utils.dumps2response
  381. def r_detach_disk(disk_uuid):
  382. args_rules = [
  383. Rules.DISK_UUID.value
  384. ]
  385. try:
  386. ji.Check.previewing(args_rules, {'disk_uuid': disk_uuid})
  387. disk = Disk()
  388. disk.uuid = disk_uuid
  389. disk.get_by('uuid')
  390. ret = dict()
  391. ret['state'] = ji.Common.exchange_state(20000)
  392. if disk.state != DiskState.mounted.value or disk.sequence == 0:
  393. # 表示未被任何实例使用,已被分离
  394. # 序列为 0 的表示实例系统盘,系统盘不可以被分离
  395. # TODO: 系统盘单独范围其它状态
  396. return ret
  397. guest = Guest()
  398. guest.uuid = disk.guest_uuid
  399. guest.get_by('uuid')
  400. # 判断 Guest 是否处于可用状态
  401. if guest.status in (status.GuestState.no_state.value, status.GuestState.dirty.value):
  402. ret['state'] = ji.Common.exchange_state(41259)
  403. return ret
  404. config = Config()
  405. config.id = 1
  406. config.get()
  407. xml = """
  408. <disk type='network' device='disk'>
  409. <driver name='qemu' type='qcow2' cache='none'/>
  410. <source protocol='gluster' name='{0}/Images/{1}.{2}'>
  411. <host name='127.0.0.1' port='24007'/>
  412. </source>
  413. <target dev='{3}' bus='virtio'/>
  414. </disk>
  415. """.format(config.glusterfs_volume, disk.uuid, disk.format,
  416. dev_table[disk.sequence])
  417. message = {'action': 'detach_disk', 'uuid': disk.guest_uuid, 'xml': xml,
  418. 'passback_parameters': {'disk_uuid': disk.uuid}}
  419. Guest.emit_instruction(message=json.dumps(message))
  420. disk.state = DiskState.unloading.value
  421. disk.update()
  422. return ret
  423. except ji.PreviewingError, e:
  424. return json.loads(e.message)
  425. @Utils.dumps2response
  426. def r_migrate(uuids, destination_host):
  427. args_rules = [
  428. Rules.UUIDS.value,
  429. Rules.DESTINATION_HOST.value
  430. ]
  431. try:
  432. ji.Check.previewing(args_rules, {'uuids': uuids, 'destination_host': destination_host})
  433. guest = Guest()
  434. for uuid in uuids.split(','):
  435. guest.uuid = uuid
  436. guest.get_by('uuid')
  437. for uuid in uuids.split(','):
  438. message = {'action': 'migrate', 'uuid': uuid, 'duri': 'qemu+ssh://' + destination_host + '/system'}
  439. Guest.emit_instruction(message=json.dumps(message))
  440. ret = dict()
  441. ret['state'] = ji.Common.exchange_state(20000)
  442. return ret
  443. except ji.PreviewingError, e:
  444. return json.loads(e.message)
  445. @Utils.dumps2response
  446. def r_get(uuids):
  447. return guest_base.get(ids=uuids, ids_rule=Rules.UUIDS.value, by_field='uuid')
  448. @Utils.dumps2response
  449. def r_get_by_filter():
  450. return guest_base.get_by_filter()
  451. @Utils.dumps2response
  452. def r_content_search():
  453. return guest_base.content_search()
  454. @Utils.dumps2response
  455. def r_update(uuid):
  456. args_rules = [
  457. Rules.UUID.value
  458. ]
  459. if 'remark' in request.json:
  460. args_rules.append(
  461. Rules.REMARK.value,
  462. )
  463. if args_rules.__len__() < 2:
  464. ret = dict()
  465. ret['state'] = ji.Common.exchange_state(20000)
  466. return ret
  467. request.json['uuid'] = uuid
  468. try:
  469. ji.Check.previewing(args_rules, request.json)
  470. guest = Guest()
  471. guest.uuid = uuid
  472. guest.get_by('uuid')
  473. guest.remark = request.json.get('remark', guest.label)
  474. guest.update()
  475. guest.get()
  476. ret = dict()
  477. ret['state'] = ji.Common.exchange_state(20000)
  478. ret['data'] = guest.__dict__
  479. return ret
  480. except ji.PreviewingError, e:
  481. return json.loads(e.message)
  482. @Utils.dumps2response
  483. def r_add_boot_jobs(uuids, boot_jobs_id):
  484. args_rules = [
  485. Rules.UUIDS.value,
  486. Rules.BOOT_JOBS_ID.value
  487. ]
  488. try:
  489. ji.Check.previewing(args_rules, {'uuids': uuids, 'boot_jobs_id': boot_jobs_id})
  490. guest = Guest()
  491. for uuid in uuids.split(','):
  492. guest.uuid = uuid
  493. guest.get_by('uuid')
  494. for uuid in uuids.split(','):
  495. guest.uuid = uuid
  496. guest.add_boot_jobs(boot_jobs_id=boot_jobs_id.split(','))
  497. ret = dict()
  498. ret['state'] = ji.Common.exchange_state(20000)
  499. if uuids.split(',').__len__() > 1:
  500. ret['data'] = dict()
  501. for uuid in uuids.split(','):
  502. guest.uuid = uuid
  503. boot_jobs = dict()
  504. boot_jobs['ttl'], boot_jobs['boot_jobs'] = guest.get_boot_jobs()
  505. ret['data'][uuid] = boot_jobs
  506. else:
  507. guest.uuid = uuids
  508. ret['data'] = dict()
  509. ret['data']['ttl'], ret['data']['boot_jobs'] = guest.get_boot_jobs()
  510. return ret
  511. except ji.PreviewingError, e:
  512. return json.loads(e.message)
  513. @Utils.dumps2response
  514. def r_get_boot_jobs(uuids):
  515. args_rules = [
  516. Rules.UUIDS.value
  517. ]
  518. try:
  519. ji.Check.previewing(args_rules, {'uuids': uuids})
  520. guest = Guest()
  521. for uuid in uuids.split(','):
  522. guest.uuid = uuid
  523. guest.get_by('uuid')
  524. ret = dict()
  525. ret['state'] = ji.Common.exchange_state(20000)
  526. if uuids.split(',').__len__() > 1:
  527. ret['data'] = dict()
  528. for uuid in uuids.split(','):
  529. guest.uuid = uuid
  530. boot_jobs = dict()
  531. boot_jobs['ttl'], boot_jobs['boot_jobs'] = guest.get_boot_jobs()
  532. ret['data'][uuid] = boot_jobs
  533. else:
  534. guest.uuid = uuids
  535. ret['data'] = dict()
  536. ret['data']['ttl'], ret['data']['boot_jobs'] = guest.get_boot_jobs()
  537. return ret
  538. except ji.PreviewingError, e:
  539. return json.loads(e.message)
  540. @Utils.dumps2response
  541. def r_delete_boot_jobs(uuids, boot_jobs_id):
  542. args_rules = [
  543. Rules.UUIDS.value,
  544. Rules.BOOT_JOBS_ID.value
  545. ]
  546. try:
  547. ji.Check.previewing(args_rules, {'uuids': uuids, 'boot_jobs_id': boot_jobs_id})
  548. guest = Guest()
  549. # 检测所指定的 UUDIs 实例都存在
  550. for uuid in uuids.split(','):
  551. guest.uuid = uuid
  552. guest.get_by('uuid')
  553. for uuid in uuids.split(','):
  554. guest.uuid = uuid
  555. guest.delete_boot_jobs(boot_jobs_id=boot_jobs_id.split(','))
  556. ret = dict()
  557. ret['state'] = ji.Common.exchange_state(20000)
  558. return ret
  559. except ji.PreviewingError, e:
  560. return json.loads(e.message)
  561. @Utils.dumps2response
  562. def r_get_uuids_of_all_had_boot_job():
  563. guest = Guest()
  564. try:
  565. ret = dict()
  566. ret['state'] = ji.Common.exchange_state(20000)
  567. ret['data'] = guest.get_uuids_of_all_had_boot_job()
  568. return ret
  569. except ji.PreviewingError, e:
  570. return json.loads(e.message)
  571. @Utils.dumps2response
  572. def r_reset_password(uuids, password):
  573. args_rules = [
  574. Rules.UUIDS.value,
  575. Rules.PASSWORD.value
  576. ]
  577. try:
  578. ji.Check.previewing(args_rules, {'uuids': uuids, 'password': password})
  579. guest = Guest()
  580. # 检测所指定的 UUDIs 实例都存在
  581. for uuid in uuids.split(','):
  582. guest.uuid = uuid
  583. guest.get_by('uuid')
  584. # 重置密码的 boot job id 固定为 1
  585. for uuid in uuids.split(','):
  586. guest.uuid = uuid
  587. guest.get_by('uuid')
  588. guest.password = password
  589. guest.update()
  590. guest.add_boot_jobs(boot_jobs_id=['1'])
  591. ret = dict()
  592. ret['state'] = ji.Common.exchange_state(20000)
  593. return ret
  594. except ji.PreviewingError, e:
  595. return json.loads(e.message)