guest.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. import copy
  4. from flask import Blueprint
  5. from flask import request
  6. import json
  7. from uuid import uuid4
  8. import jimit as ji
  9. from models import OSInitWrite
  10. from models.initialize import app, dev_table
  11. from models import Database as db
  12. from models import Config
  13. from models import GuestDisk
  14. from models import Rules
  15. from models import Utils
  16. from models import Guest
  17. from models import OSTemplate
  18. from models import GuestXML
  19. __author__ = 'James Iter'
  20. __date__ = '2017/3/22'
  21. __contact__ = 'james.iter.cn@gmail.com'
  22. __copyright__ = '(c) 2017 by James Iter.'
  23. blueprint = Blueprint(
  24. 'guest',
  25. __name__,
  26. url_prefix='/api/guest'
  27. )
  28. blueprints = Blueprint(
  29. 'guests',
  30. __name__,
  31. url_prefix='/api/guests'
  32. )
  33. @Utils.dumps2response
  34. def r_create():
  35. args_rules = [
  36. Rules.CPU.value,
  37. Rules.MEMORY.value,
  38. Rules.OS_TEMPLATE_ID.value,
  39. Rules.DISKS.value,
  40. Rules.QUANTITY.value,
  41. Rules.NAME.value,
  42. Rules.PASSWORD.value,
  43. Rules.LEASE_TERM.value
  44. ]
  45. try:
  46. ret = dict()
  47. ret['state'] = ji.Common.exchange_state(20000)
  48. ji.Check.previewing(args_rules, request.json)
  49. config = Config()
  50. config.id = 1
  51. config.get()
  52. os_template = OSTemplate()
  53. os_template.id = request.json.get('os_template_id')
  54. if not os_template.exist():
  55. ret['state'] = ji.Common.exchange_state(40450)
  56. ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], ': ', os_template.id])
  57. return ret
  58. os_template.get()
  59. os_init_writes, os_init_writes_count = OSInitWrite.get_by_filter(
  60. filter_str='os_init_id:in:' + os_template.os_init_id.__str__())
  61. if db.r.scard(app.config['ip_available_set']) < 1:
  62. ret['state'] = ji.Common.exchange_state(50350)
  63. return ret
  64. quantity = request.json.get('quantity')
  65. while quantity:
  66. quantity -= 1
  67. guest = Guest()
  68. guest.uuid = uuid4().__str__()
  69. guest.cpu = request.json.get('cpu')
  70. # 虚拟机内存单位,模板生成方法中已置其为GiB
  71. guest.memory = request.json.get('memory')
  72. guest.os_template_id = request.json.get('os_template_id')
  73. guest.name = request.json.get('name')
  74. guest.password = request.json.get('password')
  75. if guest.password is None or guest.password.__len__() < 1:
  76. guest.password = ji.Common.generate_random_code(length=16)
  77. while guest.name.__len__() < 1 or guest.exist_by('name'):
  78. guest.name = ji.Common.generate_random_code(length=8)
  79. guest.ip = db.r.spop(app.config['ip_available_set'])
  80. db.r.sadd(app.config['ip_used_set'], guest.ip)
  81. guest.network = config.vm_network
  82. guest.manage_network = config.vm_manage_network
  83. guest.vnc_port = db.r.spop(app.config['vnc_port_available_set'])
  84. db.r.sadd(app.config['vnc_port_used_set'], guest.vnc_port)
  85. guest.vnc_password = ji.Common.generate_random_code(length=16)
  86. guest_disks = list()
  87. guest_disks.append({'label': uuid4().__str__(), 'size': -1, 'format': 'qcow2'})
  88. for i, disk in enumerate(request.json.get('disks')):
  89. guest_disk = GuestDisk()
  90. guest_disk.size = disk.get('size')
  91. # TODO: 设定磁盘最大大小
  92. if not isinstance(guest_disk.size, int) or guest_disk.size < 1:
  93. continue
  94. guest_disk.guest_uuid = guest.uuid
  95. guest_disk.label = uuid4().__str__()
  96. guest_disk.sequence = i + 1
  97. guest_disk.format = 'qcow2'
  98. guest_disk.create()
  99. guest_disks.append({'label': guest_disk.label, 'size': guest_disk.size, 'format': guest_disk.format})
  100. guest_xml = GuestXML(guest=guest, disks=guest_disks, config=config)
  101. guest.xml = guest_xml.get_domain()
  102. guest.create()
  103. # 替换占位符为有效内容
  104. _os_init_writes = copy.deepcopy(os_init_writes)
  105. for k, v in enumerate(_os_init_writes):
  106. _os_init_writes[k]['content'] = v['content'].replace('{IP}', guest.ip).\
  107. replace('{HOSTNAME}', guest.name).\
  108. replace('{NETMASK}', config.netmask).\
  109. replace('{GATEWAY}', config.gateway).\
  110. replace('{DNS1}', config.dns1).\
  111. replace('{DNS2}', config.dns2)
  112. create_vm_msg = {
  113. 'action': 'create_vm',
  114. 'uuid': guest.uuid,
  115. 'name': guest.name,
  116. 'glusterfs_volume': config.glusterfs_volume,
  117. 'template_path': 'template_pool/' + os_template.name,
  118. 'guest_disks': guest_disks,
  119. 'writes': _os_init_writes,
  120. 'password': guest.password,
  121. 'xml': guest_xml.get_domain()
  122. }
  123. db.r.rpush(app.config['downstream_queue'], json.dumps(create_vm_msg, ensure_ascii=False))
  124. return ret
  125. except ji.PreviewingError, e:
  126. return json.loads(e.message)
  127. @Utils.dumps2response
  128. def r_reboot(uuids):
  129. args_rules = [
  130. Rules.UUIDS.value
  131. ]
  132. try:
  133. ji.Check.previewing(args_rules, {'uuids': uuids})
  134. guest = Guest()
  135. for uuid in uuids.split(','):
  136. guest.uuid = uuid
  137. guest.get_by('uuid')
  138. for uuid in uuids.split(','):
  139. message = {'action': 'reboot', 'uuid': uuid}
  140. Guest.emit_instruction(message=json.dumps(message))
  141. ret = dict()
  142. ret['state'] = ji.Common.exchange_state(20000)
  143. return ret
  144. except ji.PreviewingError, e:
  145. return json.loads(e.message)
  146. @Utils.dumps2response
  147. def r_force_reboot(uuids):
  148. args_rules = [
  149. Rules.UUIDS.value
  150. ]
  151. try:
  152. ji.Check.previewing(args_rules, {'uuids': uuids})
  153. guest = Guest()
  154. for uuid in uuids.split(','):
  155. guest.uuid = uuid
  156. guest.get_by('uuid')
  157. for uuid in uuids.split(','):
  158. message = {'action': 'force_reboot', 'uuid': uuid}
  159. Guest.emit_instruction(message=json.dumps(message))
  160. ret = dict()
  161. ret['state'] = ji.Common.exchange_state(20000)
  162. return ret
  163. except ji.PreviewingError, e:
  164. return json.loads(e.message)
  165. @Utils.dumps2response
  166. def r_shutdown(uuids):
  167. args_rules = [
  168. Rules.UUIDS.value
  169. ]
  170. try:
  171. ji.Check.previewing(args_rules, {'uuids': uuids})
  172. guest = Guest()
  173. for uuid in uuids.split(','):
  174. guest.uuid = uuid
  175. guest.get_by('uuid')
  176. for uuid in uuids.split(','):
  177. message = {'action': 'shutdown', 'uuid': uuid}
  178. Guest.emit_instruction(message=json.dumps(message))
  179. ret = dict()
  180. ret['state'] = ji.Common.exchange_state(20000)
  181. return ret
  182. except ji.PreviewingError, e:
  183. return json.loads(e.message)
  184. @Utils.dumps2response
  185. def r_force_shutdown(uuids):
  186. args_rules = [
  187. Rules.UUIDS.value
  188. ]
  189. try:
  190. ji.Check.previewing(args_rules, {'uuids': uuids})
  191. guest = Guest()
  192. for uuid in uuids.split(','):
  193. guest.uuid = uuid
  194. guest.get_by('uuid')
  195. for uuid in uuids.split(','):
  196. message = {'action': 'force_shutdown', 'uuid': uuid}
  197. Guest.emit_instruction(message=json.dumps(message))
  198. ret = dict()
  199. ret['state'] = ji.Common.exchange_state(20000)
  200. return ret
  201. except ji.PreviewingError, e:
  202. return json.loads(e.message)
  203. @Utils.dumps2response
  204. def r_boot(uuids):
  205. args_rules = [
  206. Rules.UUIDS.value
  207. ]
  208. try:
  209. ji.Check.previewing(args_rules, {'uuids': uuids})
  210. guest = Guest()
  211. for uuid in uuids.split(','):
  212. guest.uuid = uuid
  213. guest.get_by('uuid')
  214. for uuid in uuids.split(','):
  215. message = {'action': 'boot', 'uuid': uuid}
  216. Guest.emit_instruction(message=json.dumps(message))
  217. ret = dict()
  218. ret['state'] = ji.Common.exchange_state(20000)
  219. return ret
  220. except ji.PreviewingError, e:
  221. return json.loads(e.message)
  222. @Utils.dumps2response
  223. def r_suspend(uuids):
  224. args_rules = [
  225. Rules.UUIDS.value
  226. ]
  227. try:
  228. ji.Check.previewing(args_rules, {'uuids': uuids})
  229. guest = Guest()
  230. for uuid in uuids.split(','):
  231. guest.uuid = uuid
  232. guest.get_by('uuid')
  233. for uuid in uuids.split(','):
  234. message = {'action': 'suspend', 'uuid': uuid}
  235. Guest.emit_instruction(message=json.dumps(message))
  236. ret = dict()
  237. ret['state'] = ji.Common.exchange_state(20000)
  238. return ret
  239. except ji.PreviewingError, e:
  240. return json.loads(e.message)
  241. @Utils.dumps2response
  242. def r_resume(uuids):
  243. args_rules = [
  244. Rules.UUIDS.value
  245. ]
  246. try:
  247. ji.Check.previewing(args_rules, {'uuids': uuids})
  248. guest = Guest()
  249. for uuid in uuids.split(','):
  250. guest.uuid = uuid
  251. guest.get_by('uuid')
  252. for uuid in uuids.split(','):
  253. message = {'action': 'resume', 'uuid': uuid}
  254. Guest.emit_instruction(message=json.dumps(message))
  255. ret = dict()
  256. ret['state'] = ji.Common.exchange_state(20000)
  257. return ret
  258. except ji.PreviewingError, e:
  259. return json.loads(e.message)
  260. @Utils.dumps2response
  261. def r_delete(uuids):
  262. args_rules = [
  263. Rules.UUIDS.value
  264. ]
  265. try:
  266. ji.Check.previewing(args_rules, {'uuids': uuids})
  267. guest = Guest()
  268. for uuid in uuids.split(','):
  269. guest.uuid = uuid
  270. guest.get_by('uuid')
  271. for uuid in uuids.split(','):
  272. message = {'action': 'delete', 'uuid': uuid}
  273. Guest.emit_instruction(message=json.dumps(message))
  274. ret = dict()
  275. ret['state'] = ji.Common.exchange_state(20000)
  276. return ret
  277. except ji.PreviewingError, e:
  278. return json.loads(e.message)
  279. @Utils.dumps2response
  280. def r_disk_resize(device_node_uuid, size):
  281. args_rules = [
  282. Rules.DEVICE_NODE_UUID.value,
  283. Rules.DISK_SIZE.value
  284. ]
  285. try:
  286. ji.Check.previewing(args_rules, {'device_node_uuid': device_node_uuid, 'size': size})
  287. guest_disk = GuestDisk()
  288. guest_disk.label = device_node_uuid
  289. guest_disk.get_by('label')
  290. message = {'action': 'disk-resize', 'uuid': guest_disk.guest_uuid,
  291. 'device_node': dev_table[guest_disk.sequence], 'size': size}
  292. Guest.emit_instruction(message=json.dumps(message))
  293. ret = dict()
  294. ret['state'] = ji.Common.exchange_state(20000)
  295. return ret
  296. except ji.PreviewingError, e:
  297. return json.loads(e.message)
  298. @Utils.dumps2response
  299. def r_create_disk(size):
  300. args_rules = [
  301. Rules.DISK_SIZE.value
  302. ]
  303. try:
  304. ji.Check.previewing(args_rules, {'size': size})
  305. ret = dict()
  306. ret['state'] = ji.Common.exchange_state(20000)
  307. size = int(size)
  308. if not isinstance(size, int) or size < 1:
  309. ret['state'] = ji.Common.exchange_state(41255)
  310. return ret
  311. guest_disk = GuestDisk()
  312. guest_disk.guest_uuid = ''
  313. guest_disk.size = size
  314. guest_disk.label = uuid4().__str__()
  315. guest_disk.sequence = -1
  316. guest_disk.format = 'qcow2'
  317. guest_disk.create()
  318. config = Config()
  319. config.id = 1
  320. config.get()
  321. image_path = '/'.join(['DiskPool', guest_disk.label + '.' + guest_disk.format])
  322. message = {'action': 'create_disk', 'glusterfs_volume': config.glusterfs_volume,
  323. 'image_path': image_path, 'size': guest_disk.size}
  324. db.r.rpush(app.config['downstream_queue'], json.dumps(message, ensure_ascii=False))
  325. return ret
  326. except ji.PreviewingError, e:
  327. return json.loads(e.message)
  328. @Utils.dumps2response
  329. def r_attach_disk(uuid, size):
  330. args_rules = [
  331. Rules.UUID.value,
  332. Rules.DISK_SIZE.value
  333. ]
  334. try:
  335. ji.Check.previewing(args_rules, {'uuid': uuid, 'size': size})
  336. guest = Guest()
  337. guest.uuid = uuid
  338. guest.get_by('uuid')
  339. guest_disk = GuestDisk()
  340. guest_disk.guest_uuid = guest.uuid
  341. disks, count = guest_disk.get_all()
  342. guest_disk.size = int(size)
  343. ret = dict()
  344. ret['state'] = ji.Common.exchange_state(20000)
  345. if not isinstance(guest_disk.size, int) or guest_disk.size < 1:
  346. ret['state'] = ji.Common.exchange_state(41255)
  347. return ret
  348. config = Config()
  349. config.id = 1
  350. config.get()
  351. guest_disk.label = uuid4().__str__()
  352. guest_disk.sequence = count + 1
  353. guest_disk.format = 'qcow2'
  354. guest_disk.create()
  355. xml = """
  356. <disk type='network' device='disk'>
  357. <driver name='qemu' type='qcow2' cache='none'/>
  358. <source protocol='gluster' name='{0}/VMs/{1}/{2}.{3}'>
  359. <host name='127.0.0.1' port='24007'/>
  360. </source>
  361. <target dev='{4}' bus='virtio'/>
  362. </disk>
  363. """.format(config.glusterfs_volume, guest.name, guest_disk.label, guest_disk.format,
  364. dev_table[guest_disk.sequence])
  365. message = {'action': 'attach_disk', 'uuid': uuid, 'xml': xml,
  366. 'disk': {'label': guest_disk.label, 'size': guest_disk.size, 'format': guest_disk.format}}
  367. Guest.emit_instruction(message=json.dumps(message))
  368. return ret
  369. except ji.PreviewingError, e:
  370. return json.loads(e.message)
  371. @Utils.dumps2response
  372. def r_detach_disk(uuid):
  373. args_rules = [
  374. Rules.UUID.value
  375. ]
  376. try:
  377. ji.Check.previewing(args_rules, {'uuid': uuid})
  378. guest = Guest()
  379. guest.uuid = uuid
  380. guest.get_by('uuid')
  381. message = {'action': 'detach_disk', 'uuid': uuid}
  382. Guest.emit_instruction(message=json.dumps(message))
  383. ret = dict()
  384. ret['state'] = ji.Common.exchange_state(20000)
  385. return ret
  386. except ji.PreviewingError, e:
  387. return json.loads(e.message)
  388. @Utils.dumps2response
  389. def r_migrate(uuids, destination_host):
  390. args_rules = [
  391. Rules.UUIDS.value,
  392. Rules.DESTINATION_HOST.value
  393. ]
  394. try:
  395. ji.Check.previewing(args_rules, {'uuids': uuids, 'destination_host': destination_host})
  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. message = {'action': 'migrate', 'uuid': uuid, 'duri': 'qemu+ssh://' + destination_host + '/system'}
  402. Guest.emit_instruction(message=json.dumps(message))
  403. ret = dict()
  404. ret['state'] = ji.Common.exchange_state(20000)
  405. return ret
  406. except ji.PreviewingError, e:
  407. return json.loads(e.message)