guest.py 46 KB

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