guest.py 27 KB

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