[Libguestfs] [PATCH v2 3/3] v2v: -o rhv-upload: Add a test.

Nir Soffer nsoffer at redhat.com
Tue Oct 9 11:28:10 UTC 2018


On Thu, Sep 20, 2018 at 11:51 AM Richard W.M. Jones <rjones at redhat.com>
wrote:

> Previously this output method was almost completely untested.
>
> This commit adds a fake ovirtsdk4 module so we can test the
> -o rhv-upload method fairly completely without needing an actual
> oVirt instance around.
> ---
>  v2v/Makefile.am                               |   4 +
>  .../ovirtsdk4/__init__.py                     | 146 ++++++++++++++++++
>  .../ovirtsdk4/types.py                        | 125 +++++++++++++++
>  v2v/test-v2v-o-rhv-upload.sh                  |  51 ++++++
>  4 files changed, 326 insertions(+)
>
> diff --git a/v2v/Makefile.am b/v2v/Makefile.am
> index 14183572b..aab356637 100644
> --- a/v2v/Makefile.am
> +++ b/v2v/Makefile.am
> @@ -382,6 +382,7 @@ TESTS += \
>         test-v2v-o-openstack.sh \
>         test-v2v-o-qemu.sh \
>         test-v2v-o-rhv.sh \
> +       test-v2v-o-rhv-upload.sh \
>         test-v2v-o-vdsm-options.sh \
>         test-v2v-oa-option.sh \
>         test-v2v-of-option.sh \
> @@ -539,6 +540,9 @@ EXTRA_DIST += \
>         test-v2v-o-qemu.sh \
>         test-v2v-o-rhv.ovf.expected \
>         test-v2v-o-rhv.sh \
> +       test-v2v-o-rhv-upload.sh \
> +       test-v2v-o-rhv-upload-module/ovirtsdk4/__init__.py \
> +       test-v2v-o-rhv-upload-module/ovirtsdk4/types.py \
>         test-v2v-o-rhv-upload-oo-query.sh \
>         test-v2v-o-vdsm-oo-query.sh \
>         test-v2v-o-vdsm-options.ovf.expected \
> diff --git a/v2v/test-v2v-o-rhv-upload-module/ovirtsdk4/__init__.py
> b/v2v/test-v2v-o-rhv-upload-module/ovirtsdk4/__init__.py
> new file mode 100644
> index 000000000..2ddb950ea
> --- /dev/null
> +++ b/v2v/test-v2v-o-rhv-upload-module/ovirtsdk4/__init__.py
> @@ -0,0 +1,146 @@
> +# -*- python -*-
> +# Copyright (C) 2018 Red Hat Inc.
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 2 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License along
> +# with this program; if not, write to the Free Software Foundation, Inc.,
> +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> +
> +# Fake ovirtsdk4 module used as a test harness.
> +# See v2v/test-v2v-o-rhv-upload.sh
> +
> +class Error(Exception):
> +    pass
> +class NotFoundError(Error):
> +    pass
> +
> +class Connection(object):
> +    def __init__(
> +            self,
> +            url = None,
> +            username = None,
> +            password = None,
> +            ca_file = None,
> +            log = None,
> +            insecure = False,
> +    ):
> +        pass
> +
> +    def system_service(self):
> +        return SystemService()
> +
> +class SystemService(object):
> +    def data_centers_service(self):
> +        return DataCentersService()
> +
> +    def disks_service(self):
> +        return DisksService()
> +
> +    def image_transfers_service(self):
> +        return ImageTransfersService()
> +
> +    def storage_domains_service(self):
> +        return StorageDomainsService()
> +
> +    def vms_service(self):
> +        return VmsService()
> +
> +class DataCentersService(object):
> +    def list(self, search=None, case_sensitive=False):
> +        return []
> +
> +class DiskService(object):
> +    def __init__(self, disk_id):
> +        self._disk_id = disk_id
> +
> +    def get(self):
> +        return types.Disk()
> +
> +    def remove(self):
> +        pass
> +
> +class DisksService(object):
> +    def add(self, disk=None):
> +        return disk
> +
> +    def disk_service(self, disk_id):
> +        return DiskService(disk_id)
> +
> +class ImageTransferService(object):
> +    def __init__(self):
> +        self._finalized = False
> +
> +    def get(self):
> +        if self._finalized:
> +            raise NotFoundError
> +        else:
> +            return types.ImageTransfer()
> +
> +    def finalize(self):
> +        self._finalized = True
> +
> +class ImageTransfersService(object):
> +    def add(self, transfer):
> +        return transfer
> +
> +    def image_transfer_service(self, id):
> +        return ImageTransferService()
> +
> +class StorageDomain(object):
> +    id = "ba87af68-b630-4211-a73a-694c1a689405"
> +
> +class StorageDomainsService(object):
> +    def list(self, search=None):
> +        return [ StorageDomain() ]
> +
> +class VmsService(object):
> +    def add(self, vm):
> +        return vm
> +
> +    def list(self, search=None):
> +        return []
> +
> +# Create a background thread running a web server which is
> +# simulating the imageio server.
>

