Explorar el Código

将 Guest 的系统镜像合并到单独的磁盘镜像目录中。即不再为 Guest 的系统镜像单独分配目录

James Iter hace 9 años
padre
commit
b767a39a5a
Se han modificado 5 ficheros con 69 adiciones y 46 borrados
  1. 1 0
      README.md
  2. 17 3
      models/event_processor.py
  3. 6 7
      models/guest_xml.py
  4. 11 10
      tests/test_guest.py
  5. 34 26
      views/guest.py

+ 1 - 0
README.md

@@ -50,6 +50,7 @@
 >* 用户管理功能
 >* 参照gitlab,打包出 CentOS yum 一语安装仓库
 >* 加入移动端的支持;
+>* 支持快照
 
 
 ## 安装

+ 17 - 3
models/event_processor.py

@@ -47,9 +47,19 @@ class EventProcessor(object):
         action = cls.message['message']['action']
         uuid = cls.message['message']['uuid']
         state = cls.message['type']
+        data = cls.message['message']['data']
 
-        if action == 'create_vm':
-            if state != ResponseState.success.value:
+        if action == 'create_guest':
+            if state == ResponseState.success.value:
+                cls.disk.uuid = uuid
+                cls.disk.get_by('uuid')
+                cls.disk.guest_uuid = uuid
+                cls.disk.state = DiskState.mounted.value
+                # disk_info['virtual-size'] 的单位为Byte,需要除以 1024 的 3 次方,换算成单位为 GB 的值
+                cls.disk.size = data['disk_info']['virtual-size'] / (1024 ** 3)
+                cls.disk.update()
+
+            else:
                 cls.guest.uuid = uuid
                 cls.guest.get_by('uuid')
                 cls.guest.status = GuestState.dirty.value
@@ -58,12 +68,16 @@ class EventProcessor(object):
         elif action == 'migrate':
             pass
 
-        elif action == 'delete':
+        elif action == 'delete_guest':
             if state == ResponseState.success.value:
                 cls.guest.uuid = uuid
                 cls.guest.get_by('uuid')
                 cls.guest.delete()
 
+                cls.disk.uuid = uuid
+                cls.disk.get_by('uuid')
+                cls.disk.delete()
+
         elif action == 'create_disk':
             cls.disk.uuid = uuid
             cls.disk.get_by('uuid')

+ 6 - 7
models/guest_xml.py

@@ -2,7 +2,7 @@
 # -*- coding: utf-8 -*-
 
 
-from models import Config
+from models import Config, Disk
 from models import Guest
 
 
@@ -55,7 +55,7 @@ class GuestXML(object):
 
     def __init__(self, guest=None, disk=None, config=None):
         assert isinstance(guest, Guest)
-        assert isinstance(disk, dict)
+        assert isinstance(disk, Disk)
         assert isinstance(config, Config)
 
         self.guest = guest
@@ -131,14 +131,13 @@ class GuestXML(object):
 
         return """
                 <disk type='network' device='disk'>
-                    <driver name='qemu' type='qcow2' cache='none'/>
-                    <source protocol='gluster' name='{0}/VMs/{1}/{2}.{3}'>
+                    <driver name='qemu' type='{0}' cache='none'/>
+                    <source protocol='gluster' name='{1}/{2}'>
                         <host name='127.0.0.1' port='24007'/>
                     </source>
-                    <target dev='{4}' bus='virtio'/>
+                    <target dev='{3}' bus='virtio'/>
                 </disk>
-        """.format(self.config.glusterfs_volume, self.guest.name, self.disk['uuid'], self.disk['format'],
-                   dev_table[self.disk['sequence']])
+        """.format(self.disk.format, self.config.glusterfs_volume, self.disk.path, dev_table[self.disk.sequence])
 
     def get_graphics(self):
         return """

+ 11 - 10
tests/test_guest.py

@@ -136,16 +136,17 @@ class TestGuest(unittest.TestCase):
     #     print json.dumps(j_r, ensure_ascii=False)
     #     self.assertEqual('200', j_r['state']['code'])
     #
