guest.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  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 DiskState
  10. from models import OSInitWrite
  11. from models.initialize import app, dev_table
  12. from models import Database as db
  13. from models import Config
  14. from models import GuestDisk
  15. from models import Rules
  16. from models import Utils
  17. from models import Guest
  18. from models import OSTemplate
  19. from models import GuestXML
  20. from models import status
  21. __author__ = 'James Iter'
  22. __date__ = '2017/3/22'
  23. __contact__ = 'james.iter.cn@gmail.com'
  24. __copyright__ = '(c) 2017 by James Iter.'
  25. blueprint = Blueprint(
  26. 'guest',
  27. __name__,
  28. url_prefix='/api/guest'
  29. )
  30. blueprints = Blueprint(
  31. 'guests',
  32. __name__,
  33. url_prefix='/api/guests'
  34. )
  35. @Utils.dumps2response
  36. def r_create():
  37. args_rules = [
  38. Rules.CPU.value,
  39. Rules.MEMORY.value,
  40. Rules.OS_TEMPLATE_ID.value,
  41. Rules.QUANTITY.value,
  42. Rules.NAME.value,
  43. Rules.PASSWORD.value,
  44. Rules.LEASE_TERM.value
  45. ]
  46. try:
  47. ret = dict()
  48. ret['state'] = ji.Common.exchange_state(20000)
  49. ji.Check.previewing(args_rules, request.json)
  50. config = Config()
  51. config.id = 1
  52. config.get()
  53. os_template = OSTemplate()
  54. os_template.id = request.json.get('os_template_id')
  55. if not os_template.exist():
  56. ret['state'] = ji.Common.exchange_state(40450)
  57. ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], ': ', os_template.id.__str__()])
  58. return ret
  59. os_template.get()
  60. os_init_writes, os_init_writes_count = OSInitWrite.get_by_filter(
  61. filter_str='os_init_id:in:' + os_template.os_init_id.__str__())
  62. if db.r.scard(app.config['ip_available_set']) < 1:
  63. ret['state'] = ji.Common.exchange_state(50350)
  64. return ret
  65. quantity = request.json.get('quantity')
  66. while quantity:
  67. quantity -= 1
  68. guest = Guest()
  69. guest.uuid = uuid4().__str__()
  70. guest.cpu = request.json.get('cpu')
  71. # 虚拟机内存单位,模板生成方法中已置其为GiB
  72. guest.memory = request.json.get('memory')
  73. guest.os_template_id = request.json.get('os_template_id')
  74. guest.name = request.json.get('name')
  75. if quantity > 0:
  76. '-'.join([guest.name, quantity.__str__()])
  77. guest.password = request.json.get('password')
  78. if guest.password is None or guest.password.__len__() < 1:
  79. guest.password = ji.Common.generate_random_code(length=16)
  80. while guest.name.__len__() < 1 or guest.exist_by('name'):
  81. guest.name = ji.Common.generate_random_code(length=8)
  82. guest.ip = db.r.spop(app.config['ip_available_set'])
  83. db.r.sadd(app.config['ip_used_set'], guest.ip)
  84. guest.network = config.vm_network
  85. guest.manage_network = config.vm_manage_network
  86. guest.vnc_port = db.r.spop(app.config['vnc_port_available_set'])
  87. db.r.sadd(app.config['vnc_port_used_set'], guest.vnc_port)
  88. guest.vnc_password = ji.Common.generate_random_code(length=16)
  89. guest_disk = {'uuid': uuid4().__str__(), 'size': -1, 'format': 'qcow2', 'sequence': 0}
  90. guest_xml = GuestXML(guest=guest, disk=guest_disk, config=config)
  91. guest.xml = guest_xml.get_domain()
  92. guest.create()
  93. # 替换占位符为有效内容
  94. _os_init_writes = copy.deepcopy(os_init_writes)
  95. for k, v in enumerate(_os_init_writes):
  96. _os_init_writes[k]['content'] = v['content'].replace('{IP}', guest.ip).\
  97. replace('{HOSTNAME}', guest.name).\
  98. replace('{NETMASK}', config.netmask).\
  99. replace('{GATEWAY}', config.gateway).\
  100. replace('{DNS1}', config.dns1).\
  101. replace('{DNS2}', config.dns2)
  102. create_vm_msg = {
  103. 'action': 'create_vm',
  104. 'uuid': guest.uuid,
  105. 'name': guest.name,
  106. 'glusterfs_volume': config.glusterfs_volume,
  107. 'template_path': 'template_pool/' + os_template.name,
  108. 'guest_disk': guest_disk,
  109. 'writes': _os_init_writes,
  110. 'password': guest.password,
  111. 'xml': guest_xml.get_domain()
  112. }
  113. db.r.rpush(app.config['downstream_queue'], json.dumps(create_vm_msg, ensure_ascii=False))
  114. return ret
  115. except ji.PreviewingError, e:
  116. return json.loads(e.message)
  117. @Utils.dumps2response
  118. def r_reboot(uuids):
  119. args_rules = [
  120. Rules.UUIDS.value
  121. ]
  122. try:
  123. ji.Check.previewing(args_rules, {'uuids': uuids})
  124. guest = Guest()
  125. for uuid in uuids.split(','):
  126. guest.uuid = uuid
  127. guest.get_by('uuid')
  128. for uuid in uuids.split(','):
  129. message = {'action': 'reboot', 'uuid': uuid}
  130. Guest.emit_instruction(message=json.dumps(message))
  131. ret = dict()
  132. ret['state'] = ji.Common.exchange_state(20000)
  133. return ret
  134. except ji.PreviewingError, e:
  135. return json.loads(e.message)
  136. @Utils.dumps2response
  137. def r_force_reboot(uuids):
  138. args_rules = [
  139. Rules.UUIDS.value
  140. ]
  141. try:
  142. ji.Check.previewing(args_rules, {'uuids': uuids})
  143. guest = Guest()
  144. for uuid in uuids.split(','):
  145. guest.uuid = uuid
  146. guest.get_by('uuid')
  147. for uuid in uuids.split(','):
  148. message = {'action': 'force_reboot', 'uuid': uuid}
  149. Guest.emit_instruction(message=json.dumps(message))
  150. ret = dict()
  151. ret['state'] = ji.Common.exchange_state(20000)
  152. return ret
  153. except ji.PreviewingError, e:
  154. return json.loads(e.message)
  155. @Utils.dumps2response
  156. def r_shutdown(uuids):
  157. args_rules = [
  158. Rules.UUIDS.value
  159. ]
  160. try:
  161. ji.Check.previewing(args_rules, {'uuids': uuids})
  162. guest = Guest()
  163. for uuid in uuids.split(','):
  164. guest.uuid = uuid
  165. guest.get_by('uuid')
  166. for uuid in uuids.split(','):
  167. message = {'action': 'shutdown', 'uuid': uuid}
  168. Guest.emit_instruction(message=json.dumps(message))
  169. ret = dict()
  170. ret['state'] = ji.Common.exchange_state(20000)
  171. return ret
  172. except ji.PreviewingError, e:
  173. return json.loads(e.message)
  174. @Utils.dumps2response
  175. def r_force_shutdown(uuids):
  176. args_rules = [
  177. Rules.UUIDS.value
  178. ]
  179. try:
  180. ji.Check.previewing(args_rules, {'uuids': uuids})
  181. guest = Guest()
  182. for uuid in uuids.split(','):
  183. guest.uuid = uuid
  184. guest.get_by('uuid')
  185. for uuid in uuids.split(','):
  186. message = {'action': 'force_shutdown', 'uuid': uuid}
  187. Guest.emit_instruction(message=json.dumps(message))
  188. ret = dict()
  189. ret['state'] = ji.Common.exchange_state(20000)
  190. return ret
  191. except ji.PreviewingError, e:
  192. return json.loads(e.message)
  193. @Utils.dumps2response
  194. def r_boot(uuids):
  195. args_rules = [
  196. Rules.UUIDS.value
  197. ]
  198. try:
  199. ji.Check.previewing(args_rules, {'uuids': uuids})
  200. guest = Guest()
  201. for uuid in uuids.split(','):
  202. guest.uuid = uuid
  203. guest.get_by('uuid')
  204. for uuid in uuids.split(','):
  205. message = {'action': 'boot', 'uuid': uuid}
  206. Guest.emit_instruction(message=json.dumps(message))
  207. ret = dict()
  208. ret['state'] = ji.Common.exchange_state(20000)
  209. return ret
  210. except ji.PreviewingError, e:
  211. return json.loads(e.message)
  212. @Utils.dumps2response
  213. def r_suspend(uuids):
  214. args_rules = [
  215. Rules.UUIDS.value
  216. ]
  217. try:
  218. ji.Check.previewing(args_rules, {'uuids': uuids})
  219. guest = Guest()
  220. for uuid in uuids.split(','):
  221. guest.uuid = uuid
  222. guest.get_by('uuid')
  223. for uuid in uuids.split(','):
  224. message = {'action': 'suspend', 'uuid': uuid}
  225. Guest.emit_instruction(message=json.dumps(message))
  226. ret = dict()
  227. ret['state'] = ji.Common.exchange_state(20000)
  228. return ret
  229. except ji.PreviewingError, e:
  230. return json.loads(e.message)
  231. @Utils.dumps2response
  232. def r_resume(uuids):
  233. args_rules = [
  234. Rules.UUIDS.value
  235. ]
  236. try:
  237. ji.Check.previewing(args_rules, {'uuids': uuids})
  238. guest = Guest()
  239. for uuid in uuids.split(','):
  240. guest.uuid = uuid
  241. guest.get_by('uuid')
  242. for uuid in uuids.split(','):
  243. message = {'action': 'resume', 'uuid': uuid}
  244. Guest.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_delete(uuids):
  252. args_rules = [
  253. Rules.UUIDS.value
  254. ]
  255. # TODO: 加入是否删除使用的数据磁盘开关
  256. try:
  257. ji.Check.previewing(args_rules, {'uuids': uuids})
  258. guest = Guest()
  259. # 检测所指定的 UUDIs 实例都存在
  260. for uuid in uuids.split(','):
  261. guest.uuid = uuid
  262. guest.get_by('uuid')
  263. # 执行删除操作
  264. for uuid in uuids.split(','):
  265. message = {'action': 'delete', 'uuid': uuid}
  266. Guest.emit_instruction(message=json.dumps(message))
  267. ret = dict()
  268. ret['state'] = ji.Common.exchange_state(20000)
  269. return ret
  270. except ji.PreviewingError, e:
  271. return json.loads(e.message)
  272. @Utils.dumps2response
  273. def r_attach_disk(uuid, disk_uuid):
  274. args_rules = [
  275. Rules.UUID.value,
  276. Rules.DISK_UUID.value
  277. ]
  278. try:
  279. ji.Check.previewing(args_rules, {'uuid': uuid, 'disk_uuid': disk_uuid})
  280. guest = Guest()
  281. guest.uuid = uuid
  282. guest.get_by('uuid')
  283. guest_disk = GuestDisk()
  284. guest_disk.uuid = disk_uuid
  285. guest_disk.get_by('uuid')
  286. ret = dict()
  287. ret['state'] = ji.Common.exchange_state(20000)
  288. # 判断欲挂载的磁盘是否空闲
  289. if guest_disk.guest_uuid.__len__() > 0:
  290. ret['state'] = ji.Common.exchange_state(41258)
  291. return ret
  292. # 判断 Guest 是否处于可用状态
  293. if guest.status in (status.GuestState.no_state.value, status.GuestState.dirty.value):
  294. ret['state'] = ji.Common.exchange_state(41259)
  295. return ret
  296. # 取出该 guest 已挂载的磁盘,来做出决定,确定该磁盘的序列
  297. guest_disk.guest_uuid = guest.uuid
  298. disks, count = guest_disk.get_by_filter(filter_str='guest_uuid:in:' + guest.uuid)
  299. guest_disk.sequence = count + 1
  300. config = Config()
  301. config.id = 1
  302. config.get()
  303. xml = """
  304. <disk type='network' device='disk'>
  305. <driver name='qemu' type='qcow2' cache='none'/>
  306. <source protocol='gluster' name='{0}/DiskPool/{1}.{2}'>
  307. <host name='127.0.0.1' port='24007'/>
  308. </source>
  309. <target dev='{3}' bus='virtio'/>
  310. </disk>
  311. """.format(config.glusterfs_volume, guest_disk.uuid, guest_disk.format,
  312. dev_table[guest_disk.sequence])
  313. message = {'action': 'attach_disk', 'uuid': uuid, 'xml': xml,
  314. 'passback_parameters': {'disk_uuid': guest_disk.uuid, 'sequence': guest_disk.sequence}}
  315. Guest.emit_instruction(message=json.dumps(message))
  316. return ret
  317. except ji.PreviewingError, e:
  318. return json.loads(e.message)
  319. @Utils.dumps2response
  320. def r_detach_disk(disk_uuid):
  321. args_rules = [
  322. Rules.DISK_UUID.value
  323. ]
  324. try:
  325. ji.Check.previewing(args_rules, {'disk_uuid': disk_uuid})
  326. guest_disk = GuestDisk()
  327. guest_disk.uuid = disk_uuid
  328. guest_disk.get_by('uuid')
  329. ret = dict()
  330. ret['state'] = ji.Common.exchange_state(20000)
  331. if guest_disk.state != DiskState.mounted.value or guest_disk.sequence == 0:
  332. # 表示未被任何实例使用,已被分离
  333. # 序列为 0 的表示实例系统盘,系统盘不可以被分离
  334. # TODO: 系统盘单独范围其它状态
  335. return ret
  336. guest = Guest()
  337. guest.uuid = guest_disk.guest_uuid
  338. guest.get_by('uuid')
  339. # 判断 Guest 是否处于可用状态
  340. if guest.status in (status.GuestState.no_state.value, status.GuestState.dirty.value):
  341. ret['state'] = ji.Common.exchange_state(41259)
  342. return ret
  343. config = Config()
  344. config.id = 1
  345. config.get()
  346. xml = """
  347. <disk type='network' device='disk'>
  348. <driver name='qemu' type='qcow2' cache='none'/>
  349. <source protocol='gluster' name='{0}/DiskPool/{1}.{2}'>
  350. <host name='127.0.0.1' port='24007'/>
  351. </source>
  352. <target dev='{3}' bus='virtio'/>
  353. </disk>
  354. """.format(config.glusterfs_volume, guest_disk.uuid, guest_disk.format,
  355. dev_table[guest_disk.sequence])
  356. message = {'action': 'detach_disk', 'uuid': guest_disk.guest_uuid, 'xml': xml,
  357. 'passback_parameters': {'disk_uuid': guest_disk.uuid}}
  358. Guest.emit_instruction(message=json.dumps(message))
  359. return ret
  360. except ji.PreviewingError, e:
  361. return json.loads(e.message)
  362. @Utils.dumps2response
  363. def r_migrate(uuids, destination_host):
  364. args_rules = [
  365. Rules.UUIDS.value,
  366. Rules.DESTINATION_HOST.value
  367. ]
  368. try:
  369. ji.Check.previewing(args_rules, {'uuids': uuids, 'destination_host': destination_host})
  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. message = {'action': 'migrate', 'uuid': uuid, 'duri': 'qemu+ssh://' + destination_host + '/system'}
  376. Guest.emit_instruction(message=json.dumps(message))
  377. ret = dict()
  378. ret['state'] = ji.Common.exchange_state(20000)
  379. return ret
  380. except ji.PreviewingError, e:
  381. return json.loads(e.message)
  382. @Utils.dumps2response
  383. def r_get(uuid):
  384. guest = Guest()
  385. args_rules = [
  386. Rules.UUID.value
  387. ]
  388. guest.uuid = uuid
  389. try:
  390. ji.Check.previewing(args_rules, guest.__dict__)
  391. guest.get_by('uuid')
  392. ret = dict()
  393. ret['state'] = ji.Common.exchange_state(20000)
  394. ret['data'] = guest.__dict__
  395. return ret
  396. except ji.PreviewingError, e:
  397. return json.loads(e.message)
  398. @Utils.dumps2response
  399. def r_get_by_filter():
  400. page = str(request.args.get('page', 1))
  401. page_size = str(request.args.get('page_size', 50))
  402. args_rules = [
  403. Rules.PAGE.value,
  404. Rules.PAGE_SIZE.value
  405. ]
  406. try:
  407. ji.Check.previewing(args_rules, {'page': page, 'page_size': page_size})
  408. except ji.PreviewingError, e:
  409. return json.loads(e.message)
  410. page = int(page)
  411. page_size = int(page_size)
  412. # 把page和page_size换算成offset和limit
  413. offset = (page - 1) * page_size
  414. # offset, limit将覆盖page及page_size的影响
  415. offset = str(request.args.get('offset', offset))
  416. limit = str(request.args.get('limit', page_size))
  417. order_by = request.args.get('order_by', 'id')
  418. order = request.args.get('order', 'asc')
  419. filter_str = request.args.get('filter', '')
  420. args_rules = [
  421. Rules.OFFSET.value,
  422. Rules.LIMIT.value,
  423. Rules.ORDER_BY.value,
  424. Rules.ORDER.value
  425. ]
  426. try:
  427. ji.Check.previewing(args_rules, {'offset': offset, 'limit': limit, 'order_by': order_by, 'order': order})
  428. offset = int(offset)
  429. limit = int(limit)
  430. ret = dict()
  431. ret['state'] = ji.Common.exchange_state(20000)
  432. ret['data'] = list()
  433. ret['paging'] = {'total': 0, 'offset': offset, 'limit': limit, 'page': page, 'page_size': page_size,
  434. 'next': '', 'prev': '', 'first': '', 'last': ''}
  435. ret['data'], ret['paging']['total'] = Guest.get_by_filter(offset=offset, limit=limit, order_by=order_by,
  436. order=order, filter_str=filter_str)
  437. host_url = request.host_url.rstrip('/')
  438. other_str = '&filter=' + filter_str + '&order=' + order + '&order_by=' + order_by
  439. last_pagination = (ret['paging']['total'] + page_size - 1) / page_size
  440. if page <= 1:
  441. ret['paging']['prev'] = host_url + blueprints.url_prefix + '?page=1&page_size=' + page_size.__str__() + \
  442. other_str
  443. else:
  444. ret['paging']['prev'] = host_url + blueprints.url_prefix + '?page=' + str(page-1) + '&page_size=' + \
  445. page_size.__str__() + other_str
  446. if page >= last_pagination:
  447. ret['paging']['next'] = host_url + blueprints.url_prefix + '?page=' + last_pagination.__str__() + \
  448. '&page_size=' + page_size.__str__() + other_str
  449. else:
  450. ret['paging']['next'] = host_url + blueprints.url_prefix + '?page=' + str(page+1) + '&page_size=' + \
  451. page_size.__str__() + other_str
  452. ret['paging']['first'] = host_url + blueprints.url_prefix + '?page=1&page_size=' + \
  453. page_size.__str__() + other_str
  454. ret['paging']['last'] = \
  455. host_url + blueprints.url_prefix + '?page=' + last_pagination.__str__() + '&page_size=' + \
  456. page_size.__str__() + other_str
  457. return ret
  458. except ji.PreviewingError, e:
  459. return json.loads(e.message)
  460. @Utils.dumps2response
  461. def r_content_search():
  462. page = str(request.args.get('page', 1))
  463. page_size = str(request.args.get('page_size', 50))
  464. args_rules = [
  465. Rules.PAGE.value,
  466. Rules.PAGE_SIZE.value
  467. ]
  468. try:
  469. ji.Check.previewing(args_rules, {'page': page, 'page_size': page_size})
  470. except ji.PreviewingError, e:
  471. return json.loads(e.message)
  472. page = int(page)
  473. page_size = int(page_size)
  474. # 把page和page_size换算成offset和limit
  475. offset = (page - 1) * page_size
  476. # offset, limit将覆盖page及page_size的影响
  477. offset = str(request.args.get('offset', offset))
  478. limit = str(request.args.get('limit', page_size))
  479. order_by = request.args.get('order_by', 'id')
  480. order = request.args.get('order', 'asc')
  481. keyword = request.args.get('keyword', '')
  482. args_rules = [
  483. Rules.OFFSET.value,
  484. Rules.LIMIT.value,
  485. Rules.ORDER_BY.value,
  486. Rules.ORDER.value,
  487. Rules.KEYWORD.value
  488. ]
  489. try:
  490. ji.Check.previewing(args_rules, {'offset': offset, 'limit': limit, 'order_by': order_by, 'order': order,
  491. 'keyword': keyword})
  492. offset = int(offset)
  493. limit = int(limit)
  494. ret = dict()
  495. ret['state'] = ji.Common.exchange_state(20000)
  496. ret['data'] = list()
  497. ret['paging'] = {'total': 0, 'offset': offset, 'limit': limit, 'page': page, 'page_size': page_size}
  498. ret['data'], ret['paging']['total'] = Guest.content_search(offset=offset, limit=limit, order_by=order_by,
  499. order=order, keyword=keyword)
  500. host_url = request.host_url.rstrip('/')
  501. other_str = '&keyword=' + keyword + '&order=' + order + '&order_by=' + order_by
  502. last_pagination = (ret['paging']['total'] + page_size - 1) / page_size
  503. if page <= 1:
  504. ret['paging']['prev'] = host_url + blueprints.url_prefix + '/_search?page=1&page_size=' + \
  505. page_size.__str__() + other_str
  506. else:
  507. ret['paging']['prev'] = host_url + blueprints.url_prefix + '/_search?page=' + str(page-1) + \
  508. '&page_size=' + page_size.__str__() + other_str
  509. if page >= last_pagination:
  510. ret['paging']['next'] = host_url + blueprints.url_prefix + '/_search?page=' + last_pagination.__str__() + \
  511. '&page_size=' + page_size.__str__() + other_str
  512. else:
  513. ret['paging']['next'] = host_url + blueprints.url_prefix + '/_search?page=' + str(page+1) + \
  514. '&page_size=' + page_size.__str__() + other_str
  515. ret['paging']['first'] = host_url + blueprints.url_prefix + '/_search?page=1&page_size=' + \
  516. page_size.__str__() + other_str
  517. ret['paging']['last'] = \
  518. host_url + blueprints.url_prefix + '/_search?page=' + last_pagination.__str__() + '&page_size=' + \
  519. page_size.__str__() + other_str
  520. return ret
  521. except ji.PreviewingError, e:
  522. return json.loads(e.message)
  523. @Utils.dumps2response
  524. def r_update(uuid):
  525. args_rules = [
  526. Rules.UUID.value
  527. ]
  528. if 'remark' in request.json:
  529. args_rules.append(
  530. Rules.REMARK.value,
  531. )
  532. if args_rules.__len__() < 2:
  533. ret = dict()
  534. ret['state'] = ji.Common.exchange_state(20000)
  535. return ret
  536. request.json['uuid'] = uuid
  537. try:
  538. ji.Check.previewing(args_rules, request.json)
  539. guest = Guest()
  540. guest.uuid = uuid
  541. guest.get_by('uuid')
  542. guest.remark = request.json.get('remark', guest.name)
  543. guest.update()
  544. guest.get()
  545. ret = dict()
  546. ret['state'] = ji.Common.exchange_state(20000)
  547. ret['data'] = guest.__dict__
  548. return ret
  549. except ji.PreviewingError, e:
  550. return json.loads(e.message)