Change in vdsm[master]: v2v: introduction to OutputParser
shavivi at redhat.com
shavivi at redhat.com
Mon Mar 30 13:22:17 UTC 2015
Shahar Havivi has uploaded a new change for review.
Change subject: v2v: introduction to OutputParser
......................................................................
v2v: introduction to OutputParser
OutputParser is a parser for virt-v2v process output.
It analyze the phases of copying disk and each copy disk progress.
class also raise events respectfully.
Change-Id: I54f3d610d704d0b922e38073edcc813cbc27fe83
Signed-off-by: Shahar Havivi <shaharh at redhat.com>
---
M tests/v2vTests.py
M vdsm/v2v.py
2 files changed, 77 insertions(+), 85 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/60/39360/1
diff --git a/tests/v2vTests.py b/tests/v2vTests.py
index f295771..dff77ac 100644
--- a/tests/v2vTests.py
+++ b/tests/v2vTests.py
@@ -17,95 +17,36 @@
# Refer to the README and COPYING files for full details of the license
#
+from StringIO import StringIO
+
import v2v
-from vdsm import libvirtconnection
-
-from nose.plugins.skip import SkipTest
from testlib import VdsmTestCase as TestCaseBase
-from monkeypatch import MonkeyPatch
-
-
-class VmMock(object):
- def name(self):
- return 'windows'
-
- def state(self, flags=0):
- return [5, 0]
-
- def XMLDesc(self, flags=0):
- return """
-<domain type='vmware' id='15'>
- <name>RHEL</name>
- <uuid>564d7cb4-8e3d-06ec-ce82-7b2b13c6a611</uuid>
- <memory unit='KiB'>2097152</memory>
- <currentMemory unit='KiB'>2097152</currentMemory>
- <vcpu placement='static'>1</vcpu>
- <os>
- <type arch='x86_64'>hvm</type>
- </os>
- <clock offset='utc'/>
- <on_poweroff>destroy</on_poweroff>
- <on_reboot>restart</on_reboot>
- <on_crash>destroy</on_crash>
- <devices>
- <disk type='file' device='disk'>
- <source file='[datastore1] RHEL/RHEL.vmdk'/>
- <target dev='sda' bus='scsi'/>
- <address type='drive' controller='0' bus='0' target='0' unit='0'/>
- </disk>
- <controller type='scsi' index='0' model='vmpvscsi'/>
- <interface type='bridge'>
- <mac address='00:0c:29:c6:a6:11'/>
- <source bridge='VM Network'/>
- <model type='vmxnet3'/>
- </interface>
- <video>
- <model type='vmvga' vram='8192'/>
- </video>
- </devices>
-</domain>"""
-
-
-# FIXME: extend vmfakelib allowing to set predefined domain in Connection class
-class LibvirtMock(object):
- def close(self):
- pass
-
- def listAllDomains(self):
- return [VmMock()]
-
- def storageVolLookupByPath(self, name):
- return LibvirtMock.Volume()
-
- class Volume(object):
- def info(self):
- return [0, 0, 0]
-
-
-def hypervisorConnect(uri, username, passwd):
- return LibvirtMock()
class v2vTests(TestCaseBase):
- @MonkeyPatch(libvirtconnection, 'open_connection', hypervisorConnect)
- def testGetExternalVMs(self):
- if not v2v.supported():
- raise SkipTest('v2v is not supported current os version')
+ def testOutputParser(self):
+ output = ''.join(['[ 0.0] Opening the source -i libvirt ://roo...\n',
+ '[ 1.0] Creating an overlay to protect the f...\n',
+ '[ 88.0] Copying disk 1/2 to /tmp/v2v/0000000...\n',
+ ' (0/100%)\r',
+ ' (50/100%)\r',
+ ' (100/100%)\r',
+ '[ 180.0] Copying disk 2/2 to /tmp/v2v/100000-...\n',
+ ' (0/100%)\r',
+ ' (50/100%)\r',
+ ' (100/100%)\r',
+ '[ 256.0] Creating output metadata',
+ '[ 256.0] Finishing off'])
- vms = v2v.get_external_vms('esx://mydomain', 'user',
- 'password')['vmList']
- self.assertEquals(len(vms), 1)
- vm = vms[0]
- self.assertEquals(vm['vmId'], '564d7cb4-8e3d-06ec-ce82-7b2b13c6a611')
- self.assertEquals(vm['memSize'], 2048)
- self.assertEquals(vm['smp'], 1)
- self.assertEquals(len(vm['disks']), 1)
- self.assertEquals(len(vm['networks']), 1)
- disk = vm['disks'][0]
- self.assertEquals(disk['dev'], 'sda')
- self.assertEquals(disk['alias'], '[datastore1] RHEL/RHEL.vmdk')
- network = vm['networks'][0]
- self.assertEquals(network['type'], 'bridge')
- self.assertEquals(network['macAddr'], '00:0c:29:c6:a6:11')
- self.assertEquals(network['bridge'], 'VM Network')
+ parser = v2v.OutputParser()
+ events = list(parser.parse(StringIO(output)))
+ self.assertEqual(events, [
+ (v2v.ImportProgress(1, 2, 'Copying disk 1/2')),
+ (v2v.DiskProgress(0)),
+ (v2v.DiskProgress(50)),
+ (v2v.DiskProgress(100)),
+ (v2v.ImportProgress(2, 2, 'Copying disk 2/2')),
+ (v2v.DiskProgress(0)),
+ (v2v.DiskProgress(50)),
+ (v2v.DiskProgress(100))])
diff --git a/vdsm/v2v.py b/vdsm/v2v.py
index 4fbecf0..3990851 100644
--- a/vdsm/v2v.py
+++ b/vdsm/v2v.py
@@ -16,8 +16,10 @@
#
# Refer to the README and COPYING files for full details of the license
#
+from collections import namedtuple
from contextlib import closing
import logging
+import re
import xml.etree.ElementTree as ET
import libvirt
@@ -28,8 +30,17 @@
import caps
+ImportProgress = namedtuple('ImportProgress',
+ ['current_disk', 'disk_count', 'description'])
+DiskProgress = namedtuple('DiskProgress', ['progress'])
+
+
class InvalidVMConfiguration(ValueError):
''' Unexpected error while parsing libvirt domain xml '''
+
+
+class OutputParserError(ValueError):
+ ''' Error while parsing virt-v2v output '''
def supported():
@@ -70,6 +81,46 @@
return {'status': doneCode, 'vmList': vms}
+class OutputParser(object):
+ COPY_DISK_RE = re.compile(r'.*(Copying disk (\d+)/(\d+)).*')
+ DISK_PROGRESS_RE = re.compile(r'\s+\((\d+).*')
+
+ def parse(self, stream):
+ for line in stream:
+ if 'Copying disk' in line:
+ description, current_disk, disk_count = self._parse_line(line)
+ yield ImportProgress(int(current_disk), int(disk_count),
+ description)
+ for progress in self._parse_progress(stream):
+ yield DiskProgress(progress)
+
+ def _parse_line(self, line):
+ m = self.COPY_DISK_RE.match(line)
+ if m is None:
+ raise OutputParserError('unexpected format in "Copying disk"'
+ ', line: %r' % line)
+ return m.group(1), m.group(2), m.group(3)
+
+ def _parse_progress(self, stream):
+ buf = ''
+ progress = 0
+ while progress < 100:
+ c = stream.read(1)
+ buf += c
+ if c == '\r':
+ m = self.DISK_PROGRESS_RE.match(buf)
+ if m is None:
+ raise OutputParserError('error parsing progress, buf: %r'
+ % buf)
+ buf = ''
+ try:
+ progress = int(m.group(1))
+ except ValueError:
+ raise OutputParserError('error parsing progress regex: %r'
+ % m.groups)
+ yield progress
+
+
def _mem_to_mib(size, unit):
lunit = unit.lower()
if lunit in ('bytes', 'b'):
--
To view, visit https://gerrit.ovirt.org/39360
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I54f3d610d704d0b922e38073edcc813cbc27fe83
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Shahar Havivi <shavivi at redhat.com>
More information about the vdsm-patches
mailing list