-    # # 删除Guest
-    # # @unittest.skip('skip delete guest')
-    # def test_41_delete(self):
-    #     url = TestGuest.base_url + '/guests/' + TestGuest.uuid
-    #     headers = {'content-type': 'application/json'}
-    #     r = requests.delete(url, headers=headers)
-    #     j_r = json.loads(r.content)
-    #     print json.dumps(j_r, ensure_ascii=False)
-    #     self.assertEqual('200', j_r['state']['code'])
-    #
+    # 删除Guest
+    # @unittest.skip('skip delete guest')
+    def test_41_delete(self):
+        TestGuest.uuid = '8ed82dca-e956-469b-a6c1-c16a89763ab1'
+        url = TestGuest.base_url + '/guests/' + TestGuest.uuid
+        headers = {'content-type': 'application/json'}
+        r = requests.delete(url, 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_42_delete_disk(self):
     #     url = TestGuest.base_url + '/disk/' + TestGuest.disk_uuid
     #     headers = {'content-type': 'application/json'}

+ 34 - 26
views/guest.py

@@ -113,9 +113,17 @@ def r_create():
 
             guest.vnc_password = ji.Common.generate_random_code(length=16)
 
-            guest_disk = {'uuid': uuid4().__str__(), 'size': -1, 'format': 'qcow2', 'sequence': 0}
-
-            guest_xml = GuestXML(guest=guest, disk=guest_disk, config=config)
+            disk = Disk()
+            disk.uuid = guest.uuid
+            disk.label = guest.name + '_SystemImage'
+            disk.format = 'qcow2'
+            disk.sequence = 0
+            disk.size = 0
+            disk.path = config.storage_path + '/' + disk.uuid + '.' + disk.format
+            disk.guest_uuid = ''
+            disk.create()
+
+            guest_xml = GuestXML(guest=guest, disk=disk, config=config)
             guest.xml = guest_xml.get_domain()
             guest.create()
 
@@ -130,12 +138,12 @@ def r_create():
                     replace('{DNS2}', config.dns2)
 
             create_vm_msg = {
-                'action': 'create_vm',
+                'action': 'create_guest',
                 'uuid': guest.uuid,
                 'name': guest.name,
                 'glusterfs_volume': config.glusterfs_volume,
-                'template_path': 'template_pool/' + os_template.name,
-                'guest_disk': guest_disk,
+                'template_path': os_template.path,
+                'disk': disk.__dict__,
                 'writes': _os_init_writes,
                 'password': guest.password,
                 'xml': guest_xml.get_domain()
@@ -357,7 +365,7 @@ def r_delete(uuids):
 
         # 执行删除操作
         for uuid in uuids.split(','):
-            message = {'action': 'delete', 'uuid': uuid}
+            message = {'action': 'delete_guest', 'uuid': uuid}
             Guest.emit_instruction(message=json.dumps(message))
 
         ret = dict()
@@ -383,15 +391,15 @@ def r_attach_disk(uuid, disk_uuid):
         guest.uuid = uuid
         guest.get_by('uuid')
 
-        guest_disk = Disk()
-        guest_disk.uuid = disk_uuid
-        guest_disk.get_by('uuid')
+        disk = Disk()
+        disk.uuid = disk_uuid
+        disk.get_by('uuid')
 
         ret = dict()
         ret['state'] = ji.Common.exchange_state(20000)
 
         # 判断欲挂载的磁盘是否空闲
-        if guest_disk.guest_uuid.__len__() > 0:
+        if disk.guest_uuid.__len__() > 0:
             ret['state'] = ji.Common.exchange_state(41258)
             return ret
 
@@ -401,9 +409,9 @@ def r_attach_disk(uuid, disk_uuid):
             return ret
 
         # 取出该 guest 已挂载的磁盘,来做出决定,确定该磁盘的序列
-        guest_disk.guest_uuid = guest.uuid
-        disks, count = guest_disk.get_by_filter(filter_str='guest_uuid:in:' + guest.uuid)
-        guest_disk.sequence = count + 1
+        disk.guest_uuid = guest.uuid
+        disks, count = disk.get_by_filter(filter_str='guest_uuid:in:' + guest.uuid)
+        disk.sequence = count + 1
 
         config = Config()
         config.id = 1
@@ -417,11 +425,11 @@ def r_attach_disk(uuid, disk_uuid):
                 </source>
                 <target dev='{3}' bus='virtio'/>
             </disk>
-        """.format(config.glusterfs_volume, guest_disk.uuid, guest_disk.format,
-                   dev_table[guest_disk.sequence])
+        """.format(config.glusterfs_volume, disk.uuid, disk.format,
+                   dev_table[disk.sequence])
 
         message = {'action': 'attach_disk', 'uuid': uuid, 'xml': xml,
-                   'passback_parameters': {'disk_uuid': guest_disk.uuid, 'sequence': guest_disk.sequence}}
+                   'passback_parameters': {'disk_uuid': disk.uuid, 'sequence': disk.sequence}}
         Guest.emit_instruction(message=json.dumps(message))
 
         return ret
@@ -440,21 +448,21 @@ def r_detach_disk(disk_uuid):
     try:
         ji.Check.previewing(args_rules, {'disk_uuid': disk_uuid})
 
-        guest_disk = Disk()
-        guest_disk.uuid = disk_uuid
-        guest_disk.get_by('uuid')
+        disk = Disk()
+        disk.uuid = disk_uuid
+        disk.get_by('uuid')
 
         ret = dict()
         ret['state'] = ji.Common.exchange_state(20000)
 
-        if guest_disk.state != DiskState.mounted.value or guest_disk.sequence == 0:
+        if disk.state != DiskState.mounted.value or disk.sequence == 0:
             # 表示未被任何实例使用,已被分离
             # 序列为 0 的表示实例系统盘,系统盘不可以被分离
             # TODO: 系统盘单独范围其它状态
             return ret
 
         guest = Guest()
-        guest.uuid = guest_disk.guest_uuid
+        guest.uuid = disk.guest_uuid
         guest.get_by('uuid')
 
         # 判断 Guest 是否处于可用状态
@@ -474,11 +482,11 @@ def r_detach_disk(disk_uuid):
                 </source>
                 <target dev='{3}' bus='virtio'/>
             </disk>
-        """.format(config.glusterfs_volume, guest_disk.uuid, guest_disk.format,
-                   dev_table[guest_disk.sequence])
+        """.format(config.glusterfs_volume, disk.uuid, disk.format,
+                   dev_table[disk.sequence])
 
-        message = {'action': 'detach_disk', 'uuid': guest_disk.guest_uuid, 'xml': xml,
-                   'passback_parameters': {'disk_uuid': guest_disk.uuid}}
+        message = {'action': 'detach_disk', 'uuid': disk.guest_uuid, 'xml': xml,
+                   'passback_parameters': {'disk_uuid': disk.uuid}}
         Guest.emit_instruction(message=json.dumps(message))
 
         return ret