Explorar o código

guest_disk改为disk,disk新增path属性

James Iter %!s(int64=9) %!d(string=hai) anos
pai
achega
beb4236635

+ 6 - 0
docs/disk.md

@@ -97,6 +97,7 @@ GET https://$domain
         "sequence": -1,
         "format": "qcow2",
         "label": "Hello-disk",
+        "path": "Images/fff8aead-3206-4820-8c98-146178a91cce.qcow2",
         "state": 1,
         "id": 42,
         "size": 200
@@ -109,6 +110,7 @@ GET https://$domain
 | id         |  Y  |  Long  | 磁盘 ID                                               |
 | uuid       |  Y  | String | 磁盘 UUID                                             |
 | label      |  Y  | String | 磁盘标注信息                                           |
+| path       |  Y  | String | 磁盘存放路径                                           |
 | size       |  Y  |  Long  | 磁盘大小                                               |
 | sequence   |  Y  |  Long  | 磁盘在某个 Guest 实例中的序列                            |
 | format     |  Y  | String | 磁盘镜像格式,默认 qcow2                                |
@@ -148,6 +150,7 @@ Body:
         "format": "qcow2",
         "sequence": -1,
         "label": "Hello-disk",
+        "path": "Images/fff8aead-3206-4820-8c98-146178a91cce.qcow2",
         "state": 0,
         "id": 42,
         "size": 10
@@ -193,6 +196,7 @@ GET https://$domain
         "sequence": -1,
         "format": "qcow2",
         "label": "82QUZJGJ",
+        "path": "Images/5844e2cb-56c5-4b02-98b5-ee606bfbe3b3.qcow2",
         "state": 0,
         "id": 22,
         "size": 10
@@ -204,6 +208,7 @@ GET https://$domain
         "sequence": -1,
         "format": "qcow2",
         "label": "qhDCp3E8",
+        "path": "Images/fff8aead-3206-4820-8c98-146178a91cce.qcow2",
         "state": 0,
         "id": 42,
         "size": 10
@@ -269,6 +274,7 @@ GET https://$domain
         "sequence": -1,
         "format": "qcow2",
         "label": "Hello-disk",
+        "path": "Images/fff8aead-3206-4820-8c98-146178a91cce.qcow2",
         "state": 1,
         "id": 42,
         "size": 200

+ 5 - 3
docs/todo.md

@@ -9,9 +9,11 @@
 - [ ] os_init_write 的更新方法里,是否需要支持 os_init_id 参数
 - [ ] 增加模板镜像上传功能
 - [ ] 抽象出视图层的父类,尤其是 get、get_list、delete 这些方法基本相同
-- [ ] guest_disk 表中加入 path 字段,具体磁盘位置由 path 指明
-- [ ] guest 的系统磁盘,也需记录到 guest_disk 表中
+- [x] guest_disk 表中加入 path 字段,具体磁盘位置由 path 指明
+- [x] guest 的系统磁盘,也需记录到 guest_disk 表中
 - [x] 将 Guest 的系统镜像合并到单独的磁盘镜像目录中。即不再为 Guest 的系统镜像单独分配目录
-- [ ] os_template 表中 name 改为 path 字段。又 path 指明完整路径
+- [x] os_template 表中 name 改为 path 字段。用 path 指明完整路径
 - [ ] 统计活着的宿主机,并提供获取列表的接口,供迁移时选择
 - [ ] 加入被动更新 Guest xml 的功能,由宿主机主动推送。具体时机待定
+- [x] 统一 guest_disk 称谓为 disk
+- [ ] 分离出 API 与 views 出入口,涉及 add_rule 与 route_table

+ 6 - 4
misc/init.sql

@@ -32,10 +32,11 @@ ALTER TABLE guest ADD INDEX (on_host);
 ALTER TABLE guest ADD INDEX (ip);
 
 
