guest.py 27 KB

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