This functionality should be separated from the fake SDK module, since it is
not part of the SDK, and may be replaced by real imageio server later.


> +
> +from http.server import HTTPServer, BaseHTTPRequestHandler
> +import random
> +import threading
> +
> +# Choose a random port number in range [50000,59999]
> +imageio_port = random.randint(50000,60000)
> +
> +class RequestHandler(BaseHTTPRequestHandler):
>

This request handler is using HTTP/1.0, and will close the connection after
every request. This is not a good implementation of the imageio server, and
also
hides bugs in this code.

Should be fixed by adding:

    protocol_version = "HTTP/1.1"


> +    def do_OPTIONS(self):

+        self.send_response(200)
> +        self.send_header("Content-type", "application/json;
> charset=UTF-8")
> +        self.end_headers()
> +        # Advertize only zero support.
> +        self.wfile.write(b'''{ "features": [ "zero" ] }''')
> +
> +    # eg. zero request.  Just ignore it.
> +    def do_PATCH(self):
>

This must read content-length bytes from self.rfile.


> +        self.send_response(200)
> +        self.end_headers()
> +
> +    # Flush request.  Ignore it.
> +    def do_PUT(self):
>

This must read content-length bytes from self.rfile.

Both bugs are hidden by the fact that this server close the connection at
the end
of the request.


> +        self.send_response(200)
> +        self.end_headers()
> +
> +def server():
> +    server_address = ("", imageio_port)
> +    httpd = HTTPServer(server_address, RequestHandler)
> +    httpd.serve_forever()
>

Using HTTP instead of HTTPS is not a good idea. We are not testing the same
code
on the client side.

It is easy to run HTTPS server using pre-created certificate, if we disable
certificate
verification on the client side (e.g. --insecure).

Nir


> +
> +thread = threading.Thread(target = server, args = [], daemon = True)
> +thread.start()
> diff --git a/v2v/test-v2v-o-rhv-upload-module/ovirtsdk4/types.py
> b/v2v/test-v2v-o-rhv-upload-module/ovirtsdk4/types.py
> new file mode 100644
> index 000000000..9b3f557ee
> --- /dev/null
> +++ b/v2v/test-v2v-o-rhv-upload-module/ovirtsdk4/types.py
> @@ -0,0 +1,125 @@
> +# -*- python -*-
> +# Copyright (C) 2018 Red Hat Inc.
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 2 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License along
> +# with this program; if not, write to the Free Software Foundation, Inc.,
> +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> +
> +# Fake ovirtsdk4 module used as a test harness.
> +# See v2v/test-v2v-o-rhv-upload.sh
> +
> +from enum import Enum
> +from ovirtsdk4 import imageio_port
> +
> +class Cluster(object):
> +    def __init__(self, name):
> +        pass
> +
> +class Configuration(object):
> +    def __init__(self, type=None, data=None):
> +        pass
> +class ConfigurationType(Enum):
> +    OVA = 'ova'
> +    OVF = 'ovf'
> +
> +    def __init__(self, image):
> +        self._image = image
> +
> +    def __str__(self):
> +        return self._image
> +
> +class DiskFormat(Enum):
> +    COW = "cow"
> +    RAW = "raw"
> +
> +    def __init__(self, image):
> +        self._image = image
> +
> +    def __str__(self):
> +        return self._image
> +
> +class DiskStatus(Enum):
> +    ILLEGAL = "illegal"
> +    LOCKED = "locked"
> +    OK = "ok"
> +
> +    def __init__(self, image):
> +        self._image = image
> +
> +    def __str__(self):
> +        return self._image
> +
> +class Disk(object):
> +    def __init__(
> +            self,
> +            id = None,
> +            name = None,
> +            description = None,
> +            format = None,
> +            initial_size = None,
> +            provisioned_size = None,
> +            sparse = False,
> +            storage_domains = None
> +    ):
> +        pass
> +
> +    id = 123
> +    status = DiskStatus.OK
> +
> +class ImageTransferPhase(Enum):
> +    CANCELLED = 'cancelled'
> +    FINALIZING_FAILURE = 'finalizing_failure'
> +    FINALIZING_SUCCESS = 'finalizing_success'
> +    FINISHED_FAILURE = 'finished_failure'
> +    FINISHED_SUCCESS = 'finished_success'
> +    INITIALIZING = 'initializing'
> +    PAUSED_SYSTEM = 'paused_system'
> +    PAUSED_USER = 'paused_user'
> +    RESUMING = 'resuming'
> +    TRANSFERRING = 'transferring'
> +    UNKNOWN = 'unknown'
> +
> +    def __init__(self, image):
> +        self._image = image
> +
> +    def __str__(self):
> +        return self._image
> +
> +class ImageTransfer(object):
> +    def __init__(
> +            self,
> +            disk = None,
> +            host = None,
> +            inactivity_timeout = None,
> +    ):
> +        pass
> +
> +    id = 456
> +    phase = ImageTransferPhase.TRANSFERRING
> +    transfer_url = "http://localhost:" + str(imageio_port) + "/"
> +
> +class Initialization(object):
> +    def __init__(self, configuration):
> +        pass
> +
> +class StorageDomain(object):
> +    def __init__(self, name = None):
> +        pass
> +
> +class Vm(object):
> +    def __init__(
> +            self,
> +            cluster = None,
> +            initialization = None
> +    ):
> +        pass
> diff --git a/v2v/test-v2v-o-rhv-upload.sh b/v2v/test-v2v-o-rhv-upload.sh
> new file mode 100755
> index 000000000..8bda7cc0b
> --- /dev/null
> +++ b/v2v/test-v2v-o-rhv-upload.sh
> @@ -0,0 +1,51 @@
> +#!/bin/bash -
> +# libguestfs virt-v2v test script
> +# Copyright (C) 2018 Red Hat Inc.
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 2 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write to the Free Software
> +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA.
> +
> +# Test -o rhv-upload.
> +#
> +# These uses a test harness (see
> +# v2v/test-v2v-o-rhv-upload-module/ovirtsdk4) to fake responses from
> +# oVirt.
> +
> +set -e
> +set -x
> +
> +$TEST_FUNCTIONS
> +skip_if_skipped
> +skip_if_backend uml
> +skip_unless_phony_guest windows.img
> +
> +libvirt_uri="test://$abs_top_builddir/test-data/phony-guests/guests.xml"
> +f=$top_builddir/test-data/phony-guests/windows.img
> +
> +export VIRT_TOOLS_DATA_DIR="$top_srcdir/test-data/fake-virt-tools"
> +export VIRTIO_WIN="$top_srcdir/test-data/fake-virtio-win"
> +export PYTHONPATH=$srcdir/test-v2v-o-rhv-upload-module:$PYTHONPATH
> +
> +# Run virt-v2v -o rhv-upload.
> +#
> +# The fake ovirtsdk4 module doesn't care about most of the options
> +# like -oc, -oo rhv-cafile, -op etc.  Any values may be used.
> +$VG virt-v2v --debug-gc -v -x \
> +    -i libvirt -ic "$libvirt_uri" windows \
> +    -o rhv-upload \
> +    -oc https://example.com/ovirt-engine/api \
> +    -oo rhv-cafile=/dev/null \
> +    -oo rhv-direct \
> +    -op /dev/null \
> +    -os .
> --
> 2.19.0.rc0
>
> _______________________________________________
> Libguestfs mailing list
> Libguestfs at redhat.com
> https://www.redhat.com/mailman/listinfo/libguestfs
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://listman.redhat.com/archives/libguestfs/attachments/20181009/4ea64e4f/attachment.htm>


More information about the Libguestfs mailing list