-CREATE TABLE IF NOT EXISTS guest_disk(
+CREATE TABLE IF NOT EXISTS disk(
     id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
     uuid CHAR(36) NOT NULL,
     label VARCHAR(255) NOT NULL,
+    path VARCHAR(255) NOT NULL,
     size INT UNSIGNED NOT NULL,
     sequence TINYINT NOT NULL,
     format CHAR(16) NOT NULL DEFAULT 'qcow2',
@@ -46,14 +47,14 @@ CREATE TABLE IF NOT EXISTS guest_disk(
     ENGINE=InnoDB
     DEFAULT CHARSET=utf8;
 
-ALTER TABLE guest_disk ADD INDEX (size);
-ALTER TABLE guest_disk ADD INDEX (guest_uuid);
+ALTER TABLE disk ADD INDEX (size);
+ALTER TABLE disk ADD INDEX (guest_uuid);
 
 
 CREATE TABLE IF NOT EXISTS os_template(
     id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
     label VARCHAR(255) NOT NULL,
-    name VARCHAR(255) NOT NULL,
+    path VARCHAR(255) NOT NULL,
     active BOOLEAN NOT NULL DEFAULT TRUE,
     os_init_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
     PRIMARY KEY (id))
@@ -83,6 +84,7 @@ CREATE TABLE IF NOT EXISTS os_init_write(
 CREATE TABLE IF NOT EXISTS config(
     id BIGINT UNSIGNED NOT NULL DEFAULT 1,
     glusterfs_volume VARCHAR(255) NOT NULL,
+    storage_path VARCHAR(255) NOT NULL,
     vm_network VARCHAR(255) NOT NULL,
     vm_manage_network VARCHAR(255) NOT NULL,
     start_ip CHAR(15) NOT NULL,

+ 2 - 2
models/__init__.py

@@ -32,7 +32,7 @@ from config import (
 )
 
 from guest import (
-    Guest, GuestDisk
+    Guest, Disk
 )
 
 from guest_xml import (
@@ -72,7 +72,7 @@ __copyright__ = '(c) 2017 by James Iter.'
 
 __all__ = [
     'Rules', 'Utils', 'Init', 'Database', 'FilterFieldType', 'Filter', 'EmitKind', 'GuestState', 'DiskState',
-    'LogLevel', 'ORM', 'Config', 'Guest', 'GuestDisk', 'OSInit', 'OSInitWrite', 'OSTemplate', 'GuestXML', 'Log',
+    'LogLevel', 'ORM', 'Config', 'Guest', 'Disk', 'OSInit', 'OSInitWrite', 'OSTemplate', 'GuestXML', 'Log',
     'EventProcessor', 'ResponseState'
 ]
 

+ 1 - 0
models/config.py

@@ -27,6 +27,7 @@ class Config(ORM):
         # 配置条目的 id 只会是 1
         self.id = 1
         self.glusterfs_volume = ''
+        self.storage_path = ''
         self.vm_network = ''
         self.vm_manage_network = ''
         self.start_ip = ''

+ 2 - 2
models/event_processor.py

@@ -7,7 +7,7 @@ import time
 
 from models import Database as db
 from models import Guest
-from models import GuestDisk
+from models import Disk
 from models import Log
 from models import Utils
 from models import EmitKind
@@ -25,7 +25,7 @@ class EventProcessor(object):
     message = None
     log = Log()
     guest = Guest()
-    disk = GuestDisk()
+    disk = Disk()
 
     @classmethod
     def log_processor(cls):

+ 4 - 3
models/guest.py

@@ -64,16 +64,17 @@ class Guest(ORM):
         db.r.publish(app.config['instruction_channel'], message=message)
 
 
-class GuestDisk(ORM):
+class Disk(ORM):
 
-    _table_name = 'guest_disk'
+    _table_name = 'disk'
     _primary_key = 'id'
 
     def __init__(self):
-        super(GuestDisk, self).__init__()
+        super(Disk, self).__init__()
         self.id = 0
         self.uuid = None
         self.label = None
+        self.path = None
         self.size = None
         self.sequence = None
         self.state = DiskState.pending.value

+ 4 - 3
models/os_template.py

@@ -21,14 +21,15 @@ class OSTemplate(ORM):
         super(OSTemplate, self).__init__()
         self.id = 0
         self.label = None
-        self.name = None
+        self.path = None
         self.active = None
         self.os_init_id = None
 
     @staticmethod
     def get_filter_keywords():
         return {
-            'name': FilterFieldType.STR.value,
+            'label': FilterFieldType.STR.value,
+            'path': FilterFieldType.STR.value,
             'active': FilterFieldType.BOOL.value,
             'os_init_id': FilterFieldType.INT.value
         }
@@ -39,5 +40,5 @@ class OSTemplate(ORM):
 
     @staticmethod
     def get_allow_content_search_keywords():
-        return ['name']
+        return ['label', 'path']
 

+ 2 - 0
models/rules.py

@@ -27,6 +27,7 @@ class Rules(Enum):
 
     CONFIG_ID = (int, 'id')
     GLUSTERFS_VOLUME = (basestring, 'glusterfs_volume')
+    STORAGE_PATH = (basestring, 'storage_path')
     VM_NETWORK = (basestring, 'vm_network')
     VM_MANAGE_NETWORK = (basestring, 'vm_manage_network')
     START_IP = (IP, 'start_ip')
@@ -46,6 +47,7 @@ class Rules(Enum):
     OS_TEMPLATE_ID = (int, 'os_template_id')
     QUANTITY = (int, 'quantity')
     NAME = (basestring, 'name')
+    PATH = (basestring, 'path')
     PASSWORD = (basestring, 'password')
     LEASE_TERM = (int, 'lease_term')
     DESTINATION_HOST = (basestring, 'destination_host', (5, 64))

+ 17 - 18
tests/test_guest.py

@@ -27,23 +27,23 @@ class TestGuest(unittest.TestCase):
 
     # 创建Guest
     # @unittest.skip('skip create guest')
-    def test_11_create(self):
-        payload = {
-            "cpu": 4,
-            "memory": 4,
-            "os_template_id": 2,
-            "quantity": 3,
-            "name": "",
-            "password": "pswd.com",
-            "lease_term": 100
-        }
-
-        url = TestGuest.base_url + '/guest'
-        headers = {'content-type': 'application/json'}
-        r = requests.post(url, data=json.dumps(payload), headers=headers)
-        j_r = json.loads(r.content)
-        print json.dumps(j_r, ensure_ascii=False)
-        self.assertEqual('200', j_r['state']['code'])
+    # def test_11_create(self):
+    #     payload = {
+    #         "cpu": 4,
+    #         "memory": 4,
+    #         "os_template_id": 1,
+    #         "quantity": 1,
+    #         "name": "",
+    #         "password": "pswd.com",
+    #         "lease_term": 100
+    #     }
+    #
+    #     url = TestGuest.base_url + '/guest'
+    #     headers = {'content-type': 'application/json'}
+    #     r = requests.post(url, data=json.dumps(payload), headers=headers)
+    #     j_r = json.loads(r.content)
+    #     print json.dumps(j_r, ensure_ascii=False)
+    #     self.assertEqual('200', j_r['state']['code'])
 
     # 获取 Guest 列表
     # def test_12_get_list(self):
@@ -210,7 +210,6 @@ class TestGuest(unittest.TestCase):
     #     print json.dumps(j_r, ensure_ascii=False)
 
     # def test_58_attach_disk(self):
-    #     TestGuest.disk_uuid = '234670cb-3ce4-4ef9-ba23-12bed636184c'
     #     url = TestGuest.base_url + '/guest/_attach_disk/' + TestGuest.uuid + '/' + TestGuest.disk_uuid
     #     headers = {'content-type': 'application/json'}
     #     r = requests.put(url, headers=headers)

+ 8 - 0
views/config.py

@@ -32,6 +32,7 @@ def r_create():
 
     args_rules = [
         Rules.GLUSTERFS_VOLUME.value,
+        Rules.STORAGE_PATH.value,
         Rules.VM_NETWORK.value,
         Rules.VM_MANAGE_NETWORK.value,
         Rules.START_IP.value,
@@ -47,6 +48,7 @@ def r_create():
 
     config.id = 1
     config.glusterfs_volume = request.json.get('glusterfs_volume')
+    config.storage_path = request.json.get('storage_path')
     config.vm_network = request.json.get('vm_network')
     config.vm_manage_network = request.json.get('vm_manage_network')
     config.start_ip = request.json.get('start_ip')
@@ -91,6 +93,11 @@ def r_update():
             Rules.GLUSTERFS_VOLUME.value,
         )
 
+    if 'storage_path' in request.json:
+        args_rules.append(
+            Rules.STORAGE_PATH.value,
+        )
+
     if 'vm_network' in request.json:
         args_rules.append(
             Rules.VM_NETWORK.value,
@@ -157,6 +164,7 @@ def r_update():
         config.get()
 
         config.glusterfs_volume = request.json.get('glusterfs_volume', config.glusterfs_volume)
+        config.storage_path = request.json.get('storage_path', config.storage_path)
         config.vm_network = request.json.get('vm_network', config.vm_network)
         config.vm_manage_network = request.json.get('vm_manage_network', config.vm_manage_network)
         config.start_ip = request.json.get('start_ip', config.start_ip)

+ 44 - 47
views/disk.py

@@ -11,7 +11,7 @@ from models import Guest, DiskState
 from models.initialize import app, dev_table
 from models import Database as db
 from models import Config
-from models import GuestDisk
+from models import Disk
 from models import Rules
 from models import Utils
 
@@ -54,26 +54,26 @@ def r_create():
             ret['state'] = ji.Common.exchange_state(41255)
             return ret
 
-        guest_disk = GuestDisk()
-        guest_disk.guest_uuid = ''
-        guest_disk.size = size
-        guest_disk.uuid = uuid4().__str__()
-        guest_disk.label = ji.Common.generate_random_code(length=8)
-        guest_disk.sequence = -1
-        guest_disk.format = 'qcow2'
+        disk = Disk()
+        disk.guest_uuid = ''
+        disk.size = size
+        disk.uuid = uuid4().__str__()
+        disk.label = ji.Common.generate_random_code(length=8)
+        disk.sequence = -1
+        disk.format = 'qcow2'
 
         config = Config()
         config.id = 1
         config.get()
 
-        image_path = '/'.join(['DiskPool', guest_disk.uuid + '.' + guest_disk.format])
+        disk.path = config.storage_path + '/' + disk.uuid + '.' + disk.format
 
         message = {'action': 'create_disk', 'glusterfs_volume': config.glusterfs_volume,
-                   'image_path': image_path, 'size': guest_disk.size, 'uuid': guest_disk.uuid}
+                   'image_path': disk.path, 'size': disk.size, 'uuid': disk.uuid}
 
         db.r.rpush(app.config['downstream_queue'], json.dumps(message, ensure_ascii=False))
 
-        guest_disk.create()
+        disk.create()
 
         return ret
 
@@ -92,36 +92,35 @@ def r_resize(uuid, size):
     try:
         ji.Check.previewing(args_rules, {'uuid': uuid, 'size': size})
 
-        guest_disk = GuestDisk()
-        guest_disk.uuid = uuid
-        guest_disk.get_by('uuid')
+        disk = Disk()
+        disk.uuid = uuid
+        disk.get_by('uuid')
 
         used = True
 
-        if guest_disk.guest_uuid.__len__() != 36:
+        if disk.guest_uuid.__len__() != 36:
             used = False
 
         ret = dict()
         ret['state'] = ji.Common.exchange_state(20000)
 
-        if guest_disk.size >= size:
+        if disk.size >= size:
             ret['state'] = ji.Common.exchange_state(41257)
             return ret
 
-        message = {'action': 'resize_disk', 'size': size, 'guest_uuid': guest_disk.guest_uuid,
-                   'disk_uuid': guest_disk.uuid, 'passback_parameters': {'size': size}}
+        message = {'action': 'resize_disk', 'size': size, 'guest_uuid': disk.guest_uuid,
+                   'disk_uuid': disk.uuid, 'passback_parameters': {'size': size}}
 
         if used:
-            message['device_node'] = dev_table[guest_disk.sequence]
+            message['device_node'] = dev_table[disk.sequence]
             Guest.emit_instruction(message=json.dumps(message))
         else:
             config = Config()
             config.id = 1
             config.get()
 
-            image_path = '/'.join(['DiskPool', guest_disk.uuid + '.' + guest_disk.format])
             message['glusterfs_volume'] = config.glusterfs_volume
-            message['image_path'] = image_path
+            message['image_path'] = disk.path
 
             db.r.rpush(app.config['downstream_queue'], json.dumps(message, ensure_ascii=False))
 
@@ -144,14 +143,14 @@ def r_delete(uuids):
         ret = dict()
         ret['state'] = ji.Common.exchange_state(20000)
 
-        guest_disk = GuestDisk()
+        disk = Disk()
 
         # 检测所指定的 UUDIs 磁盘都存在
         for uuid in uuids.split(','):
-            guest_disk.uuid = uuid
-            guest_disk.get_by('uuid')
+            disk.uuid = uuid
+            disk.get_by('uuid')
 
-            if guest_disk.state != DiskState.idle.value:
+            if disk.state != DiskState.idle.value:
                 ret['state'] = ji.Common.exchange_state(41256)
                 return ret
 
@@ -161,13 +160,11 @@ def r_delete(uuids):
 
         # 执行删除操作
         for uuid in uuids.split(','):
-            guest_disk.uuid = uuid
-            guest_disk.get_by('uuid')
+            disk.uuid = uuid
+            disk.get_by('uuid')
 
-            image_path = '/'.join(['DiskPool', guest_disk.uuid + '.' + guest_disk.format])
-
-            message = {'action': 'delete_disk', 'uuid': guest_disk.uuid,
-                       'glusterfs_volume': config.glusterfs_volume, 'image_path': image_path}
+            message = {'action': 'delete_disk', 'uuid': disk.uuid,
+                       'glusterfs_volume': config.glusterfs_volume, 'image_path': disk.path}
             db.r.rpush(app.config['downstream_queue'], json.dumps(message, ensure_ascii=False))
 
         return ret
@@ -178,19 +175,19 @@ def r_delete(uuids):
 
 @Utils.dumps2response
 def r_get(uuid):
-    guest_disk = GuestDisk()
+    disk = Disk()
 
     args_rules = [
         Rules.UUID.value
     ]
-    guest_disk.uuid = uuid
+    disk.uuid = uuid
 
     try:
-        ji.Check.previewing(args_rules, guest_disk.__dict__)
-        guest_disk.get_by('uuid')
+        ji.Check.previewing(args_rules, disk.__dict__)
+        disk.get_by('uuid')
         ret = dict()
         ret['state'] = ji.Common.exchange_state(20000)
-        ret['data'] = guest_disk.__dict__
+        ret['data'] = disk.__dict__
         return ret
     except ji.PreviewingError, e:
         return json.loads(e.message)
@@ -241,8 +238,8 @@ def r_get_by_filter():
         ret['paging'] = {'total': 0, 'offset': offset, 'limit': limit, 'page': page, 'page_size': page_size,
                          'next': '', 'prev': '', 'first': '', 'last': ''}
 
-        ret['data'], ret['paging']['total'] = GuestDisk.get_by_filter(offset=offset, limit=limit, order_by=order_by,
-                                                                      order=order, filter_str=filter_str)
+        ret['data'], ret['paging']['total'] = Disk.get_by_filter(offset=offset, limit=limit, order_by=order_by,
+                                                                 order=order, filter_str=filter_str)
 
         host_url = request.host_url.rstrip('/')
         other_str = '&filter=' + filter_str + '&order=' + order + '&order_by=' + order_by
@@ -319,8 +316,8 @@ def r_content_search():
         ret['data'] = list()
         ret['paging'] = {'total': 0, 'offset': offset, 'limit': limit, 'page': page, 'page_size': page_size}
 
-        ret['data'], ret['paging']['total'] = GuestDisk.content_search(offset=offset, limit=limit, order_by=order_by,
-                                                                       order=order, keyword=keyword)
+        ret['data'], ret['paging']['total'] = Disk.content_search(offset=offset, limit=limit, order_by=order_by,
+                                                                  order=order, keyword=keyword)
 
         host_url = request.host_url.rstrip('/')
         other_str = '&keyword=' + keyword + '&order=' + order + '&order_by=' + order_by
@@ -372,18 +369,18 @@ def r_update(uuid):
 
     try:
         ji.Check.previewing(args_rules, request.json)
-        guest_disk = GuestDisk()
-        guest_disk.uuid = uuid
-        guest_disk.get_by('uuid')
+        disk = Disk()
+        disk.uuid = uuid
+        disk.get_by('uuid')
 
-        guest_disk.label = request.json.get('label', guest_disk.label)
+        disk.label = request.json.get('label', disk.label)
 
-        guest_disk.update()
-        guest_disk.get()
+        disk.update()
+        disk.get()
 
         ret = dict()
         ret['state'] = ji.Common.exchange_state(20000)
-        ret['data'] = guest_disk.__dict__
+        ret['data'] = disk.__dict__
         return ret
     except ji.PreviewingError, e:
         return json.loads(e.message)

+ 3 - 3
views/guest.py

@@ -14,7 +14,7 @@ from models import OSInitWrite
 from models.initialize import app, dev_table
 from models import Database as db
 from models import Config
-from models import GuestDisk
+from models import Disk
 from models import Rules
 from models import Utils
 from models import Guest
@@ -383,7 +383,7 @@ def r_attach_disk(uuid, disk_uuid):
         guest.uuid = uuid
         guest.get_by('uuid')
 
-        guest_disk = GuestDisk()
+        guest_disk = Disk()
         guest_disk.uuid = disk_uuid
         guest_disk.get_by('uuid')
 
@@ -440,7 +440,7 @@ def r_detach_disk(disk_uuid):
     try:
         ji.Check.previewing(args_rules, {'disk_uuid': disk_uuid})
 
-        guest_disk = GuestDisk()
+        guest_disk = Disk()
         guest_disk.uuid = disk_uuid
         guest_disk.get_by('uuid')
 

+ 8 - 8
views/os_template.py

@@ -38,13 +38,13 @@ def r_create():
 
     args_rules = [
         Rules.LABEL.value,
-        Rules.NAME.value,
+        Rules.PATH.value,
         Rules.ACTIVE.value,
         Rules.OS_INIT_ID_EXT.value
     ]
 
     os_template.label = request.json.get('label')
-    os_template.name = request.json.get('name')
+    os_template.path = request.json.get('path')
     os_template.active = request.json.get('active')
     os_template.os_init_id = request.json.get('os_init_id', 0)
 
@@ -54,13 +54,13 @@ def r_create():
         ret = dict()
         ret['state'] = ji.Common.exchange_state(20000)
 
-        if os_template.exist_by('name'):
+        if os_template.exist_by('path'):
             ret['state'] = ji.Common.exchange_state(40901)
-            ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], ': ', os_template.name])
+            ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], ': ', os_template.path])
             return ret
 
         os_template.create()
-        os_template.get_by('name')
+        os_template.get_by('path')
         ret['data'] = os_template.__dict__
         return ret
     except ji.PreviewingError, e:
@@ -81,9 +81,9 @@ def r_update(_id):
             Rules.LABEL.value,
         )
 
-    if 'name' in request.json:
+    if 'path' in request.json:
         args_rules.append(
-            Rules.NAME.value,
+            Rules.PATH.value,
         )
 
     if 'active' in request.json:
@@ -109,7 +109,7 @@ def r_update(_id):
 
         os_template.get()
         os_template.label = request.json.get('label', os_template.label)
-        os_template.name = request.json.get('name', os_template.name)
+        os_template.path = request.json.get('path', os_template.path)
         os_template.active = request.json.get('active', os_template.active)
         os_template.os_init_id = request.json.get('os_init_id', os_template.os_init_id)