2015-04-01 21:07:51 +08:00
|
|
|
# Copyright (C) 2013, 2015 Red Hat, Inc.
|
2013-03-18 05:06:52 +08:00
|
|
|
#
|
|
|
|
# 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
|
2013-10-28 04:59:47 +08:00
|
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
|
|
# (at your option) any later version.
|
2013-03-18 05:06:52 +08:00
|
|
|
#
|
|
|
|
# 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.
|
|
|
|
|
|
|
|
import unittest
|
|
|
|
import os
|
|
|
|
import logging
|
|
|
|
|
2013-04-11 07:48:07 +08:00
|
|
|
from tests import utils
|
2013-03-18 05:06:52 +08:00
|
|
|
|
2013-07-03 06:30:46 +08:00
|
|
|
from virtinst import Cloner
|
2013-03-18 05:06:52 +08:00
|
|
|
|
|
|
|
ORIG_NAME = "clone-orig"
|
|
|
|
CLONE_NAME = "clone-new"
|
|
|
|
|
|
|
|
# Create some files to use as test images
|
|
|
|
FILE1 = "/tmp/virtinst-test1.img"
|
|
|
|
FILE2 = "/tmp/virtinst-test2.img"
|
2013-07-26 10:06:28 +08:00
|
|
|
P1_VOL1 = "/dev/default-pool/testvol1.img"
|
|
|
|
P1_VOL2 = "/dev/default-pool/testvol2.img"
|
|
|
|
P2_VOL1 = "/dev/cross-pool/testvol1.img"
|
|
|
|
P2_VOL2 = "/dev/cross-pool/testvol2.img"
|
2013-03-18 05:06:52 +08:00
|
|
|
|
2013-07-26 10:06:28 +08:00
|
|
|
POOL1 = "/dev/default-pool"
|
|
|
|
POOL2 = "/dev/cross-pool"
|
|
|
|
DISKPOOL = "/dev/disk-pool"
|
2013-03-18 05:06:52 +08:00
|
|
|
|
2013-04-14 02:34:52 +08:00
|
|
|
local_files = [FILE1, FILE2]
|
2013-03-18 05:06:52 +08:00
|
|
|
|
|
|
|
clonexml_dir = os.path.join(os.getcwd(), "tests/clone-xml")
|
|
|
|
|
2013-04-14 02:34:52 +08:00
|
|
|
|
2013-03-18 05:06:52 +08:00
|
|
|
class TestClone(unittest.TestCase):
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
for f in local_files:
|
|
|
|
os.system("touch %s" % f)
|
|
|
|
|
|
|
|
def tearDown(self):
|
|
|
|
for f in local_files:
|
|
|
|
os.unlink(f)
|
|
|
|
|
2018-02-21 03:34:56 +08:00
|
|
|
def _clone(self, filebase, disks=None, force_list=None,
|
|
|
|
skip_list=None, compare=True, conn=None,
|
|
|
|
clone_disks_file=None):
|
2013-03-18 05:06:52 +08:00
|
|
|
"""Helper for comparing clone input/output from 2 xml files"""
|
|
|
|
infile = os.path.join(clonexml_dir, filebase + "-in.xml")
|
|
|
|
in_content = utils.read_file(infile)
|
|
|
|
|
2017-07-19 05:00:01 +08:00
|
|
|
if not conn:
|
2018-02-23 03:57:10 +08:00
|
|
|
conn = utils.URIs.open_testdriver_cached()
|
2017-07-19 05:00:01 +08:00
|
|
|
cloneobj = Cloner(conn)
|
2013-03-18 05:06:52 +08:00
|
|
|
cloneobj.original_xml = in_content
|
|
|
|
for force in force_list or []:
|
|
|
|
cloneobj.force_target = force
|
|
|
|
for skip in skip_list or []:
|
|
|
|
cloneobj.skip_target = skip
|
|
|
|
|
|
|
|
cloneobj = self._default_clone_values(cloneobj, disks)
|
|
|
|
|
|
|
|
if compare:
|
2015-04-01 21:07:51 +08:00
|
|
|
self._clone_compare(cloneobj, filebase,
|
|
|
|
clone_disks_file=clone_disks_file)
|
2013-03-18 05:06:52 +08:00
|
|
|
self._clone_define(filebase)
|
|
|
|
else:
|
2017-07-21 05:18:14 +08:00
|
|
|
cloneobj.setup_original()
|
|
|
|
cloneobj.setup_clone()
|
2013-03-18 05:06:52 +08:00
|
|
|
|
|
|
|
def _default_clone_values(self, cloneobj, disks=None):
|
|
|
|
"""Sets default values for the cloned VM."""
|
|
|
|
cloneobj.clone_name = "clone-new"
|
|
|
|
cloneobj.clone_uuid = "12345678-1234-1234-1234-123456789012"
|
|
|
|
|
2013-07-03 06:30:46 +08:00
|
|
|
cloneobj.clone_macs = ["22:23:45:67:89:00", "22:23:45:67:89:01"]
|
2013-03-18 05:06:52 +08:00
|
|
|
|
2013-07-03 06:30:46 +08:00
|
|
|
if disks is None:
|
2013-07-26 10:06:28 +08:00
|
|
|
disks = ["/dev/disk-pool/disk-vol1", "/tmp/clone2.img",
|
2015-06-05 22:55:39 +08:00
|
|
|
"/clone3", "/tmp/clone4.img",
|
2013-07-03 06:30:46 +08:00
|
|
|
"/tmp/clone5.img", None]
|
2013-03-18 05:06:52 +08:00
|
|
|
|
2013-07-03 06:30:46 +08:00
|
|
|
cloneobj.clone_paths = disks
|
2013-03-18 05:06:52 +08:00
|
|
|
return cloneobj
|
|
|
|
|
2015-04-01 21:07:51 +08:00
|
|
|
def _clone_compare(self, cloneobj, outbase, clone_disks_file=None):
|
2013-03-18 05:06:52 +08:00
|
|
|
"""Helps compare output from passed clone instance with an xml file"""
|
|
|
|
outfile = os.path.join(clonexml_dir, outbase + "-out.xml")
|
|
|
|
|
2017-07-21 05:18:14 +08:00
|
|
|
cloneobj.setup_original()
|
|
|
|
cloneobj.setup_clone()
|
2013-03-18 05:06:52 +08:00
|
|
|
|
|
|
|
utils.diff_compare(cloneobj.clone_xml, outfile)
|
2015-04-01 21:07:51 +08:00
|
|
|
if clone_disks_file:
|
|
|
|
xml_clone_disks = ""
|
|
|
|
for i in cloneobj.get_clone_disks():
|
|
|
|
xml_clone_disks += i.get_vol_install().get_xml_config()
|
|
|
|
utils.diff_compare(xml_clone_disks, clone_disks_file)
|
2013-03-18 05:06:52 +08:00
|
|
|
|
|
|
|
def _clone_define(self, filebase):
|
|
|
|
"""Take the valid output xml and attempt to define it on the
|
|
|
|
connection to ensure we don't get any errors"""
|
|
|
|
outfile = os.path.join(clonexml_dir, filebase + "-out.xml")
|
|
|
|
outxml = utils.read_file(outfile)
|
2018-02-23 03:57:10 +08:00
|
|
|
conn = utils.URIs.open_testdriver_cached()
|
2013-03-18 05:06:52 +08:00
|
|
|
utils.test_create(conn, outxml)
|
|
|
|
|
|
|
|
def testRemoteNoStorage(self):
|
|
|
|
"""Test remote clone where VM has no storage that needs cloning"""
|
2018-02-23 03:57:10 +08:00
|
|
|
conn = utils.URIs.open_test_remote()
|
2018-02-21 03:34:56 +08:00
|
|
|
self._clone("nostorage", conn=conn)
|
|
|
|
self._clone("noclone-storage", conn=conn)
|
2013-03-18 05:06:52 +08:00
|
|
|
|
|
|
|
def testRemoteWithStorage(self):
|
|
|
|
"""
|
|
|
|
Test remote clone with storage needing cloning. Should fail,
|
|
|
|
since libvirt has no storage clone api.
|
|
|
|
"""
|
2018-02-23 03:57:10 +08:00
|
|
|
conn = utils.URIs.open_test_remote()
|
2018-02-21 03:34:56 +08:00
|
|
|
disks = ["%s/1.img" % POOL1, "%s/2.img" % POOL1]
|
|
|
|
try:
|
|
|
|
self._clone("general-cfg", disks=disks, conn=conn)
|
|
|
|
# We shouldn't succeed, so test fails
|
|
|
|
raise AssertionError("Remote clone with storage passed "
|
|
|
|
"when it shouldn't.")
|
|
|
|
except (ValueError, RuntimeError) as e:
|
|
|
|
# Exception expected
|
|
|
|
logging.debug("Received expected exception: %s", str(e))
|
2013-03-18 05:06:52 +08:00
|
|
|
|
2013-07-13 22:09:00 +08:00
|
|
|
def testCloneStorageManaged(self):
|
2018-02-21 03:34:56 +08:00
|
|
|
disks = ["%s/new1.img" % POOL1, "%s/new2.img" % DISKPOOL]
|
|
|
|
self._clone("managed-storage", disks=disks)
|
2013-03-18 05:06:52 +08:00
|
|
|
|
|
|
|
def testCloneStorageCrossPool(self):
|
2018-02-23 03:57:10 +08:00
|
|
|
conn = utils.URIs.open_test_remote()
|
2018-02-21 03:34:56 +08:00
|
|
|
clone_disks_file = os.path.join(
|
|
|
|
clonexml_dir, "cross-pool-disks-out.xml")
|
|
|
|
disks = ["%s/new1.img" % POOL2, "%s/new2.img" % POOL1]
|
|
|
|
self._clone("cross-pool", disks=disks,
|
|
|
|
clone_disks_file=clone_disks_file, conn=conn)
|
2013-03-18 05:06:52 +08:00
|
|
|
|
|
|
|
def testCloneStorageForce(self):
|
2018-02-21 03:34:56 +08:00
|
|
|
disks = ["/dev/default-pool/1234.img", None, "/clone2.img"]
|
|
|
|
self._clone("force", disks=disks, force_list=["hda", "fdb", "sdb"])
|
2013-03-18 05:06:52 +08:00
|
|
|
|
|
|
|
def testCloneStorageSkip(self):
|
2018-02-21 03:34:56 +08:00
|
|
|
disks = ["/dev/default-pool/1234.img", None, "/tmp/clone2.img"]
|
|
|
|
skip_list = ["hda", "fdb"]
|
|
|
|
self._clone("skip", disks=disks, skip_list=skip_list)
|
2013-03-18 05:06:52 +08:00
|
|
|
|
|
|
|
def testCloneFullPool(self):
|
|
|
|
try:
|
2018-02-21 03:34:56 +08:00
|
|
|
self._clone("fullpool",
|
|
|
|
disks=["/full-pool/test.img"], compare=False)
|
2013-03-18 05:06:52 +08:00
|
|
|
except Exception:
|
|
|
|
return
|
|
|
|
|
|
|
|
raise AssertionError("Expected exception, but none raised.")
|
2017-03-06 16:43:10 +08:00
|
|
|
|
|
|
|
def testCloneNvramAuto(self):
|
2018-02-21 03:34:56 +08:00
|
|
|
self._clone("nvram-auto")
|
2017-07-19 03:42:11 +08:00
|
|
|
|
|
|
|
def testCloneNvramNewpool(self):
|
2018-02-21 03:34:56 +08:00
|
|
|
self._clone("nvram-newpool")
|
2017-09-16 00:34:58 +08:00
|
|
|
|
|
|
|
def testCloneGraphicsPassword(self):
|
2018-02-21 03:34:56 +08:00
|
|
|
self._clone("graphics-password")
|