guest.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  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 Disk
  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. disk = Disk()
  90. disk.uuid = guest.uuid
  91. disk.label = guest.name + '_SystemImage'
  92. disk.format = 'qcow2'
  93. disk.sequence = 0
  94. disk.size = 0
  95. disk.path = config.storage_path + '/' + disk.uuid + '.' + disk.format
  96. disk.guest_uuid = ''
  97. disk.create()
  98. guest_xml = GuestXML(guest=guest, disk=disk, config=config)
  99. guest.xml = guest_xml.get_domain()
  100. guest.create()
  101. # 替换占位符为有效内容
  102. _os_init_writes = copy.deepcopy(os_init_writes)
  103. for k, v in enumerate(_os_init_writes):
  104. _os_init_writes[k]['content'] = v['content'].replace('{IP}', guest.ip).\
  105. replace('{HOSTNAME}', guest.name).\
  106. replace('{NETMASK}', config.netmask).\
  107. replace('{GATEWAY}', config.gateway).\
  108. replace('{DNS1}', config.dns1).\
  109. replace('{DNS2}', config.dns2)
  110. create_vm_msg = {
  111. 'action': 'create_guest',
  112. 'uuid': guest.uuid,
  113. 'name': guest.name,
  114. 'glusterfs_volume': config.glusterfs_volume,
  115. 'template_path': os_template.path,
  116. 'disk': disk.__dict__,
  117. 'writes': _os_init_writes,
  118. 'password': guest.password,
  119. 'xml': guest_xml.get_domain()
  120. }
  121. db.r.rpush(app.config['downstream_queue'], json.dumps(create_vm_msg, ensure_ascii=False))
  122. return ret
  123. except ji.PreviewingError, e:
  124. return json.loads(e.message)
  125. @Utils.dumps2response
  126. def r_reboot(uuids):
  127. args_rules = [
  128. Rules.UUIDS.value
  129. ]
  130. try:
  131. ji.Check.previewing(args_rules, {'uuids': uuids})
  132. guest = Guest()
  133. for uuid in uuids.split(','):
  134. guest.uuid = uuid
  135. guest.get_by('uuid')
  136. for uuid in uuids.split(','):
  137. message = {'action': 'reboot', 'uuid': uuid}
  138. Guest.emit_instruction(message=json.dumps(message))
  139. ret = dict()
  140. ret['state'] = ji.Common.exchange_state(20000)
  141. return ret
  142. except ji.PreviewingError, e:
  143. return json.loads(e.message)
  144. @Utils.dumps2response
  145. def r_force_reboot(uuids):
  146. args_rules = [
  147. Rules.UUIDS.value
  148. ]
  149. try:
  150. ji.Check.previewing(args_rules, {'uuids': uuids})
  151. guest = Guest()
  152. for uuid in uuids.split(','):
  153. guest.uuid = uuid
  154. guest.get_by('uuid')
  155. for uuid in uuids.split(','):
  156. message = {'action': 'force_reboot', 'uuid': uuid}
  157. Guest.emit_instruction(message=json.dumps(message))
  158. ret = dict()
  159. ret['state'] = ji.Common.exchange_state(20000)
  160. return ret
  161. except ji.PreviewingError, e:
  162. return json.loads(e.message)
  163. @Utils.dumps2response
  164. def r_shutdown(uuids):
  165. args_rules = [
  166. Rules.UUIDS.value
  167. ]
  168. try:
  169. ji.Check.previewing(args_rules, {'uuids': uuids})
  170. guest = Guest()
  171. for uuid in uuids.split(','):
  172. guest.uuid = uuid
  173. guest.get_by('uuid')
  174. for uuid in uuids.split(','):
  175. message = {'action': 'shutdown', 'uuid': uuid}
  176. Guest.emit_instruction(message=json.dumps(message))
  177. ret = dict()
  178. ret['state'] = ji.Common.exchange_state(20000)
  179. return ret
  180. except ji.PreviewingError, e:
  181. return json.loads(e.message)
  182. @Utils.dumps2response
  183. def r_force_shutdown(uuids):
  184. args_rules = [
  185. Rules.UUIDS.value
  186. ]
  187. try:
  188. ji.Check.previewing(args_rules, {'uuids': uuids})
  189. guest = Guest()
  190. for uuid in uuids.split(','):
  191. guest.uuid = uuid
  192. guest.get_by('uuid')
  193. for uuid in uuids.split(','):
  194. message = {'action': 'force_shutdown', 'uuid': uuid}
  195. Guest.emit_instruction(message=json.dumps(message))
  196. ret = dict()
  197. ret['state'] = ji.Common.exchange_state(20000)
  198. return ret
  199. except ji.PreviewingError, e:
  200. return json.loads(e.message)
  201. @Utils.dumps2response
  202. def r_boot(uuids):
  203. # TODO: 做好关系依赖判断,比如boot不可以对suspend的实例操作。
  204. args_rules = [
  205. Rules.UUIDS.value
  206. ]
  207. try:
  208. ji.Check.previewing(args_rules, {'uuids': uuids})
  209. guest = Guest()
  210. for uuid in uuids.split(','):
  211. guest.uuid = uuid
  212. guest.get_by('uuid')
  213. for uuid in uuids.split(','):
  214. message = {'action': 'boot', 'uuid': uuid}
  215. Guest.emit_instruction(message=json.dumps(message))
  216. ret = dict()
  217. ret['state'] = ji.Common.exchange_state(20000)
  218. return ret
  219. except ji.PreviewingError, e:
  220. return json.loads(e.message)
  221. @Utils.dumps2response
  222. def r_suspend(uuids):
  223. args_rules = [
  224. Rules.UUIDS.value
  225. ]
  226. try:
  227. ji.Check.previewing(args_rules, {'uuids': uuids})
  228. guest = Guest()
  229. for uuid in uuids.split(','):
  230. guest.uuid = uuid
  231. guest.get_by('uuid')
  232. for uuid in uuids.split(','):
  233. message = {'action': 'suspend', 'uuid': uuid}
  234. Guest.emit_instruction(message=json.dumps(message))
  235. ret = dict()
  236. ret['state'] = ji.Common.exchange_state(20000)
  237. return ret
  238. except ji.PreviewingError, e:
  239. return json.loads(e.message)
  240. @Utils.dumps2response
  241. def r_resume(uuids):
  242. args_rules = [
  243. Rules.UUIDS.value
  244. ]
  245. try:
  246. ji.Check.previewing(args_rules, {'uuids': uuids})
  247. guest = Guest()
  248. for uuid in uuids.split(','):
  249. guest.uuid = uuid
  250. guest.get_by('uuid')
  251. for uuid in uuids.split(','):
  252. message = {'action': 'resume', 'uuid': uuid}
  253. Guest.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_delete(uuids):
  261. args_rules = [
  262. Rules.UUIDS.value
  263. ]
  264. # TODO: 加入是否删除使用的数据磁盘开关,如果为True,则顺便删除使用的磁盘。否则解除该磁盘被使用的状态。
  265. try:
  266. ji.Check.previewing(args_rules, {'uuids': uuids})
  267. guest = Guest()
  268. # 检测所指定的 UUDIs 实例都存在
  269. for uuid in uuids.split(','):
  270. guest.uuid = uuid
  271. guest.get_by('uuid')
  272. # 执行删除操作
  273. for uuid in uuids.split(','):
  274. message = {'action': 'delete_guest', 'uuid': uuid}
  275. Guest.emit_instruction(message=json.dumps(message))
  276. ret = dict()
  277. ret['state'] = ji.Common.exchange_state(20000)
  278. return ret
  279. except ji.PreviewingError, e:
  280. return json.loads(e.message)
  281. @Utils.dumps2response
  282. def r_attach_disk(uuid, disk_uuid):
  283. args_rules = [
  284. Rules.UUID.value,
  285. Rules.DISK_UUID.value
  286. ]
  287. try:
  288. ji.Check.previewing(args_rules, {'uuid': uuid, 'disk_uuid': disk_uuid})
  289. guest = Guest()
  290. guest.uuid = uuid
  291. guest.get_by('uuid')
  292. disk = Disk()
  293. disk.uuid = disk_uuid
  294. disk.get_by('uuid')
  295. ret = dict()
  296. ret['state'] = ji.Common.exchange_state(20000)
  297. # 判断欲挂载的磁盘是否空闲
  298. if disk.guest_uuid.__len__() > 0:
  299. ret['state'] = ji.Common.exchange_state(41258)
  300. return ret
  301. # 判断 Guest 是否处于可用状态
  302. if guest.status in (status.GuestState.no_state.value, status.GuestState.dirty.value):
  303. ret['state'] = ji.Common.exchange_state(41259)
  304. return ret
  305. # 取出该 guest 已挂载的磁盘,来做出决定,确定该磁盘的序列
  306. disk.guest_uuid = guest.uuid
  307. disks, count = disk.get_by_filter(filter_str='guest_uuid:in:' + guest.uuid)
  308. disk.sequence = count + 1
  309. config = Config()
  310. config.id = 1
  311. config.get()
  312. xml = """
  313. <disk type='network' device='disk'>
  314. <driver name='qemu' type='qcow2' cache='none'/>
  315. <source protocol='gluster' name='{0}/DiskPool/{1}.{2}'>
  316. <host name='127.0.0.1' port='24007'/>
  317. </source>
  318. <target dev='{3}' bus='virtio'/>
  319. </disk>
  320. """.format(config.glusterfs_volume, disk.uuid, disk.format,
  321. dev_table[disk.sequence])
  322. message = {'action': 'attach_disk', 'uuid': uuid, 'xml': xml,
  323. 'passback_parameters': {'disk_uuid': disk.uuid, 'sequence': disk.sequence}}
  324. Guest.emit_instruction(message=json.dumps(message))
  325. return ret
  326. except ji.PreviewingError, e:
  327. return json.loads(e.message)
  328. @Utils.dumps2response
  329. def r_detach_disk(disk_uuid):
  330. args_rules = [
  331. Rules.DISK_UUID.value
  332. ]
  333. try:
  334. ji.Check.previewing(args_rules, {'disk_uuid': disk_uuid})
  335. disk = Disk()
  336. disk.uuid = disk_uuid
  337. disk.get_by('uuid')
  338. ret = dict()
  339. ret['state'] = ji.Common.exchange_state(20000)
  340. if disk.state != DiskState.mounted.value or disk.sequence == 0:
  341. # 表示未被任何实例使用,已被分离
  342. # 序列为 0 的表示实例系统盘,系统盘不可以被分离
  343. # TODO: 系统盘单独范围其它状态
  344. return ret
  345. guest = Guest()
  346. guest.uuid = disk.guest_uuid
  347. guest.get_by('uuid')
  348. # 判断 Guest 是否处于可用状态
  349. if guest.status in (status.GuestState.no_state.value, status.GuestState.dirty.value):
  350. ret['state'] = ji.Common.exchange_state(41259)
  351. return ret
  352. config = Config()
  353. config.id = 1
  354. config.get()
  355. xml = """
  356. <disk type='network' device='disk'>
  357. <driver name='qemu' type='qcow2' cache='none'/>
  358. <source protocol='gluster' name='{0}/DiskPool/{1}.{2}'>
  359. <host name='127.0.0.1' port='24007'/>
  360. </source>
  361. <target dev='{3}' bus='virtio'/>
  362. </disk>
  363. """.format(config.glusterfs_volume, disk.uuid, disk.format,
  364. dev_table[disk.sequence])
  365. message = {'action': 'detach_disk', 'uuid': disk.guest_uuid, 'xml': xml,
  366. 'passback_parameters': {'disk_uuid': disk.uuid}}
  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_migrate(uuids, destination_host):
  373. args_rules = [
  374. Rules.UUIDS.value,
  375. Rules.DESTINATION_HOST.value
  376. ]
  377. try:
  378. ji.Check.previewing(args_rules, {'uuids': uuids, 'destination_host': destination_host})
  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. message = {'action': 'migrate', 'uuid': uuid, 'duri': 'qemu+ssh://' + destination_host + '/system'}
  385. Guest.emit_instruction(message=json.dumps(message))
  386. ret = dict()
  387. ret['state'] = ji.Common.exchange_state(20000)
  388. return ret
  389. except ji.PreviewingError, e:
  390. return json.loads(e.message)
  391. @Utils.dumps2response
  392. def r_get(uuid):
  393. guest = Guest()
  394. args_rules = [
  395. Rules.UUID.value
  396. ]
  397. guest.uuid = uuid
  398. try:
  399. ji.Check.previewing(args_rules, guest.__dict__)
  400. guest.get_by('uuid')
  401. ret = dict()
  402. ret['state'] = ji.Common.exchange_state(20000)
  403. ret['data'] = guest.__dict__
  404. return ret
  405. except ji.PreviewingError, e:
  406. return json.loads(e.message)
  407. @Utils.dumps2response
  408. def r_get_by_filter():
  409. page = str(request.args.get('page', 1))
  410. page_size = str(request.args.get('page_size', 50))
  411. args_rules = [
  412. Rules.PAGE.value,
  413. Rules.PAGE_SIZE.value
  414. ]
  415. try:
  416. ji.Check.previewing(args_rules, {'page': page, 'page_size': page_size})
  417. except ji.PreviewingError, e:
  418. return json.loads(e.message)
  419. page = int(page)
  420. page_size = int(page_size)
  421. # 把page和page_size换算成offset和limit
  422. offset = (page - 1) * page_size
  423. # offset, limit将覆盖page及page_size的影响
  424. offset = str(request.args.get('offset', offset))
  425. limit = str(request.args.get('limit', page_size))
  426. order_by = request.args.get('order_by', 'id')
  427. order = request.args.get('order', 'asc')
  428. filter_str = request.args.get('filter', '')
  429. args_rules = [
  430. Rules.OFFSET.value,
  431. Rules.LIMIT.value,
  432. Rules.ORDER_BY.value,
  433. Rules.ORDER.value
  434. ]
  435. try:
  436. ji.Check.previewing(args_rules, {'offset': offset, 'limit': limit, 'order_by': order_by, 'order': order})
  437. offset = int(offset)
  438. limit = int(limit)
  439. ret = dict()
  440. ret['state'] = ji.Common.exchange_state(20000)
  441. ret['data'] = list()
  442. ret['paging'] = {'total': 0, 'offset': offset, 'limit': limit, 'page': page, 'page_size': page_size,
  443. 'next': '', 'prev': '', 'first': '', 'last': ''}
  444. ret['data'], ret['paging']['total'] = Guest.get_by_filter(offset=offset, limit=limit, order_by=order_by,
  445. order=order, filter_str=filter_str)
  446. host_url = request.host_url.rstrip('/')
  447. other_str = '&filter=' + filter_str + '&order=' + order + '&order_by=' + order_by
  448. last_pagination = (ret['paging']['total'] + page_size - 1) / page_size
  449. if page <= 1:
  450. ret['paging']['prev'] = host_url + blueprints.url_prefix + '?page=1&page_size=' + page_size.__str__() + \
  451. other_str
  452. else:
  453. ret['paging']['prev'] = host_url + blueprints.url_prefix + '?page=' + str(page-1) + '&page_size=' + \
  454. page_size.__str__() + other_str
  455. if page >= last_pagination:
  456. ret['paging']['next'] = host_url + blueprints.url_prefix + '?page=' + last_pagination.__str__() + \
  457. '&page_size=' + page_size.__str__() + other_str
  458. else:
  459. ret['paging']['next'] = host_url + blueprints.url_prefix + '?page=' + str(page+1) + '&page_size=' + \
  460. page_size.__str__() + other_str
  461. ret['paging']['first'] = host_url + blueprints.url_prefix + '?page=1&page_size=' + \
  462. page_size.__str__() + other_str
  463. ret['paging']['last'] = \
  464. host_url + blueprints.url_prefix + '?page=' + last_pagination.__str__() + '&page_size=' + \
  465. page_size.__str__() + other_str
  466. return ret
  467. except ji.PreviewingError, e:
  468. return json.loads(e.message)
  469. @Utils.dumps2response
  470. def r_content_search():
  471. page = str(request.args.get('page', 1))
  472. page_size = str(request.args.get('page_size', 50))
  473. args_rules = [
  474. Rules.PAGE.value,
  475. Rules.PAGE_SIZE.value
  476. ]
  477. try:
  478. ji.Check.previewing(args_rules, {'page': page, 'page_size': page_size})
  479. except ji.PreviewingError, e:
  480. return json.loads(e.message)
  481. page = int(page)
  482. page_size = int(page_size)
  483. # 把page和page_size换算成offset和limit
  484. offset = (page - 1) * page_size
  485. # offset, limit将覆盖page及page_size的影响
  486. offset = str(request.args.get('offset', offset))
  487. limit = str(request.args.get('limit', page_size))
  488. order_by = request.args.get('order_by', 'id')
  489. order = request.args.get('order', 'asc')
  490. keyword = request.args.get('keyword', '')
  491. args_rules = [
  492. Rules.OFFSET.value,
  493. Rules.LIMIT.value,
  494. Rules.ORDER_BY.value,
  495. Rules.ORDER.value,
  496. Rules.KEYWORD.value
  497. ]
  498. try:
  499. ji.Check.previewing(args_rules, {'offset': offset, 'limit': limit, 'order_by': order_by, 'order': order,
  500. 'keyword': keyword})
  501. offset = int(offset)
  502. limit = int(limit)
  503. ret = dict()
  504. ret['state'] = ji.Common.exchange_state(20000)
  505. ret['data'] = list()
  506. ret['paging'] = {'total': 0, 'offset': offset, 'limit': limit, 'page': page, 'page_size': page_size}
  507. ret['data'], ret['paging']['total'] = Guest.content_search(offset=offset, limit=limit, order_by=order_by,
  508. order=order, keyword=keyword)
  509. host_url = request.host_url.rstrip('/')
  510. other_str = '&keyword=' + keyword + '&order=' + order + '&order_by=' + order_by
  511. last_pagination = (ret['paging']['total'] + page_size - 1) / page_size
  512. if page <= 1:
  513. ret['paging']['prev'] = host_url + blueprints.url_prefix + '/_search?page=1&page_size=' + \
  514. page_size.__str__() + other_str
  515. else:
  516. ret['paging']['prev'] = host_url + blueprints.url_prefix + '/_search?page=' + str(page-1) + \
  517. '&page_size=' + page_size.__str__() + other_str
  518. if page >= last_pagination:
  519. ret['paging']['next'] = host_url + blueprints.url_prefix + '/_search?page=' + last_pagination.__str__() + \
  520. '&page_size=' + page_size.__str__() + other_str
  521. else:
  522. ret['paging']['next'] = host_url + blueprints.url_prefix + '/_search?page=' + str(page+1) + \
  523. '&page_size=' + page_size.__str__() + other_str
  524. ret['paging']['first'] = host_url + blueprints.url_prefix + '/_search?page=1&page_size=' + \
  525. page_size.__str__() + other_str
  526. ret['paging']['last'] = \
  527. host_url + blueprints.url_prefix + '/_search?page=' + last_pagination.__str__() + '&page_size=' + \
  528. page_size.__str__() + other_str
  529. return ret
  530. except ji.PreviewingError, e:
  531. return json.loads(e.message)
  532. @Utils.dumps2response
  533. def r_update(uuid):
  534. args_rules = [
  535. Rules.UUID.value
  536. ]
  537. if 'remark' in request.json:
  538. args_rules.append(
  539. Rules.REMARK.value,
  540. )
  541. if args_rules.__len__() < 2:
  542. ret = dict()
  543. ret['state'] = ji.Common.exchange_state(20000)
  544. return ret
  545. request.json['uuid'] = uuid
  546. try:
  547. ji.Check.previewing(args_rules, request.json)
  548. guest = Guest()
  549. guest.uuid = uuid
  550. guest.get_by('uuid')
  551. guest.remark = request.json.get('remark', guest.name)
  552. guest.update()
  553. guest.get()
  554. ret = dict()
  555. ret['state'] = ji.Common.exchange_state(20000)
  556. ret['data'] = guest.__dict__
  557. return ret
  558. except ji.PreviewingError, e:
  559. return json.loads(e.message)