[PATCH] Abstract vm element class for live update

From: Royce Lv <lvroyce@linux.vnet.ibm.com> Abstract vm element class for live update to be compatible with different element type and their various libvirt calls. Royce Lv (1): Abstract vm element updater for common usage src/kimchi/model.py | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 2 deletions(-) -- 1.8.1.2

From: Royce Lv <lvroyce@linux.vnet.ibm.com> Different kinds of vm elements will be added through different libvirt apis, this patch abstract a framework for this update. Wrap correspondent libvirt api in vm element class, and format their own libvirt call parameters in each class. Signed-off-by: Royce Lv <lvroyce@linux.vnet.ibm.com> --- src/kimchi/model.py | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/src/kimchi/model.py b/src/kimchi/model.py index 2c6d3a1..0f82b61 100644 --- a/src/kimchi/model.py +++ b/src/kimchi/model.py @@ -78,7 +78,6 @@ ISO_POOL_NAME = u'kimchi_isos' GUESTS_STATS_INTERVAL = 5 HOST_STATS_INTERVAL = 1 VM_STATIC_UPDATE_PARAMS = {'name': './name'} -VM_LIVE_UPDATE_PARAMS = {} STORAGE_SOURCES = {'netfs': {'addr': '/pool/source/host/@name', 'path': '/pool/source/dir/@path'}} @@ -490,7 +489,13 @@ class Model(object): return dom def _live_vm_update(self, dom, params): - pass + try: + for key, val in params.items(): + element = VMElementDef.create(key, val, dom) + element.add_to_vm() + except libvirt.libvirtError as e: + raise OperationFailed("Cannot apply change on vm: %s", + e.get_error_message()) def vm_update(self, name, params): dom = self._get_vm(name) @@ -1510,6 +1515,62 @@ class LibvirtVMScreenshot(VMScreenshot): os.close(fd) +class VMElementDef(object): + @classmethod + def create(cls, elem_type, elemArgs, dom): + for klass in cls.__subclasses__(): + if elem_type == klass.elemType: + return klass(elemArgs, dom) + raise OperationFailed('Unsupported vm element type: %s' % elemArgs['type']) + + def __init__(self, elemArgs, dom): + self.dom = dom + self.elemArgs = elemArgs + + def add_to_vm(self): + """Live update domain with correspondant libvirt API. + This should be paired with cancel() operation to cancel failed update.""" + pass + + def delete_from_vm(self): + """Revert operation of live update vm.""" + pass + + @property + def _update_param(self): + ''' Subclasses have to override this method to actually generate the + update param.''' + raise OperationFailed('Update param generater is not implemented: %s' % self) + + +class VMDiskDef(VMElementDef): + elemType = 'disk' + + def __init__(self, elemArgs, dom): + super(VMDiskDef, self).__init__(elemArgs, dom) + + def add_to_vm(self): + self.dom.attachDeviceFlags(xml=self._update_param['xml'], + flags=libvirt.VIR_DOMAIN_AFFECT_CURRENT|libvirt.VIR_DOMAIN_AFFECT_CONFIG) + + def delete_from_vm(self): + self.dom.detachDeviceFlags(xml=self._update_param['xml'], + flags=libvirt.VIR_DOMAIN_AFFECT_CURRENT|libvirt.VIR_DOMAIN_AFFECT_CONFIG) + + @property + def _update_param(self): + self.elemArgs['readonly'] = "<readonly/>" \ + if self.elemArgs['target']['type'] == 'cdrom' else None + xml = """ + <disk type='{source[type]}' device='{target[type]}'> + <source file='{source[path]}'/> + <target dev='{target[name]}' bus='{target[bus]}'/> + {readonly} + </disk> + """.format(**self.elemArgs) + return dict(xml=xml) + + class StoragePoolDef(object): @classmethod def create(cls, poolArgs): -- 1.8.1.2

Am 17-01-2014 12:06, schrieb lvroyce0210@gmail.com:
+ raise OperationFailed('Unsupported vm element type: %s' % elemArgs['type']) This line is longer than 80 characters. Please keep it shorter than that.
+ """Live update domain with correspondant libvirt API. + This should be paired with cancel() operation to cancel failed update.""" This line is longer than 80 characters. Please keep it shorter than that.
+ raise OperationFailed('Update param generater is not implemented: %s' % self) This line is longer than 80 characters. Please keep it shorter than that. + self.dom.attachDeviceFlags(xml=self._update_param['xml'], + flags=libvirt.VIR_DOMAIN_AFFECT_CURRENT|libvirt.VIR_DOMAIN_AFFECT_CONFIG) This line is longer than 80 characters. Please keep it shorter than that. Also, the second line should be aligned to the beginning of the parameter list on the first line (i.e. "flags=" should be right below "xml="). + def delete_from_vm(self): + self.dom.detachDeviceFlags(xml=self._update_param['xml'], + flags=libvirt.VIR_DOMAIN_AFFECT_CURRENT|libvirt.VIR_DOMAIN_AFFECT_CONFIG) This line is longer than 80 characters. Please keep it shorter than that. Also, the second line should be aligned to the beginning of the parameter list on the first line (i.e. "flags=" should be right below "xml=").

