guest.py 52 KB

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