guest.py 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. import copy
  4. from math import ceil
  5. import requests
  6. import json
  7. from uuid import uuid4
  8. import random
  9. import time
  10. import jimit as ji
  11. from flask import Blueprint, url_for, request
  12. from api.base import Base
  13. from models.initialize import app, dev_table
  14. from models import DiskState, Host
  15. from models import Database as db
  16. from models import Config
  17. from models import Disk
  18. from models import Rules
  19. from models import Utils
  20. from models import Guest
  21. from models import OSTemplateImage
  22. from models import OSTemplateProfile
  23. from models import OSTemplateInitializeOperate
  24. from models import GuestXML
  25. from models import SSHKeyGuestMapping
  26. from models import SSHKey
  27. from models import Snapshot
  28. from models import status
  29. __author__ = 'James Iter'
  30. __date__ = '2017/3/22'
  31. __contact__ = 'james.iter.cn@gmail.com'
  32. __copyright__ = '(c) 2017 by James Iter.'
  33. blueprint = Blueprint(
  34. 'api_guest',
  35. __name__,
  36. url_prefix='/api/guest'
  37. )
  38. blueprints = Blueprint(
  39. 'api_guests',
  40. __name__,
  41. url_prefix='/api/guests'
  42. )
  43. guest_base = Base(the_class=Guest, the_blueprint=blueprint, the_blueprints=blueprints)
  44. os_template_image_base = Base(the_class=OSTemplateImage, the_blueprint=blueprint, the_blueprints=blueprints)
  45. os_template_profile_base = Base(the_class=OSTemplateProfile, the_blueprint=blueprint, the_blueprints=blueprints)
  46. @Utils.dumps2response
  47. def r_create():
  48. args_rules = [
  49. Rules.CPU.value,
  50. Rules.MEMORY.value,
  51. Rules.BANDWIDTH.value,
  52. Rules.BANDWIDTH_UNIT.value,
  53. Rules.OS_TEMPLATE_IMAGE_ID.value,
  54. Rules.QUANTITY.value,
  55. Rules.REMARK.value,
  56. Rules.PASSWORD.value,
  57. Rules.LEASE_TERM.value
  58. ]
  59. if 'node_id' in request.json:
  60. args_rules.append(
  61. Rules.NODE_ID.value
  62. )
  63. if 'ssh_keys_id' in request.json:
  64. args_rules.append(
  65. Rules.SSH_KEYS_ID.value
  66. )
  67. try:
  68. ret = dict()
  69. ret['state'] = ji.Common.exchange_state(20000)
  70. ji.Check.previewing(args_rules, request.json)
  71. config = Config()
  72. config.id = 1
  73. config.get()
  74. os_template_image = OSTemplateImage()
  75. os_template_profile = OSTemplateProfile()
  76. os_template_image.id = request.json.get('os_template_image_id')
  77. if not os_template_image.exist():
  78. ret['state'] = ji.Common.exchange_state(40450)
  79. ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], ': ', os_template_image.id.__str__()])
  80. return ret
  81. os_template_image.get()
  82. os_template_profile.id = os_template_image.os_template_profile_id
  83. os_template_profile.get()
  84. os_template_initialize_operates, os_template_initialize_operates_count = \
  85. OSTemplateInitializeOperate.get_by_filter(
  86. filter_str='os_template_initialize_operate_set_id:eq:' +
  87. os_template_profile.os_template_initialize_operate_set_id.__str__())
  88. if db.r.scard(app.config['ip_available_set']) < 1:
  89. ret['state'] = ji.Common.exchange_state(50350)
  90. return ret
  91. node_id = request.json.get('node_id', None)
  92. # 默认只取可随机分配虚拟机的 hosts
  93. available_hosts = Host.get_available_hosts(nonrandom=False)
  94. # 当指定了 host 时,取全部活着的 hosts
  95. if node_id is not None:
  96. available_hosts = Host.get_available_hosts(nonrandom=None)
  97. if available_hosts.__len__() == 0:
  98. ret['state'] = ji.Common.exchange_state(50351)
  99. return ret
  100. available_hosts_mapping_by_node_id = dict()
  101. for host in available_hosts:
  102. if host['node_id'] not in available_hosts_mapping_by_node_id:
  103. available_hosts_mapping_by_node_id[host['node_id']] = host
  104. if node_id is not None and node_id not in available_hosts_mapping_by_node_id:
  105. ret['state'] = ji.Common.exchange_state(50351)
  106. return ret
  107. ssh_keys_id = request.json.get('ssh_keys_id', list())
  108. ssh_keys = list()
  109. ssh_key_guest_mapping = SSHKeyGuestMapping()
  110. if ssh_keys_id.__len__() > 0:
  111. rows, _ = SSHKey.get_by_filter(
  112. filter_str=':'.join(['id', 'in', ','.join(_id.__str__() for _id in ssh_keys_id)]))
  113. for row in rows:
  114. ssh_keys.append(row['public_key'])
  115. bandwidth = request.json.get('bandwidth')
  116. bandwidth_unit = request.json.get('bandwidth_unit')
  117. if bandwidth_unit == 'k':
  118. bandwidth = bandwidth * 1000
  119. elif bandwidth_unit == 'm':
  120. bandwidth = bandwidth * 1000 ** 2
  121. elif bandwidth_unit == 'g':
  122. bandwidth = bandwidth * 1000 ** 3
  123. else:
  124. ret = dict()
  125. ret['state'] = ji.Common.exchange_state(41203)
  126. raise ji.PreviewingError(json.dumps(ret, ensure_ascii=False))
  127. # http://man7.org/linux/man-pages/man8/tc.8.html
  128. # 如果带宽大于 tc 所控最大速率,则置其为无限带宽
  129. # 34359738360 等于 tc 最大可控字节速率,换算出的比特位
  130. if bandwidth > 34359738360:
  131. bandwidth = 0
  132. quantity = request.json.get('quantity')
  133. while quantity:
  134. quantity -= 1
  135. guest = Guest()
  136. guest.uuid = uuid4().__str__()
  137. guest.cpu = request.json.get('cpu')
  138. # 虚拟机内存单位,模板生成方法中已置其为GiB
  139. guest.memory = request.json.get('memory')
  140. guest.bandwidth = bandwidth
  141. guest.os_template_image_id = request.json.get('os_template_image_id')
  142. guest.label = ji.Common.generate_random_code(length=8)
  143. guest.remark = request.json.get('remark', '')
  144. guest.password = request.json.get('password')
  145. if guest.password is None or guest.password.__len__() < 1:
  146. guest.password = ji.Common.generate_random_code(length=16)
  147. guest.ip = db.r.spop(app.config['ip_available_set'])
  148. db.r.sadd(app.config['ip_used_set'], guest.ip)
  149. guest.network = config.vm_network
  150. guest.manage_network = config.vm_manage_network
  151. guest.vnc_port = db.r.spop(app.config['vnc_port_available_set'])
  152. db.r.sadd(app.config['vnc_port_used_set'], guest.vnc_port)
  153. guest.vnc_password = ji.Common.generate_random_code(length=16)
  154. disk = Disk()
  155. disk.uuid = guest.uuid
  156. disk.remark = guest.label.__str__() + '_SystemImage'
  157. disk.format = 'qcow2'
  158. disk.sequence = 0
  159. disk.size = 0
  160. disk.path = config.storage_path + '/' + disk.uuid + '.' + disk.format
  161. disk.guest_uuid = ''
  162. # disk.node_id 由 guest 事件处理机更新。涉及迁移时,其所属 node_id 会变更。参见 @models/event_processory.py:111 附近。
  163. disk.node_id = 0
  164. disk.quota(config=config)
  165. disk.create()
  166. if node_id is None:
  167. # 在可用计算节点中平均分配任务
  168. chosen_host = available_hosts[quantity % available_hosts.__len__()]
  169. else:
  170. chosen_host = available_hosts_mapping_by_node_id[node_id]
  171. guest.node_id = chosen_host['node_id']
  172. guest_xml = GuestXML(host=chosen_host, guest=guest, disk=disk, config=config,
  173. os_type=os_template_profile.os_type)
  174. guest.xml = guest_xml.get_domain()
  175. guest.node_id = int(guest.node_id)
  176. guest.create()
  177. ssh_key_guest_mapping.guest_uuid = guest.uuid
  178. if ssh_keys_id.__len__() > 0:
  179. for ssh_key_id in ssh_keys_id:
  180. ssh_key_guest_mapping.ssh_key_id = ssh_key_id
  181. ssh_key_guest_mapping.create()
  182. # 替换占位符为有效内容
  183. _os_template_initialize_operates = copy.deepcopy(os_template_initialize_operates)
  184. for k, v in enumerate(_os_template_initialize_operates):
  185. _os_template_initialize_operates[k]['content'] = v['content'].replace('{IP}', guest.ip).\
  186. replace('{HOSTNAME}', guest.label). \
  187. replace('{PASSWORD}', guest.password). \
  188. replace('{NETMASK}', config.netmask).\
  189. replace('{GATEWAY}', config.gateway).\
  190. replace('{DNS1}', config.dns1).\
  191. replace('{DNS2}', config.dns2). \
  192. replace('{SSH-KEY}', '\n'.join(ssh_keys))
  193. _os_template_initialize_operates[k]['command'] = v['command'].replace('{IP}', guest.ip). \
  194. replace('{HOSTNAME}', guest.label). \
  195. replace('{PASSWORD}', guest.password). \
  196. replace('{NETMASK}', config.netmask). \
  197. replace('{GATEWAY}', config.gateway). \
  198. replace('{DNS1}', config.dns1). \
  199. replace('{DNS2}', config.dns2). \
  200. replace('{SSH-KEY}', '\n'.join(ssh_keys))
  201. message = {
  202. '_object': 'guest',
  203. 'action': 'create',
  204. 'uuid': guest.uuid,
  205. 'storage_mode': config.storage_mode,
  206. 'dfs_volume': config.dfs_volume,
  207. 'node_id': guest.node_id,
  208. 'name': guest.label,
  209. 'template_path': os_template_image.path,
  210. 'os_type': os_template_profile.os_type,
  211. 'disks': [disk.__dict__],
  212. 'xml': guest_xml.get_domain(),
  213. 'os_template_initialize_operates': _os_template_initialize_operates,
  214. 'passback_parameters': {}
  215. }
  216. Utils.emit_instruction(message=json.dumps(message, ensure_ascii=False))
  217. return ret
  218. except ji.PreviewingError, e:
  219. return json.loads(e.message)
  220. @Utils.dumps2response
  221. def r_reboot(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': 'reboot',
  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_reboot(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. disks, _ = Disk.get_by_filter(filter_str=':'.join(['guest_uuid', 'eq', guest.uuid]))
  261. message = {
  262. '_object': 'guest',
  263. 'action': 'force_reboot',
  264. 'uuid': uuid,
  265. 'node_id': guest.node_id,
  266. 'disks': disks
  267. }
  268. Utils.emit_instruction(message=json.dumps(message))
  269. ret = dict()
  270. ret['state'] = ji.Common.exchange_state(20000)
  271. return ret
  272. except ji.PreviewingError, e:
  273. return json.loads(e.message)
  274. @Utils.dumps2response
  275. def r_shutdown(uuids):
  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. for uuid in uuids.split(','):
  286. guest.uuid = uuid
  287. guest.get_by('uuid')
  288. message = {
  289. '_object': 'guest',
  290. 'action': 'shutdown',
  291. 'uuid': uuid,
  292. 'node_id': guest.node_id
  293. }
  294. Utils.emit_instruction(message=json.dumps(message))
  295. ret = dict()
  296. ret['state'] = ji.Common.exchange_state(20000)
  297. return ret
  298. except ji.PreviewingError, e:
  299. return json.loads(e.message)
  300. @Utils.dumps2response
  301. def r_force_shutdown(uuids):
  302. args_rules = [
  303. Rules.UUIDS.value
  304. ]
  305. try:
  306. ji.Check.previewing(args_rules, {'uuids': uuids})
  307. guest = Guest()
  308. for uuid in uuids.split(','):
  309. guest.uuid = uuid
  310. guest.get_by('uuid')
  311. for uuid in uuids.split(','):
  312. guest.uuid = uuid
  313. guest.get_by('uuid')
  314. message = {
  315. '_object': 'guest',
  316. 'action': 'force_shutdown',
  317. 'uuid': uuid,
  318. 'node_id': guest.node_id
  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_boot(uuids):
  328. # TODO: 做好关系依赖判断,比如boot不可以对suspend的实例操作。
  329. args_rules = [
  330. Rules.UUIDS.value
  331. ]
  332. try:
  333. ji.Check.previewing(args_rules, {'uuids': uuids})
  334. guest = Guest()
  335. for uuid in uuids.split(','):
  336. guest.uuid = uuid
  337. guest.get_by('uuid')
  338. config = Config()
  339. config.id = 1
  340. config.get()
  341. for uuid in uuids.split(','):
  342. guest.uuid = uuid
  343. guest.get_by('uuid')
  344. disks, _ = Disk.get_by_filter(filter_str=':'.join(['guest_uuid', 'eq', guest.uuid]))
  345. message = {
  346. '_object': 'guest',
  347. 'action': 'boot',
  348. 'uuid': uuid,
  349. 'node_id': guest.node_id,
  350. 'passback_parameters': {},
  351. 'disks': disks
  352. }
  353. Utils.emit_instruction(message=json.dumps(message))
  354. ret = dict()
  355. ret['state'] = ji.Common.exchange_state(20000)
  356. return ret
  357. except ji.PreviewingError, e:
  358. return json.loads(e.message)
  359. @Utils.dumps2response
  360. def r_suspend(uuids):
  361. args_rules = [
  362. Rules.UUIDS.value
  363. ]
  364. try:
  365. ji.Check.previewing(args_rules, {'uuids': uuids})
  366. guest = Guest()
  367. for uuid in uuids.split(','):
  368. guest.uuid = uuid
  369. guest.get_by('uuid')
  370. for uuid in uuids.split(','):
  371. guest.uuid = uuid
  372. guest.get_by('uuid')
  373. message = {
  374. '_object': 'guest',
  375. 'action': 'suspend',
  376. 'uuid': uuid,
  377. 'node_id': guest.node_id
  378. }
  379. Utils.emit_instruction(message=json.dumps(message))
  380. ret = dict()
  381. ret['state'] = ji.Common.exchange_state(20000)
  382. return ret
  383. except ji.PreviewingError, e:
  384. return json.loads(e.message)
  385. @Utils.dumps2response
  386. def r_resume(uuids):
  387. args_rules = [
  388. Rules.UUIDS.value
  389. ]
  390. try:
  391. ji.Check.previewing(args_rules, {'uuids': uuids})
  392. guest = Guest()
  393. for uuid in uuids.split(','):
  394. guest.uuid = uuid
  395. guest.get_by('uuid')
  396. for uuid in uuids.split(','):
  397. guest.uuid = uuid
  398. guest.get_by('uuid')
  399. message = {
  400. '_object': 'guest',
  401. 'action': 'resume',
  402. 'uuid': uuid,
  403. 'node_id': guest.node_id
  404. }
  405. Utils.emit_instruction(message=json.dumps(message))
  406. ret = dict()
  407. ret['state'] = ji.Common.exchange_state(20000)
  408. return ret
  409. except ji.PreviewingError, e:
  410. return json.loads(e.message)
  411. @Utils.dumps2response
  412. def r_delete(uuids):
  413. args_rules = [
  414. Rules.UUIDS.value
  415. ]
  416. # TODO: 加入是否删除使用的数据磁盘开关,如果为True,则顺便删除使用的磁盘。否则解除该磁盘被使用的状态。
  417. try:
  418. ji.Check.previewing(args_rules, {'uuids': uuids})
  419. guest = Guest()
  420. # 检测所指定的 UUDIs 实例都存在
  421. for uuid in uuids.split(','):
  422. guest.uuid = uuid
  423. guest.get_by('uuid')
  424. config = Config()
  425. config.id = 1
  426. config.get()
  427. # 执行删除操作
  428. for uuid in uuids.split(','):
  429. guest.uuid = uuid
  430. guest.get_by('uuid')
  431. message = {
  432. '_object': 'guest',
  433. 'action': 'delete',
  434. 'uuid': uuid,
  435. 'storage_mode': config.storage_mode,
  436. 'dfs_volume': config.dfs_volume,
  437. 'node_id': guest.node_id
  438. }
  439. Utils.emit_instruction(message=json.dumps(message))
  440. # 删除创建失败的 Guest
  441. if guest.status == status.GuestState.dirty.value:
  442. disk = Disk()
  443. disk.uuid = guest.uuid
  444. disk.get_by('uuid')
  445. if disk.state == status.DiskState.pending.value:
  446. disk.delete()
  447. guest.delete()
  448. SSHKeyGuestMapping.delete_by_filter(filter_str=':'.join(['guest_uuid', 'eq', guest.uuid]))
  449. ret = dict()
  450. ret['state'] = ji.Common.exchange_state(20000)
  451. return ret
  452. except ji.PreviewingError, e:
  453. return json.loads(e.message)
  454. @Utils.dumps2response
  455. def r_attach_disk(uuid, disk_uuid):
  456. args_rules = [
  457. Rules.UUID.value,
  458. Rules.DISK_UUID.value
  459. ]
  460. try:
  461. ji.Check.previewing(args_rules, {'uuid': uuid, 'disk_uuid': disk_uuid})
  462. guest = Guest()
  463. guest.uuid = uuid
  464. guest.get_by('uuid')
  465. disk = Disk()
  466. disk.uuid = disk_uuid
  467. disk.get_by('uuid')
  468. config = Config()
  469. config.id = 1
  470. config.get()
  471. ret = dict()
  472. ret['state'] = ji.Common.exchange_state(20000)
  473. # 判断欲挂载的磁盘是否空闲
  474. if disk.guest_uuid.__len__() > 0 or disk.state != DiskState.idle.value:
  475. ret['state'] = ji.Common.exchange_state(41258)
  476. return ret
  477. # 判断 Guest 是否处于可用状态
  478. if guest.status in (status.GuestState.no_state.value, status.GuestState.dirty.value):
  479. ret['state'] = ji.Common.exchange_state(41259)
  480. return ret
  481. # 判断 Guest 与 磁盘是否在同一宿主机上
  482. if config.storage_mode in [status.StorageMode.local.value, status.StorageMode.shared_mount.value]:
  483. if guest.node_id != disk.node_id:
  484. ret['state'] = ji.Common.exchange_state(41260)
  485. return ret
  486. # 通过检测未被使用的序列,来确定当前磁盘在目标 Guest 身上的序列
  487. disk.guest_uuid = guest.uuid
  488. disks, count = disk.get_by_filter(filter_str='guest_uuid:in:' + guest.uuid)
  489. already_used_sequence = list()
  490. for _disk in disks:
  491. already_used_sequence.append(_disk['sequence'])
  492. for sequence in range(0, dev_table.__len__()):
  493. if sequence not in already_used_sequence:
  494. disk.sequence = sequence
  495. break
  496. disk.state = DiskState.mounting.value
  497. guest_xml = GuestXML(guest=guest, disk=disk, config=config)
  498. message = {
  499. '_object': 'guest',
  500. 'action': 'attach_disk',
  501. 'uuid': uuid,
  502. 'node_id': guest.node_id,
  503. 'xml': guest_xml.get_disk(),
  504. 'passback_parameters': {'disk_uuid': disk.uuid, 'sequence': disk.sequence},
  505. 'disks': [disk.__dict__]
  506. }
  507. Utils.emit_instruction(message=json.dumps(message))
  508. disk.update()
  509. return ret
  510. except ji.PreviewingError, e:
  511. return json.loads(e.message)
  512. @Utils.dumps2response
  513. def r_detach_disk(disk_uuid):
  514. args_rules = [
  515. Rules.DISK_UUID.value
  516. ]
  517. try:
  518. ji.Check.previewing(args_rules, {'disk_uuid': disk_uuid})
  519. disk = Disk()
  520. disk.uuid = disk_uuid
  521. disk.get_by('uuid')
  522. ret = dict()
  523. ret['state'] = ji.Common.exchange_state(20000)
  524. if disk.state != DiskState.mounted.value or disk.sequence == 0:
  525. # 表示未被任何实例使用,已被分离
  526. # 序列为 0 的表示实例系统盘,系统盘不可以被分离
  527. # TODO: 系统盘单独范围其它状态
  528. return ret
  529. guest = Guest()
  530. guest.uuid = disk.guest_uuid
  531. guest.get_by('uuid')
  532. # 判断 Guest 是否处于可用状态
  533. if guest.status in (status.GuestState.no_state.value, status.GuestState.dirty.value):
  534. ret['state'] = ji.Common.exchange_state(41259)
  535. return ret
  536. config = Config()
  537. config.id = 1
  538. config.get()
  539. guest_xml = GuestXML(guest=guest, disk=disk, config=config)
  540. message = {
  541. '_object': 'guest',
  542. 'action': 'detach_disk',
  543. 'uuid': disk.guest_uuid,
  544. 'node_id': guest.node_id,
  545. 'xml': guest_xml.get_disk(),
  546. 'passback_parameters': {'disk_uuid': disk.uuid}
  547. }
  548. Utils.emit_instruction(message=json.dumps(message))
  549. disk.state = DiskState.unloading.value
  550. disk.update()
  551. return ret
  552. except ji.PreviewingError, e:
  553. return json.loads(e.message)
  554. @Utils.dumps2response
  555. def r_migrate(uuids, destination_host):
  556. args_rules = [
  557. Rules.UUIDS.value,
  558. Rules.DESTINATION_HOST.value
  559. ]
  560. try:
  561. ji.Check.previewing(args_rules, {'uuids': uuids, 'destination_host': destination_host})
  562. ret = dict()
  563. ret['state'] = ji.Common.exchange_state(20000)
  564. # 取全部活着的 hosts
  565. available_hosts = Host.get_available_hosts(nonrandom=None)
  566. if available_hosts.__len__() == 0:
  567. ret['state'] = ji.Common.exchange_state(50351)
  568. return ret
  569. available_hosts_mapping_by_node_id = dict()
  570. for host in available_hosts:
  571. if host['node_id'] not in available_hosts_mapping_by_node_id:
  572. available_hosts_mapping_by_node_id[host['node_id']] = host
  573. guest = Guest()
  574. for uuid in uuids.split(','):
  575. guest.uuid = uuid
  576. guest.get_by('uuid')
  577. config = Config()
  578. config.id = 1
  579. config.get()
  580. for uuid in uuids.split(','):
  581. guest.uuid = uuid
  582. guest.get_by('uuid')
  583. # 忽略宕机计算节点 上面的 虚拟机 迁移请求
  584. # 忽略目标计算节点 等于 当前所在 计算节点 的虚拟机 迁移请求
  585. if guest.node_id not in available_hosts_mapping_by_node_id or \
  586. available_hosts_mapping_by_node_id[guest.node_id]['hostname'] == destination_host:
  587. continue
  588. message = {
  589. '_object': 'guest',
  590. 'action': 'migrate',
  591. 'uuid': uuid,
  592. 'node_id': guest.node_id,
  593. 'storage_mode': config.storage_mode,
  594. 'duri': 'qemu+ssh://' + destination_host + '/system'
  595. }
  596. Utils.emit_instruction(message=json.dumps(message))
  597. return ret
  598. except ji.PreviewingError, e:
  599. return json.loads(e.message)
  600. @Utils.dumps2response
  601. def r_get(uuids):
  602. ret = guest_base.get(ids=uuids, ids_rule=Rules.UUIDS.value, by_field='uuid')
  603. if '200' != ret['state']['code']:
  604. return ret
  605. rows, _ = SSHKeyGuestMapping.get_by_filter(filter_str=':'.join(['guest_uuid', 'in', uuids]))
  606. guest_uuid_ssh_key_id_mapping = dict()
  607. ssh_keys_id = list()
  608. for row in rows:
  609. if row['ssh_key_id'] not in ssh_keys_id:
  610. ssh_keys_id.append(row['ssh_key_id'].__str__())
  611. if row['guest_uuid'] not in guest_uuid_ssh_key_id_mapping:
  612. guest_uuid_ssh_key_id_mapping[row['guest_uuid']] = list()
  613. guest_uuid_ssh_key_id_mapping[row['guest_uuid']].append(row['ssh_key_id'])
  614. rows, _ = SSHKey.get_by_filter(filter_str=':'.join(['id', 'in', ','.join(ssh_keys_id)]))
  615. ssh_key_id_mapping = dict()
  616. for row in rows:
  617. row['url'] = url_for('v_ssh_keys.show')
  618. ssh_key_id_mapping[row['id']] = row
  619. if -1 == uuids.find(','):
  620. if 'ssh_keys' not in ret['data']:
  621. ret['data']['ssh_keys'] = list()
  622. if ret['data']['uuid'] in guest_uuid_ssh_key_id_mapping:
  623. for ssh_key_id in guest_uuid_ssh_key_id_mapping[ret['data']['uuid']]:
  624. if ssh_key_id not in ssh_key_id_mapping:
  625. continue
  626. ret['data']['ssh_keys'].append(ssh_key_id_mapping[ssh_key_id])
  627. else:
  628. for i, guest in enumerate(ret['data']):
  629. if 'ssh_keys' not in ret['data'][i]:
  630. ret['data'][i]['ssh_keys'] = list()
  631. if ret['data'][i]['uuid'] in guest_uuid_ssh_key_id_mapping:
  632. for ssh_key_id in guest_uuid_ssh_key_id_mapping[ret['data'][i]['uuid']]:
  633. if ssh_key_id not in ssh_key_id_mapping:
  634. continue
  635. ret['data'][i]['ssh_keys'].append(ssh_key_id_mapping[ssh_key_id])
  636. return ret
  637. @Utils.dumps2response
  638. def r_get_by_filter():
  639. ret = guest_base.get_by_filter()
  640. uuids = list()
  641. for guest in ret['data']:
  642. uuids.append(guest['uuid'])
  643. rows, _ = SSHKeyGuestMapping.get_by_filter(filter_str=':'.join(['guest_uuid', 'in', ','.join(uuids)]))
  644. guest_uuid_ssh_key_id_mapping = dict()
  645. ssh_keys_id = list()
  646. for row in rows:
  647. if row['ssh_key_id'] not in ssh_keys_id:
  648. ssh_keys_id.append(row['ssh_key_id'].__str__())
  649. if row['guest_uuid'] not in guest_uuid_ssh_key_id_mapping:
  650. guest_uuid_ssh_key_id_mapping[row['guest_uuid']] = list()
  651. guest_uuid_ssh_key_id_mapping[row['guest_uuid']].append(row['ssh_key_id'])
  652. rows, _ = SSHKey.get_by_filter(filter_str=':'.join(['id', 'in', ','.join(ssh_keys_id)]))
  653. ssh_key_id_mapping = dict()
  654. for row in rows:
  655. row['url'] = url_for('v_ssh_keys.show')
  656. ssh_key_id_mapping[row['id']] = row
  657. rows, _ = Snapshot.get_by_filter(filter_str=':'.join(['guest_uuid', 'in', ','.join(uuids)]))
  658. snapshots_guest_uuid_mapping = dict()
  659. for row in rows:
  660. guest_uuid = row['guest_uuid']
  661. if guest_uuid not in snapshots_guest_uuid_mapping:
  662. snapshots_guest_uuid_mapping[guest_uuid] = list()
  663. snapshots_guest_uuid_mapping[guest_uuid].append(row)
  664. for i, guest in enumerate(ret['data']):
  665. guest_uuid = ret['data'][i]['uuid']
  666. if 'ssh_keys' not in ret['data'][i]:
  667. ret['data'][i]['ssh_keys'] = list()
  668. if guest_uuid in guest_uuid_ssh_key_id_mapping:
  669. for ssh_key_id in guest_uuid_ssh_key_id_mapping[guest_uuid]:
  670. if ssh_key_id not in ssh_key_id_mapping:
  671. continue
  672. ret['data'][i]['ssh_keys'].append(ssh_key_id_mapping[ssh_key_id])
  673. if 'snapshot' not in ret['data'][i]:
  674. ret['data'][i]['snapshot'] = {
  675. 'creatable': True,
  676. 'mapping': list()
  677. }
  678. if guest_uuid in snapshots_guest_uuid_mapping:
  679. ret['data'][i]['snapshot']['mapping'] = snapshots_guest_uuid_mapping[guest_uuid]
  680. for snapshot in snapshots_guest_uuid_mapping[guest_uuid]:
  681. if snapshot['progress'] == 100:
  682. continue
  683. else:
  684. ret['data'][i]['snapshot']['creatable'] = False
  685. return ret
  686. @Utils.dumps2response
  687. def r_content_search():
  688. ret = guest_base.content_search()
  689. uuids = list()
  690. for guest in ret['data']:
  691. uuids.append(guest['uuid'])
  692. rows, _ = SSHKeyGuestMapping.get_by_filter(filter_str=':'.join(['guest_uuid', 'in', ','.join(uuids)]))
  693. guest_uuid_ssh_key_id_mapping = dict()
  694. ssh_keys_id = list()
  695. for row in rows:
  696. if row['ssh_key_id'] not in ssh_keys_id:
  697. ssh_keys_id.append(row['ssh_key_id'].__str__())
  698. if row['guest_uuid'] not in guest_uuid_ssh_key_id_mapping:
  699. guest_uuid_ssh_key_id_mapping[row['guest_uuid']] = list()
  700. guest_uuid_ssh_key_id_mapping[row['guest_uuid']].append(row['ssh_key_id'])
  701. rows, _ = SSHKey.get_by_filter(filter_str=':'.join(['id', 'in', ','.join(ssh_keys_id)]))
  702. ssh_key_id_mapping = dict()
  703. for row in rows:
  704. row['url'] = url_for('v_ssh_keys.show')
  705. ssh_key_id_mapping[row['id']] = row
  706. rows, _ = Snapshot.get_by_filter(filter_str=':'.join(['guest_uuid', 'in', ','.join(uuids)]))
  707. snapshots_guest_uuid_mapping = dict()
  708. for row in rows:
  709. guest_uuid = row['guest_uuid']
  710. if guest_uuid not in snapshots_guest_uuid_mapping:
  711. snapshots_guest_uuid_mapping[guest_uuid] = list()
  712. snapshots_guest_uuid_mapping[guest_uuid].append(row)
  713. for i, guest in enumerate(ret['data']):
  714. guest_uuid = ret['data'][i]['uuid']
  715. if 'ssh_keys' not in ret['data'][i]:
  716. ret['data'][i]['ssh_keys'] = list()
  717. if guest_uuid in guest_uuid_ssh_key_id_mapping:
  718. for ssh_key_id in guest_uuid_ssh_key_id_mapping[guest_uuid]:
  719. if ssh_key_id not in ssh_key_id_mapping:
  720. continue
  721. ret['data'][i]['ssh_keys'].append(ssh_key_id_mapping[ssh_key_id])
  722. if 'snapshot' not in ret['data'][i]:
  723. ret['data'][i]['snapshot'] = {
  724. 'creatable': True,
  725. 'mapping': list()
  726. }
  727. if guest_uuid in snapshots_guest_uuid_mapping:
  728. ret['data'][i]['snapshot']['mapping'] = snapshots_guest_uuid_mapping[guest_uuid]
  729. for snapshot in snapshots_guest_uuid_mapping[guest_uuid]:
  730. if snapshot['progress'] == 100:
  731. continue
  732. else:
  733. ret['data'][i]['snapshot']['creatable'] = False
  734. return ret
  735. @Utils.dumps2response
  736. def r_distribute_count():
  737. from models import Guest
  738. rows, count = Guest.get_all()
  739. ret = dict()
  740. ret['state'] = ji.Common.exchange_state(20000)
  741. ret['data'] = {
  742. 'os_template_image_id': dict(),
  743. 'status': dict(),
  744. 'node_id': dict(),
  745. 'cpu_memory': dict(),
  746. 'cpu': 0,
  747. 'memory': 0,
  748. 'guests': rows.__len__()
  749. }
  750. for guest in rows:
  751. if guest['os_template_image_id'] not in ret['data']['os_template_image_id']:
  752. ret['data']['os_template_image_id'][guest['os_template_image_id']] = 0
  753. if guest['status'] not in ret['data']['status']:
  754. ret['data']['status'][guest['status']] = 0
  755. if guest['node_id'] not in ret['data']['node_id']:
  756. ret['data']['node_id'][guest['node_id']] = 0
  757. cpu_memory = '_'.join([str(guest['cpu']), str(guest['memory'])])
  758. if cpu_memory not in ret['data']['cpu_memory']:
  759. ret['data']['cpu_memory'][cpu_memory] = 0
  760. ret['data']['os_template_image_id'][guest['os_template_image_id']] += 1
  761. ret['data']['status'][guest['status']] += 1
  762. ret['data']['node_id'][guest['node_id']] += 1
  763. ret['data']['cpu_memory'][cpu_memory] += 1
  764. ret['data']['cpu'] += guest['cpu']
  765. ret['data']['memory'] += guest['memory']
  766. return ret
  767. @Utils.dumps2response
  768. def r_update(uuid):
  769. args_rules = [
  770. Rules.UUID.value
  771. ]
  772. if 'remark' in request.json:
  773. args_rules.append(
  774. Rules.REMARK.value,
  775. )
  776. if args_rules.__len__() < 2:
  777. ret = dict()
  778. ret['state'] = ji.Common.exchange_state(20000)
  779. return ret
  780. request.json['uuid'] = uuid
  781. try:
  782. ji.Check.previewing(args_rules, request.json)
  783. guest = Guest()
  784. guest.uuid = uuid
  785. guest.get_by('uuid')
  786. guest.remark = request.json.get('remark', guest.label)
  787. guest.update()
  788. guest.get()
  789. ret = dict()
  790. ret['state'] = ji.Common.exchange_state(20000)
  791. ret['data'] = guest.__dict__
  792. return ret
  793. except ji.PreviewingError, e:
  794. return json.loads(e.message)
  795. @Utils.dumps2response
  796. def r_reset_password(uuids, password):
  797. args_rules = [
  798. Rules.UUIDS.value,
  799. Rules.PASSWORD.value
  800. ]
  801. try:
  802. ji.Check.previewing(args_rules, {'uuids': uuids, 'password': password})
  803. guest = Guest()
  804. os_template_image = OSTemplateImage()
  805. os_template_profile = OSTemplateProfile()
  806. # 检测所指定的 UUDIs 实例都存在
  807. for uuid in uuids.split(','):
  808. guest.uuid = uuid
  809. guest.get_by('uuid')
  810. for uuid in uuids.split(','):
  811. guest.uuid = uuid
  812. guest.get_by('uuid')
  813. os_template_image.id = guest.os_template_image_id
  814. os_template_image.get()
  815. os_template_profile.id = os_template_image.os_template_profile_id
  816. os_template_profile.get()
  817. user = 'root'
  818. if os_template_profile.os_type == 'windows':
  819. user = 'administrator'
  820. # guest.password 由 guest 事件处理机更新。参见 @models/event_processory.py:189 附近。
  821. message = {
  822. '_object': 'guest',
  823. 'action': 'reset_password',
  824. 'uuid': guest.uuid,
  825. 'node_id': guest.node_id,
  826. 'os_type': os_template_profile.os_type,
  827. 'user': user,
  828. 'password': password,
  829. 'passback_parameters': {'password': password}
  830. }
  831. Utils.emit_instruction(message=json.dumps(message, ensure_ascii=False))
  832. ret = dict()
  833. ret['state'] = ji.Common.exchange_state(20000)
  834. return ret
  835. except ji.PreviewingError, e:
  836. return json.loads(e.message)
  837. @Utils.dumps2response
  838. def r_allocate_bandwidth(uuids, bandwidth, bandwidth_unit):
  839. args_rules = [
  840. Rules.UUIDS.value,
  841. Rules.BANDWIDTH_IN_URL.value,
  842. Rules.BANDWIDTH_UNIT.value,
  843. ]
  844. try:
  845. ji.Check.previewing(args_rules, {'uuids': uuids, 'bandwidth': bandwidth, 'bandwidth_unit': bandwidth_unit})
  846. ret = dict()
  847. ret['state'] = ji.Common.exchange_state(20000)
  848. bandwidth = int(bandwidth)
  849. if bandwidth_unit == 'k':
  850. bandwidth = bandwidth * 1000
  851. elif bandwidth_unit == 'm':
  852. bandwidth = bandwidth * 1000 ** 2
  853. elif bandwidth_unit == 'g':
  854. bandwidth = bandwidth * 1000 ** 3
  855. else:
  856. ret['state'] = ji.Common.exchange_state(41203)
  857. return ret
  858. # http://man7.org/linux/man-pages/man8/tc.8.html
  859. # 如果带宽大于 tc 所控最大速率,则置其为无限带宽
  860. # 34359738360 等于 tc 最大可控字节速率,换算出的比特位
  861. if bandwidth > 34359738360:
  862. bandwidth = 0
  863. guest = Guest()
  864. # 检测所指定的 UUDIs 实例都存在
  865. for uuid in uuids.split(','):
  866. guest.uuid = uuid
  867. guest.get_by('uuid')
  868. for uuid in uuids.split(','):
  869. guest.uuid = uuid
  870. guest.get_by('uuid')
  871. guest.bandwidth = bandwidth
  872. message = {
  873. '_object': 'guest',
  874. 'action': 'allocate_bandwidth',
  875. 'uuid': guest.uuid,
  876. 'node_id': guest.node_id,
  877. 'bandwidth': guest.bandwidth,
  878. 'passback_parameters': {'bandwidth': guest.bandwidth}
  879. }
  880. Utils.emit_instruction(message=json.dumps(message, ensure_ascii=False))
  881. return ret
  882. except ji.PreviewingError, e:
  883. return json.loads(e.message)
  884. @Utils.dumps2response
  885. def r_adjust_ability(uuids, cpu, memory):
  886. args_rules = [
  887. Rules.UUIDS.value,
  888. Rules.CPU.value,
  889. Rules.MEMORY.value,
  890. ]
  891. try:
  892. ret = dict()
  893. ret['state'] = ji.Common.exchange_state(20000)
  894. cpu = int(cpu)
  895. memory = int(memory)
  896. ji.Check.previewing(args_rules, {'uuids': uuids, 'cpu': cpu, 'memory': memory})
  897. not_ready_yet_of_guests = list()
  898. guest = Guest()
  899. # 检测所指定的 UUDIs 实例都存在。且状态都为可以操作状态(即关闭状态)。
  900. for uuid in uuids.split(','):
  901. guest.uuid = uuid
  902. guest.get_by('uuid')
  903. if guest.status != status.GuestState.shutoff.value:
  904. not_ready_yet_of_guests.append(guest.__dict__)
  905. if not_ready_yet_of_guests.__len__() > 0:
  906. ret['state'] = ji.Common.exchange_state(41261)
  907. ret['data'] = not_ready_yet_of_guests
  908. return ret
  909. for uuid in uuids.split(','):
  910. guest.uuid = uuid
  911. guest.get_by('uuid')
  912. guest.cpu = cpu
  913. guest.memory = memory
  914. message = {
  915. '_object': 'guest',
  916. 'action': 'adjust_ability',
  917. 'uuid': guest.uuid,
  918. 'node_id': guest.node_id,
  919. 'cpu': guest.cpu,
  920. 'memory': guest.memory,
  921. 'passback_parameters': {'cpu': guest.cpu, 'memory': guest.memory}
  922. }
  923. Utils.emit_instruction(message=json.dumps(message, ensure_ascii=False))
  924. return ret
  925. except ji.PreviewingError, e:
  926. return json.loads(e.message)
  927. @Utils.dumps2response
  928. def r_refresh_guest_state():
  929. try:
  930. ret = dict()
  931. ret['state'] = ji.Common.exchange_state(20000)
  932. # 取全部活着的 hosts
  933. available_hosts = Host.get_available_hosts(nonrandom=None)
  934. if available_hosts.__len__() == 0:
  935. ret['state'] = ji.Common.exchange_state(50351)
  936. return ret
  937. for host in available_hosts:
  938. message = {
  939. '_object': 'global',
  940. 'action': 'refresh_guest_state',
  941. 'node_id': host['node_id']
  942. }
  943. Utils.emit_instruction(message=json.dumps(message, ensure_ascii=False))
  944. except ji.PreviewingError, e:
  945. return json.loads(e.message)
  946. @Utils.dumps2response
  947. def r_show():
  948. args = list()
  949. page = int(request.args.get('page', 1))
  950. page_size = int(request.args.get('page_size', 10))
  951. keyword = request.args.get('keyword', None)
  952. if page is not None:
  953. args.append('page=' + page.__str__())
  954. if page_size is not None:
  955. args.append('page_size=' + page_size.__str__())
  956. if keyword is not None:
  957. args.append('keyword=' + keyword.__str__())
  958. hosts_url = url_for('api_hosts.r_get_by_filter', _external=True)
  959. guests_url = url_for('api_guests.r_get_by_filter', _external=True)
  960. if keyword is not None:
  961. guests_url = url_for('api_guests.r_content_search', _external=True)
  962. if args.__len__() > 0:
  963. guests_url = guests_url + '?' + '&'.join(args)
  964. hosts_ret = requests.get(url=hosts_url, cookies=request.cookies)
  965. hosts_ret = json.loads(hosts_ret.content)
  966. hosts_mapping_by_node_id = dict()
  967. for host in hosts_ret['data']:
  968. hosts_mapping_by_node_id[int(host['node_id'])] = host
  969. guests_ret = requests.get(url=guests_url, cookies=request.cookies)
  970. guests_ret = json.loads(guests_ret.content)
  971. os_templates_image, _ = OSTemplateImage.get_by_filter()
  972. os_templates_image_mapping_by_id = dict()
  973. for os_template_image in os_templates_image:
  974. os_templates_image_mapping_by_id[os_template_image['id']] = os_template_image
  975. os_templates_profile, _ = OSTemplateProfile.get_by_filter()
  976. os_templates_profile_mapping_by_id = dict()
  977. for os_template_profile in os_templates_profile:
  978. os_templates_profile_mapping_by_id[os_template_profile['id']] = os_template_profile
  979. last_page = int(ceil(guests_ret['paging']['total'] / float(page_size)))
  980. page_length = 5
  981. pages = list()
  982. if page < int(ceil(page_length / 2.0)):
  983. for i in range(1, page_length + 1):
  984. pages.append(i)
  985. if i == last_page or last_page == 0:
  986. break
  987. elif last_page - page < page_length / 2:
  988. for i in range(last_page - page_length + 1, last_page + 1):
  989. if i < 1:
  990. continue
  991. pages.append(i)
  992. else:
  993. for i in range(page - page_length / 2, page + int(ceil(page_length / 2.0))):
  994. pages.append(i)
  995. if i == last_page or last_page == 0:
  996. break
  997. ret = dict()
  998. ret['state'] = ji.Common.exchange_state(20000)
  999. ret['data'] = {
  1000. 'guests': guests_ret['data'],
  1001. 'os_templates_image_mapping_by_id': os_templates_image_mapping_by_id,
  1002. 'os_templates_profile_mapping_by_id': os_templates_profile_mapping_by_id,
  1003. 'hosts_mapping_by_node_id': hosts_mapping_by_node_id,
  1004. 'paging': guests_ret['paging'],
  1005. 'page': page,
  1006. 'page_size': page_size,
  1007. 'keyword': keyword,
  1008. 'pages': pages,
  1009. 'last_page': last_page
  1010. }
  1011. return ret
  1012. @Utils.dumps2response
  1013. def r_vnc(uuid):
  1014. guest_ret = guest_base.get(ids=uuid, ids_rule=Rules.UUID.value, by_field='uuid')
  1015. if '200' != guest_ret['state']['code']:
  1016. return guest_ret
  1017. hosts_url = url_for('api_hosts.r_get_by_filter', _external=True)
  1018. hosts_ret = requests.get(url=hosts_url, cookies=request.cookies)
  1019. hosts_ret = json.loads(hosts_ret.content)
  1020. hosts_mapping_by_node_id = dict()
  1021. for host in hosts_ret['data']:
  1022. hosts_mapping_by_node_id[int(host['node_id'])] = host
  1023. port = random.randrange(50000, 60000)
  1024. while True:
  1025. if not Utils.port_is_opened(port=port):
  1026. break
  1027. port = random.randrange(50000, 60000)
  1028. payload = {'listen_port': port, 'target_host': hosts_mapping_by_node_id[guest_ret['data']['node_id']]['hostname'],
  1029. 'target_port': guest_ret['data']['vnc_port']}
  1030. db.r.rpush(app.config['ipc_queue'], json.dumps(payload, ensure_ascii=False))
  1031. time.sleep(1)
  1032. ret = dict()
  1033. ret['state'] = ji.Common.exchange_state(20000)
  1034. ret['data'] = {
  1035. 'port': port,
  1036. 'vnc_password': guest_ret['data']['vnc_password']
  1037. }
  1038. return ret
  1039. @Utils.dumps2response
  1040. def r_detail(uuid):
  1041. hosts_url = url_for('api_hosts.r_get_by_filter', _external=True)
  1042. hosts_ret = requests.get(url=hosts_url, cookies=request.cookies)
  1043. hosts_ret = json.loads(hosts_ret.content)
  1044. hosts_mapping_by_node_id = dict()
  1045. for host in hosts_ret['data']:
  1046. hosts_mapping_by_node_id[int(host['node_id'])] = host
  1047. guest = Guest()
  1048. guest.uuid = uuid
  1049. guest.get_by(field='uuid')
  1050. guest.ssh_keys = list()
  1051. rows, _ = SSHKeyGuestMapping.get_by_filter(filter_str=':'.join(['guest_uuid', 'in', guest.uuid]))
  1052. ssh_keys_id = list()
  1053. for row in rows:
  1054. if row['ssh_key_id'] not in ssh_keys_id:
  1055. ssh_keys_id.append(row['ssh_key_id'].__str__())
  1056. rows, _ = SSHKey.get_by_filter(filter_str=':'.join(['id', 'in', ','.join(ssh_keys_id)]))
  1057. for row in rows:
  1058. row['url'] = url_for('v_ssh_keys.show')
  1059. guest.ssh_keys.append(row)
  1060. os_template_image = OSTemplateImage()
  1061. os_template_image.id = guest.os_template_image_id.__str__()
  1062. os_template_image.get()
  1063. os_template_profiles, _ = OSTemplateProfile.get_by_filter()
  1064. os_templates_profile_mapping_by_id = dict()
  1065. for os_template_profile in os_template_profiles:
  1066. os_templates_profile_mapping_by_id[os_template_profile['id']] = os_template_profile
  1067. disks_url = url_for('api_disks.r_get_by_filter', filter='guest_uuid:in:' + guest.uuid, _external=True)
  1068. disks_ret = requests.get(url=disks_url, cookies=request.cookies)
  1069. disks = json.loads(disks_ret.content)['data']
  1070. config = Config()
  1071. config.id = 1
  1072. config.get()
  1073. ret = dict()
  1074. ret['state'] = ji.Common.exchange_state(20000)
  1075. ret['data'] = {
  1076. 'uuid': uuid,
  1077. 'guest': guest.__dict__,
  1078. 'os_template_image': os_template_image.__dict__,
  1079. 'os_templates_profile_mapping_by_id': os_templates_profile_mapping_by_id,
  1080. 'hosts_mapping_by_node_id': hosts_mapping_by_node_id,
  1081. 'disks': disks,
  1082. 'config': config.__dict__
  1083. }
  1084. return ret