On 01/17/2014 12:06 PM, lvroyce0210@gmail.com wrote:
From: Royce Lv <lvroyce@linux.vnet.ibm.com>
Different kinds of vm elements will be added through different libvirt apis, this patch abstract a framework for this update. Wrap correspondent libvirt api in vm element class, and format their own libvirt call parameters in each class.
Signed-off-by: Royce Lv <lvroyce@linux.vnet.ibm.com> --- src/kimchi/model.py | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 2 deletions(-)
diff --git a/src/kimchi/model.py b/src/kimchi/model.py index 2c6d3a1..0f82b61 100644 --- a/src/kimchi/model.py +++ b/src/kimchi/model.py @@ -78,7 +78,6 @@ ISO_POOL_NAME = u'kimchi_isos' GUESTS_STATS_INTERVAL = 5 HOST_STATS_INTERVAL = 1 VM_STATIC_UPDATE_PARAMS = {'name': './name'} -VM_LIVE_UPDATE_PARAMS = {} STORAGE_SOURCES = {'netfs': {'addr': '/pool/source/host/@name', 'path': '/pool/source/dir/@path'}}
@@ -490,7 +489,13 @@ class Model(object): return dom
def _live_vm_update(self, dom, params): - pass + try: + for key, val in params.items(): + element = VMElementDef.create(key, val, dom) + element.add_to_vm() + except libvirt.libvirtError as e: + raise OperationFailed("Cannot apply change on vm: %s", + e.get_error_message())
def vm_update(self, name, params): dom = self._get_vm(name) @@ -1510,6 +1515,62 @@ class LibvirtVMScreenshot(VMScreenshot): os.close(fd)
+class VMElementDef(object):
What about VMDeviceDef()
+ @classmethod + def create(cls, elem_type, elemArgs, dom): + for klass in cls.__subclasses__(): + if elem_type == klass.elemType: + return klass(elemArgs, dom) + raise OperationFailed('Unsupported vm element type: %s' % elemArgs['type']) + + def __init__(self, elemArgs, dom): + self.dom = dom + self.elemArgs = elemArgs + + def add_to_vm(self): + """Live update domain with correspondant libvirt API. + This should be paired with cancel() operation to cancel failed update.""" + pass + + def delete_from_vm(self): + """Revert operation of live update vm.""" + pass + + @property + def _update_param(self): + ''' Subclasses have to override this method to actually generate the + update param.''' + raise OperationFailed('Update param generater is not implemented: %s' % self) + + +class VMDiskDef(VMElementDef): + elemType = 'disk' + + def __init__(self, elemArgs, dom): + super(VMDiskDef, self).__init__(elemArgs, dom) +
+ def add_to_vm(self): + self.dom.attachDeviceFlags(xml=self._update_param['xml'], + flags=libvirt.VIR_DOMAIN_AFFECT_CURRENT|libvirt.VIR_DOMAIN_AFFECT_CONFIG) + + def delete_from_vm(self): + self.dom.detachDeviceFlags(xml=self._update_param['xml'], + flags=libvirt.VIR_DOMAIN_AFFECT_CURRENT|libvirt.VIR_DOMAIN_AFFECT_CONFIG) +
Those functions will be the same for all kind of devices. The difference is on the xml passed to attachDeviceFlags() and detachDeviceFlags() So I suggest to move those function to VMDeviceDef() and create a function get_device_xml() that will return the xml needed to attachDeviceFlags() and detachDeviceFlags()
+ @property + def _update_param(self): + self.elemArgs['readonly'] = "<readonly/>" \ + if self.elemArgs['target']['type'] == 'cdrom' else None + xml = """ + <disk type='{source[type]}' device='{target[type]}'> + <source file='{source[path]}'/> + <target dev='{target[name]}' bus='{target[bus]}'/> + {readonly} + </disk> + """.format(**self.elemArgs) + return dict(xml=xml) + + class StoragePoolDef(object): @classmethod def create(cls, poolArgs):
participants (3)
-
Aline Manera
-
Crístian Viana
-
lvroyce0210@gmail.com