guest.py 23 KB

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