libvirt-python 12.6.0__tar.gz → 12.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/AUTHORS +1 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/ChangeLog +113 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/HACKING +20 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/PKG-INFO +2 -2
- libvirt_python-12.7.0/VERSION +1 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/build/libvirt_python.egg-info/SOURCES.txt +1 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/libvirt-override.c +3 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/libvirt-python.spec +11 -17
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/setup.cfg +1 -1
- libvirt_python-12.7.0/tests/test_conn.py +268 -0
- libvirt_python-12.7.0/tests/test_domain_migration.py +391 -0
- libvirt_python-12.6.0/VERSION +0 -1
- libvirt_python-12.6.0/tests/test_conn.py +0 -92
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/CONTRIBUTING.rst +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/COPYING +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/MANIFEST.in +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/Makefile +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/README +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/examples/README +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/examples/consolecallback.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/examples/dhcpleases.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/examples/dominfo.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/examples/domipaddrs.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/examples/domrestore.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/examples/domsave.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/examples/domstart.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/examples/esxlist.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/examples/event-test.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/examples/guest-vcpus/guest-vcpu-daemon.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/examples/guest-vcpus/guest-vcpu.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/examples/nodestats.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/examples/sparsestream.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/examples/topology.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/generator.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/libvirt-lxc-override-api.xml +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/libvirt-lxc-override.c +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/libvirt-override-api.xml +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/libvirt-override-virConnect.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/libvirt-override-virDomain.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/libvirt-override-virDomainCheckpoint.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/libvirt-override-virDomainSnapshot.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/libvirt-override-virNetwork.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/libvirt-override-virStoragePool.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/libvirt-override-virStream.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/libvirt-override.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/libvirt-qemu-override-api.xml +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/libvirt-qemu-override.c +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/libvirt-qemu-override.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/libvirt-utils.c +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/libvirt-utils.h +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/libvirtaio.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/pyproject.toml +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/requirements-test.txt +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/setup.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/tests/eventmock.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/tests/test_aio.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/tests/test_api_coverage.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/tests/test_domain.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/tests/test_domain_checkpoint.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/tests/test_domain_config.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/tests/test_domain_lifecycle.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/tests/test_domain_snapshot.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/tests/test_interface.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/tests/test_network.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/tests/test_nodedev.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/tests/test_storage.py +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/tox.ini +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/typewrappers.c +0 -0
- {libvirt_python-12.6.0 → libvirt_python-12.7.0}/typewrappers.h +0 -0
|
@@ -43,6 +43,7 @@ The individual contributors are
|
|
|
43
43
|
Guido Günther <agx@sigxcpu.org>
|
|
44
44
|
Han Han <hhan@redhat.com>
|
|
45
45
|
Hu Tao <hutao@cn.fujitsu.com>
|
|
46
|
+
Jaehoon Kim <jhkim@linux.ibm.com>
|
|
46
47
|
Jason Andryuk <andryuk@aero.org>
|
|
47
48
|
Jelle van der Waa <jvanderwaa@redhat.com>
|
|
48
49
|
Jim Fehlig <jfehlig@suse.com>
|
|
@@ -1,3 +1,116 @@
|
|
|
1
|
+
2026- 8- 25 Jaehoon Kim <jhkim@linux.ibm.com>
|
|
2
|
+
|
|
3
|
+
Add VIR_DOMAIN_IOTHREAD_POLL_WEIGHT macro
|
|
4
|
+
The VIR_DOMAIN_IOTHREAD_POLL_WEIGHT typed param is being introduced
|
|
5
|
+
in libvirt v12.7.0. Add the correct VIR_TYPED_PARAM_UINT entry to
|
|
6
|
+
virPyDomainSetIOThreadParams[] so that the parameter is parsed with
|
|
7
|
+
the correct type.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
2026- 8- 20 Radoslaw Smigielski <rsmigiel@redhat.com>
|
|
12
|
+
|
|
13
|
+
tests: add migration API tests for migrate, migrate2, and migrate3
|
|
14
|
+
Add a new test file test_domain_migration.py to cover the VM migration API,
|
|
15
|
+
using mocked C-level calls and test driver.
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
2026- 8- 6 Radoslaw Smigielski <rsmigiel@redhat.com>
|
|
20
|
+
|
|
21
|
+
tests: expand connection tests in test_conn.py
|
|
22
|
+
Add functional tests for read-write and read-only connections using
|
|
23
|
+
the test:///default driver.
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
2026- 8- 6 Daniel P. Berrangé <berrange@redhat.com>
|
|
28
|
+
|
|
29
|
+
rpm: convert to new pyproject macros
|
|
30
|
+
The currently used macros are deprecated:
|
|
31
|
+
|
|
32
|
+
https://fedoraproject.org/wiki/Changes/DeprecateSetuppyMacros
|
|
33
|
+
|
|
34
|
+
and print a warning that they will be removed in Fedora 45 so we
|
|
35
|
+
are overdue to port to the new macros.
|
|
36
|
+
|
|
37
|
+
The new macros appear to be compatible with CentOS Stream 9, so
|
|
38
|
+
we don't need conditional use of the old macros.
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
2026- 8- 6 Daniel P. Berrangé <berrange@redhat.com>
|
|
43
|
+
|
|
44
|
+
ci: add pyproject-rpm-macros
|
|
45
|
+
This is needed for the forthcoming change to the RPM packaging
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
2026- 8- 6 Daniel P. Berrangé <berrange@redhat.com>
|
|
50
|
+
|
|
51
|
+
rpm: update to RHEL-9 / Fedora 43 as min versions
|
|
52
|
+
This lets us assume newer Python packaging macros
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
2026- 8- 5 Radoslaw Smigielski <rsmigiel@redhat.com>
|
|
57
|
+
|
|
58
|
+
docs: simplyfy steps to build docs with Sphinx
|
|
59
|
+
Encapsulate all requirements in Python virtual environment,
|
|
60
|
+
do not depend on installing them at the system level.
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
2026- 8- 5 Radoslaw Smigielski <rsmigiel@redhat.com>
|
|
65
|
+
|
|
66
|
+
docs: document Sphinx building steps
|
|
67
|
+
Added a "Building API Documentation" section to HACKING file
|
|
68
|
+
with the step of building docs with sphinx.
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
2026- 8- 5 Radoslaw Smigielski <rsmigiel@redhat.com>
|
|
73
|
+
|
|
74
|
+
docs: publish libvirt-python API docs via GitLab pages
|
|
75
|
+
Add jobs:
|
|
76
|
+
- website_job
|
|
77
|
+
- pages
|
|
78
|
+
to build libvirt-python API docs using Sphinx.
|
|
79
|
+
|
|
80
|
+
Created base on libvirt-php/libvirt-java/libvirt-ruby examples.
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
2026- 8- 5 Radoslaw Smigielski <rsmigiel@redhat.com>
|
|
85
|
+
|
|
86
|
+
docs: add Sphinx configuration to generate Python API documentation
|
|
87
|
+
The libvirt-python bindings lack official API documentation despite
|
|
88
|
+
all the infrastructure for it already existing: the libvirt C project
|
|
89
|
+
ships XML API descriptions (libvirt-api.xml) with detailed function
|
|
90
|
+
documentation, and generator.py already extracts these descriptions
|
|
91
|
+
into Python docstrings in the generated code. However, there was no
|
|
92
|
+
tooling to render these docstrings into browsable documentation.
|
|
93
|
+
|
|
94
|
+
Add a basic Sphinx setup with autodoc to generate HTML API reference
|
|
95
|
+
from the existing docstrings for all four modules: libvirt (main API),
|
|
96
|
+
libvirt_qemu, libvirt_lxc, and libvirtaio.
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
2026- 8- 3 Daniel P. Berrangé <berrange@redhat.com>
|
|
101
|
+
|
|
102
|
+
Declare python 3.9 as min required
|
|
103
|
+
This is a side effect of the mypy type annotations changed in
|
|
104
|
+
|
|
105
|
+
https://gitlab.com/libvirt/libvirt-python/-/merge_requests/208
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
2026- 8- 3 Jiri Denemark <jdenemar@redhat.com>
|
|
110
|
+
|
|
111
|
+
Post-release version bump to 12.7.0
|
|
112
|
+
|
|
113
|
+
|
|
1
114
|
2026- 7- 28 Daniel P. Berrangé <berrange@redhat.com>
|
|
2
115
|
|
|
3
116
|
Use lowercase types for collection types
|
|
@@ -36,3 +36,23 @@ hand written source files
|
|
|
36
36
|
the virStoragePool class
|
|
37
37
|
- libvirt-override-virStream.py - high level overrides in
|
|
38
38
|
the virStream class
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
Building API Documentation
|
|
43
|
+
==========================
|
|
44
|
+
|
|
45
|
+
The Python API reference is built with Sphinx using the autodoc
|
|
46
|
+
extension. Since the Python modules are generated at build time
|
|
47
|
+
from XML API descriptions, the package must be compiled before
|
|
48
|
+
Sphinx can import anything.
|
|
49
|
+
|
|
50
|
+
$ python -m venv docs-venv --system-site-packages --symlinks
|
|
51
|
+
$ source docs-venv/bin/activate
|
|
52
|
+
$ python -m pip install setuptools build
|
|
53
|
+
$ python -m pip install -r requirements-docs.txt
|
|
54
|
+
$ python -m build -n -x
|
|
55
|
+
$ python -m pip install dist/libvirt_python*.whl
|
|
56
|
+
$ python -m sphinx -b html docs/ py_api_docs
|
|
57
|
+
|
|
58
|
+
The rendered HTML will be in the py_api_docs/ directory.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: libvirt-python
|
|
3
|
-
Version: 12.
|
|
3
|
+
Version: 12.7.0
|
|
4
4
|
Summary: The libvirt virtualization API python binding
|
|
5
5
|
Home-page: http://www.libvirt.org
|
|
6
6
|
Maintainer: Libvirt Maintainers
|
|
@@ -9,7 +9,7 @@ License: LGPL-v2.0-or-later
|
|
|
9
9
|
Classifier: Development Status :: 5 - Production/Stable
|
|
10
10
|
Classifier: Intended Audience :: Developers
|
|
11
11
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
12
|
-
Requires-Python: >=3.
|
|
12
|
+
Requires-Python: >=3.9
|
|
13
13
|
Description-Content-Type: text/x-rst
|
|
14
14
|
License-File: COPYING
|
|
15
15
|
Dynamic: license-file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
12.7.0
|
|
@@ -1696,6 +1696,9 @@ static virPyTypedParamsHint virPyDomainSetIOThreadParams[] = {
|
|
|
1696
1696
|
{ VIR_DOMAIN_IOTHREAD_THREAD_POOL_MIN, VIR_TYPED_PARAM_INT },
|
|
1697
1697
|
{ VIR_DOMAIN_IOTHREAD_THREAD_POOL_MAX, VIR_TYPED_PARAM_INT },
|
|
1698
1698
|
# endif /* LIBVIR_CHECK_VERSION(8, 5, 0) */
|
|
1699
|
+
# if LIBVIR_CHECK_VERSION(12, 7, 0)
|
|
1700
|
+
{ VIR_DOMAIN_IOTHREAD_POLL_WEIGHT, VIR_TYPED_PARAM_UINT },
|
|
1701
|
+
# endif /* LIBVIR_CHECK_VERSION(12, 7, 0) */
|
|
1699
1702
|
};
|
|
1700
1703
|
|
|
1701
1704
|
static PyObject *
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
# This spec file assumes you are building on a Fedora or RHEL version
|
|
4
4
|
# that's still supported by the vendor. It may work on other distros
|
|
5
5
|
# or versions, but no effort will be made to ensure that going forward
|
|
6
|
-
%define min_rhel
|
|
7
|
-
%define min_fedora
|
|
6
|
+
%define min_rhel 9
|
|
7
|
+
%define min_fedora 43
|
|
8
8
|
|
|
9
9
|
%if (0%{?fedora} && 0%{?fedora} >= %{min_fedora}) || (0%{?rhel} && 0%{?rhel} >= %{min_rhel})
|
|
10
10
|
%define supported_platform 1
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
Summary: The libvirt virtualization API python3 binding
|
|
18
18
|
Name: libvirt-python
|
|
19
|
-
Version: 12.
|
|
19
|
+
Version: 12.7.0
|
|
20
20
|
Release: 1%{?dist}
|
|
21
21
|
Source0: https://libvirt.org/sources/python/%{dist_name}-%{version}.tar.gz
|
|
22
22
|
Url: https://libvirt.org
|
|
@@ -25,7 +25,6 @@ BuildRequires: libvirt-devel == %{version}
|
|
|
25
25
|
BuildRequires: python3-devel
|
|
26
26
|
BuildRequires: python3-pytest
|
|
27
27
|
BuildRequires: python3-lxml
|
|
28
|
-
BuildRequires: python3-setuptools
|
|
29
28
|
BuildRequires: gcc
|
|
30
29
|
|
|
31
30
|
# Don't want provides for python shared objects
|
|
@@ -59,31 +58,26 @@ of recent versions of Linux (and other OSes).
|
|
|
59
58
|
# for the -python3 package
|
|
60
59
|
find examples -type f -exec chmod 0644 \{\} \;
|
|
61
60
|
|
|
61
|
+
%generate_buildrequires
|
|
62
|
+
%pyproject_buildrequires
|
|
63
|
+
|
|
62
64
|
%build
|
|
63
65
|
%if ! %{supported_platform}
|
|
64
66
|
echo "This RPM requires either Fedora >= %{min_fedora} or RHEL >= %{min_rhel}"
|
|
65
67
|
exit 1
|
|
66
68
|
%endif
|
|
67
69
|
|
|
68
|
-
%
|
|
70
|
+
%pyproject_wheel
|
|
69
71
|
|
|
70
72
|
%install
|
|
71
|
-
%
|
|
73
|
+
%pyproject_install
|
|
74
|
+
%pyproject_save_files libvirt libvirt_lxc libvirt_qemu libvirtaio 'libvirtmod*'
|
|
72
75
|
|
|
73
76
|
%check
|
|
77
|
+
%pyproject_check_import
|
|
74
78
|
%pytest
|
|
75
79
|
|
|
76
|
-
%files -n python3-libvirt
|
|
80
|
+
%files -n python3-libvirt -f %{pyproject_files}
|
|
77
81
|
%doc ChangeLog AUTHORS README COPYING examples/
|
|
78
|
-
%{python3_sitearch}/libvirt.py*
|
|
79
|
-
%{python3_sitearch}/libvirtaio.py*
|
|
80
|
-
%{python3_sitearch}/libvirt_qemu.py*
|
|
81
|
-
%{python3_sitearch}/libvirt_lxc.py*
|
|
82
|
-
%{python3_sitearch}/__pycache__/libvirt.cpython-*.py*
|
|
83
|
-
%{python3_sitearch}/__pycache__/libvirt_qemu.cpython-*.py*
|
|
84
|
-
%{python3_sitearch}/__pycache__/libvirt_lxc.cpython-*.py*
|
|
85
|
-
%{python3_sitearch}/__pycache__/libvirtaio.cpython-*.py*
|
|
86
|
-
%{python3_sitearch}/libvirtmod*
|
|
87
|
-
%{python3_sitearch}/*egg-info
|
|
88
82
|
|
|
89
83
|
%changelog
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import libvirt
|
|
3
|
+
import tempfile
|
|
4
|
+
import contextlib
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestLibvirtConn(unittest.TestCase):
|
|
9
|
+
def setUp(self):
|
|
10
|
+
self.conn = libvirt.open("test:///default")
|
|
11
|
+
|
|
12
|
+
def tearDown(self):
|
|
13
|
+
self.conn = None
|
|
14
|
+
|
|
15
|
+
def testConnDomainList(self):
|
|
16
|
+
doms = self.conn.listAllDomains()
|
|
17
|
+
self.assertEqual(len(doms), 1)
|
|
18
|
+
self.assertEqual(type(doms[0]), libvirt.virDomain)
|
|
19
|
+
self.assertEqual(doms[0].name(), "test")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class TestLibvirtConnMetadata(unittest.TestCase):
|
|
23
|
+
"""Connection metadata and lifecycle tests"""
|
|
24
|
+
|
|
25
|
+
def setUp(self):
|
|
26
|
+
self.conn = libvirt.open("test:///default")
|
|
27
|
+
|
|
28
|
+
def tearDown(self):
|
|
29
|
+
self.conn = None
|
|
30
|
+
|
|
31
|
+
def testConnGetURI(self):
|
|
32
|
+
uri = self.conn.getURI()
|
|
33
|
+
|
|
34
|
+
self.assertIsInstance(uri, str)
|
|
35
|
+
self.assertEqual(uri, "test:///default")
|
|
36
|
+
|
|
37
|
+
def testConnGetHostname(self):
|
|
38
|
+
hostname = self.conn.getHostname()
|
|
39
|
+
|
|
40
|
+
self.assertIsInstance(hostname, str)
|
|
41
|
+
self.assertGreater(len(hostname), 0)
|
|
42
|
+
|
|
43
|
+
def testConnGetLibVersion(self):
|
|
44
|
+
version = self.conn.getLibVersion()
|
|
45
|
+
|
|
46
|
+
self.assertIsInstance(version, int)
|
|
47
|
+
self.assertGreater(version, 0)
|
|
48
|
+
|
|
49
|
+
def testConnGetVersion(self):
|
|
50
|
+
"""test driver reports hypervisor version 2"""
|
|
51
|
+
version = self.conn.getVersion()
|
|
52
|
+
|
|
53
|
+
self.assertIsInstance(version, int)
|
|
54
|
+
self.assertEqual(version, 2)
|
|
55
|
+
|
|
56
|
+
def testConnGetType(self):
|
|
57
|
+
"""test driver reports type TEST"""
|
|
58
|
+
hv_type = self.conn.getType()
|
|
59
|
+
|
|
60
|
+
self.assertIsInstance(hv_type, str)
|
|
61
|
+
self.assertEqual(hv_type, "TEST")
|
|
62
|
+
|
|
63
|
+
def testConnIsAlive(self):
|
|
64
|
+
self.assertTrue(self.conn.isAlive())
|
|
65
|
+
|
|
66
|
+
def testConnIsEncrypted(self):
|
|
67
|
+
result = self.conn.isEncrypted()
|
|
68
|
+
|
|
69
|
+
self.assertIsInstance(result, (bool, int))
|
|
70
|
+
self.assertFalse(result)
|
|
71
|
+
|
|
72
|
+
def testConnIsSecure(self):
|
|
73
|
+
result = self.conn.isSecure()
|
|
74
|
+
|
|
75
|
+
self.assertIsInstance(result, (bool, int))
|
|
76
|
+
self.assertTrue(result)
|
|
77
|
+
|
|
78
|
+
def testConnClose(self):
|
|
79
|
+
self.assertTrue(self.conn.isAlive())
|
|
80
|
+
|
|
81
|
+
ret = self.conn.close()
|
|
82
|
+
self.assertEqual(ret, 0)
|
|
83
|
+
|
|
84
|
+
with self.assertRaises(libvirt.libvirtError):
|
|
85
|
+
self.conn.isAlive()
|
|
86
|
+
|
|
87
|
+
def testConnContextManager(self):
|
|
88
|
+
with libvirt.open("test:///default") as conn:
|
|
89
|
+
self.assertEqual(conn.getURI(), "test:///default")
|
|
90
|
+
self.assertTrue(conn.isAlive())
|
|
91
|
+
|
|
92
|
+
with self.assertRaises(libvirt.libvirtError):
|
|
93
|
+
conn.isAlive()
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class TestLibvirtConnOpenNegative(unittest.TestCase):
|
|
97
|
+
"""Connection open failure for an invalid URI"""
|
|
98
|
+
|
|
99
|
+
def testOpenFails(self):
|
|
100
|
+
with self.assertRaises(libvirt.libvirtError) as ctx:
|
|
101
|
+
libvirt.open("not-a-valid-libvirt-uri")
|
|
102
|
+
|
|
103
|
+
self.assertIsNotNone(ctx.exception.get_error_message())
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class TestLibvirtConnReadOnly(unittest.TestCase):
|
|
107
|
+
"""Read-only libvirt.openReadOnly() connection tests"""
|
|
108
|
+
|
|
109
|
+
DEFINE_XML = """
|
|
110
|
+
<domain type='test'>
|
|
111
|
+
<name>test-define-temp</name>
|
|
112
|
+
<uuid>12345678-1234-1234-1234-123456789abc</uuid>
|
|
113
|
+
<memory unit='KiB'>524288</memory>
|
|
114
|
+
<vcpu>1</vcpu>
|
|
115
|
+
<os>
|
|
116
|
+
<type>hvm</type>
|
|
117
|
+
</os>
|
|
118
|
+
</domain>
|
|
119
|
+
"""
|
|
120
|
+
|
|
121
|
+
def setUp(self):
|
|
122
|
+
self.conn = libvirt.openReadOnly("test:///default")
|
|
123
|
+
|
|
124
|
+
def tearDown(self):
|
|
125
|
+
self.conn = None
|
|
126
|
+
|
|
127
|
+
def testOpenReadOnlySucceeds(self):
|
|
128
|
+
self.assertIsNotNone(self.conn)
|
|
129
|
+
self.assertTrue(self.conn.isAlive())
|
|
130
|
+
|
|
131
|
+
def testReadOnlyGetURI(self):
|
|
132
|
+
self.assertEqual(self.conn.getURI(), "test:///default")
|
|
133
|
+
|
|
134
|
+
def testReadOnlyGetType(self):
|
|
135
|
+
self.assertEqual(self.conn.getType(), "TEST")
|
|
136
|
+
|
|
137
|
+
def testReadOnlyListDomains(self):
|
|
138
|
+
domains = self.conn.listAllDomains()
|
|
139
|
+
|
|
140
|
+
self.assertIsInstance(domains, list)
|
|
141
|
+
self.assertGreater(len(domains), 0)
|
|
142
|
+
self.assertIsInstance(domains[0], libvirt.virDomain)
|
|
143
|
+
|
|
144
|
+
def testReadOnlyLookupAndInfo(self):
|
|
145
|
+
dom = self.conn.lookupByName("test")
|
|
146
|
+
|
|
147
|
+
self.assertEqual(dom.name(), "test")
|
|
148
|
+
|
|
149
|
+
info = dom.info()
|
|
150
|
+
self.assertIsInstance(info, (tuple, list))
|
|
151
|
+
self.assertEqual(len(info), 5)
|
|
152
|
+
|
|
153
|
+
state, _ = dom.state()
|
|
154
|
+
self.assertIsInstance(state, int)
|
|
155
|
+
|
|
156
|
+
def testReadOnlyXMLDesc(self):
|
|
157
|
+
dom = self.conn.lookupByName("test")
|
|
158
|
+
xml = dom.XMLDesc(0)
|
|
159
|
+
|
|
160
|
+
self.assertIsInstance(xml, str)
|
|
161
|
+
self.assertIn("<domain", xml)
|
|
162
|
+
|
|
163
|
+
def testReadOnlyDefineXMLDenied(self):
|
|
164
|
+
with self.assertRaises(libvirt.libvirtError) as ctx:
|
|
165
|
+
self.conn.defineXML(self.DEFINE_XML)
|
|
166
|
+
|
|
167
|
+
self.assertEqual(ctx.exception.get_error_code(),
|
|
168
|
+
libvirt.VIR_ERR_OPERATION_DENIED)
|
|
169
|
+
|
|
170
|
+
def testReadOnlyDestroyDenied(self):
|
|
171
|
+
dom = self.conn.lookupByName("test")
|
|
172
|
+
|
|
173
|
+
with self.assertRaises(libvirt.libvirtError) as ctx:
|
|
174
|
+
dom.destroy()
|
|
175
|
+
|
|
176
|
+
self.assertEqual(ctx.exception.get_error_code(),
|
|
177
|
+
libvirt.VIR_ERR_OPERATION_DENIED)
|
|
178
|
+
|
|
179
|
+
def testReadOnlyXMLDescSecureDenied(self):
|
|
180
|
+
dom = self.conn.lookupByName("test")
|
|
181
|
+
|
|
182
|
+
with self.assertRaises(libvirt.libvirtError) as ctx:
|
|
183
|
+
dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE)
|
|
184
|
+
|
|
185
|
+
self.assertEqual(ctx.exception.get_error_code(),
|
|
186
|
+
libvirt.VIR_ERR_OPERATION_DENIED)
|
|
187
|
+
|
|
188
|
+
def testReadOnlyContextManager(self):
|
|
189
|
+
with libvirt.openReadOnly("test:///default") as conn:
|
|
190
|
+
self.assertEqual(conn.getURI(), "test:///default")
|
|
191
|
+
self.assertTrue(conn.isAlive())
|
|
192
|
+
|
|
193
|
+
with self.assertRaises(libvirt.libvirtError):
|
|
194
|
+
conn.isAlive()
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class TestLibvirtConnAuth(unittest.TestCase):
|
|
198
|
+
connXML = """
|
|
199
|
+
<node>
|
|
200
|
+
<auth>
|
|
201
|
+
<user password="2147483647">marin</user>
|
|
202
|
+
<user password="87539319">srinivasa</user>
|
|
203
|
+
</auth>
|
|
204
|
+
</node>"""
|
|
205
|
+
def setUp(self):
|
|
206
|
+
def noop(msg, opaque):
|
|
207
|
+
pass
|
|
208
|
+
libvirt.registerErrorHandler(noop, None)
|
|
209
|
+
|
|
210
|
+
@contextlib.contextmanager
|
|
211
|
+
def tempxmlfile(content):
|
|
212
|
+
try:
|
|
213
|
+
fp = tempfile.NamedTemporaryFile(delete=False,
|
|
214
|
+
prefix="libvirt-python-test",
|
|
215
|
+
suffix=".xml")
|
|
216
|
+
fname = fp.name
|
|
217
|
+
fp.write(content.encode("utf8"))
|
|
218
|
+
fp.close()
|
|
219
|
+
yield fname
|
|
220
|
+
finally:
|
|
221
|
+
os.unlink(fname)
|
|
222
|
+
|
|
223
|
+
def authHelper(self, username, password):
|
|
224
|
+
with TestLibvirtConnAuth.tempxmlfile(self.connXML) as fname:
|
|
225
|
+
magic = 142857
|
|
226
|
+
def authCB(creds, opaque):
|
|
227
|
+
if opaque != magic:
|
|
228
|
+
return -1
|
|
229
|
+
|
|
230
|
+
for cred in creds:
|
|
231
|
+
if (cred[0] == libvirt.VIR_CRED_AUTHNAME and
|
|
232
|
+
username is not None):
|
|
233
|
+
cred[4] = username
|
|
234
|
+
return 0
|
|
235
|
+
elif (cred[0] == libvirt.VIR_CRED_PASSPHRASE and
|
|
236
|
+
password is not None):
|
|
237
|
+
cred[4] = password
|
|
238
|
+
return 0
|
|
239
|
+
return -1
|
|
240
|
+
return 0
|
|
241
|
+
|
|
242
|
+
auth = [[libvirt.VIR_CRED_AUTHNAME,
|
|
243
|
+
libvirt.VIR_CRED_ECHOPROMPT,
|
|
244
|
+
libvirt.VIR_CRED_REALM,
|
|
245
|
+
libvirt.VIR_CRED_PASSPHRASE,
|
|
246
|
+
libvirt.VIR_CRED_NOECHOPROMPT,
|
|
247
|
+
libvirt.VIR_CRED_EXTERNAL],
|
|
248
|
+
authCB, magic]
|
|
249
|
+
|
|
250
|
+
return libvirt.openAuth("test://" + fname,
|
|
251
|
+
auth, 0)
|
|
252
|
+
|
|
253
|
+
def testOpenAuthGood(self):
|
|
254
|
+
conn = self.authHelper("srinivasa", "87539319")
|
|
255
|
+
|
|
256
|
+
def testOpenAuthBad(self):
|
|
257
|
+
try:
|
|
258
|
+
conn = self.authHelper("srinivasa", "2147483647")
|
|
259
|
+
raise Exception("Unexpected open success")
|
|
260
|
+
except libvirt.libvirtError as ex:
|
|
261
|
+
pass
|
|
262
|
+
|
|
263
|
+
def testOpenAuthNone(self):
|
|
264
|
+
try:
|
|
265
|
+
conn = self.authHelper(None, None)
|
|
266
|
+
raise Exception("Unexpected open success")
|
|
267
|
+
except libvirt.libvirtError as ex:
|
|
268
|
+
pass
|
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
import libvirt
|
|
2
|
+
import unittest
|
|
3
|
+
|
|
4
|
+
from unittest.mock import patch, MagicMock
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestLibvirtDomainMigrationMocked(unittest.TestCase):
|
|
8
|
+
def setUp(self):
|
|
9
|
+
self.conn = libvirt.open("test:///default")
|
|
10
|
+
self.dom = self.conn.lookupByName("test")
|
|
11
|
+
|
|
12
|
+
def tearDown(self):
|
|
13
|
+
self.dom = None
|
|
14
|
+
self.conn = None
|
|
15
|
+
|
|
16
|
+
@patch("libvirtmod.virDomainMigrate3")
|
|
17
|
+
def testMigrate3LiveMigrationSuccess(self, mock_migrate3):
|
|
18
|
+
dst_conn = libvirt.open("test:///default")
|
|
19
|
+
dst_dom = dst_conn.lookupByName("test")
|
|
20
|
+
|
|
21
|
+
# A small hack to make virDomainFree work with mocked objects,
|
|
22
|
+
# the same applies to all tests in this set that return a domain pointer.
|
|
23
|
+
# Transfer ownership of the raw C pointer to the mock return value by
|
|
24
|
+
# setting _o to None so dst_dom.__del__ won't also call virDomainFree on it.
|
|
25
|
+
mock_migrate3.return_value = dst_dom._o
|
|
26
|
+
dst_dom._o = None
|
|
27
|
+
|
|
28
|
+
params = {
|
|
29
|
+
libvirt.VIR_MIGRATE_PARAM_URI: "qemu+ssh://desthost/system",
|
|
30
|
+
libvirt.VIR_MIGRATE_PARAM_BANDWIDTH: 1024,
|
|
31
|
+
}
|
|
32
|
+
flags = libvirt.VIR_MIGRATE_LIVE | libvirt.VIR_MIGRATE_PERSIST_DEST
|
|
33
|
+
|
|
34
|
+
result = self.dom.migrate3(dst_conn, params, flags)
|
|
35
|
+
|
|
36
|
+
self.assertIsInstance(result, libvirt.virDomain)
|
|
37
|
+
|
|
38
|
+
mock_migrate3.assert_called_once()
|
|
39
|
+
call_args = mock_migrate3.call_args
|
|
40
|
+
self.assertEqual(call_args[0][0], self.dom._o)
|
|
41
|
+
self.assertEqual(call_args[0][1], dst_conn._o)
|
|
42
|
+
self.assertEqual(call_args[0][3], flags)
|
|
43
|
+
|
|
44
|
+
dst_conn.close()
|
|
45
|
+
|
|
46
|
+
@patch("libvirtmod.virDomainMigrateToURI3")
|
|
47
|
+
def testMigrateToURI3PeerToPeerSuccess(self, mock_migrateToURI3):
|
|
48
|
+
mock_migrateToURI3.return_value = 0
|
|
49
|
+
|
|
50
|
+
dest_uri = "qemu+ssh://desthost/system"
|
|
51
|
+
params = {
|
|
52
|
+
libvirt.VIR_MIGRATE_PARAM_BANDWIDTH: 2048,
|
|
53
|
+
libvirt.VIR_MIGRATE_PARAM_DEST_NAME: "migrated-vm",
|
|
54
|
+
}
|
|
55
|
+
flags = libvirt.VIR_MIGRATE_LIVE | libvirt.VIR_MIGRATE_PEER2PEER
|
|
56
|
+
|
|
57
|
+
result = self.dom.migrateToURI3(dest_uri, params, flags)
|
|
58
|
+
|
|
59
|
+
self.assertEqual(result, 0)
|
|
60
|
+
|
|
61
|
+
mock_migrateToURI3.assert_called_once()
|
|
62
|
+
call_args = mock_migrateToURI3.call_args
|
|
63
|
+
self.assertEqual(call_args[0][0], self.dom._o)
|
|
64
|
+
self.assertEqual(call_args[0][1], dest_uri)
|
|
65
|
+
self.assertEqual(call_args[0][3], flags)
|
|
66
|
+
|
|
67
|
+
@patch("libvirtmod.virDomainMigrate3")
|
|
68
|
+
def testMigrate3OfflineMigration(self, mock_migrate3):
|
|
69
|
+
dst_conn = libvirt.open("test:///default")
|
|
70
|
+
dst_dom = dst_conn.lookupByName("test")
|
|
71
|
+
|
|
72
|
+
# domain must be inactive
|
|
73
|
+
if self.dom.isActive():
|
|
74
|
+
self.dom.destroy()
|
|
75
|
+
|
|
76
|
+
mock_migrate3.return_value = dst_dom._o
|
|
77
|
+
dst_dom._o = None
|
|
78
|
+
|
|
79
|
+
params = {}
|
|
80
|
+
flags = libvirt.VIR_MIGRATE_OFFLINE | libvirt.VIR_MIGRATE_PERSIST_DEST
|
|
81
|
+
|
|
82
|
+
result = self.dom.migrate3(dst_conn, params, flags)
|
|
83
|
+
|
|
84
|
+
self.assertIsInstance(result, libvirt.virDomain)
|
|
85
|
+
call_args = mock_migrate3.call_args
|
|
86
|
+
self.assertTrue(call_args[0][3] & libvirt.VIR_MIGRATE_OFFLINE)
|
|
87
|
+
|
|
88
|
+
dst_conn.close()
|
|
89
|
+
|
|
90
|
+
@patch("libvirtmod.virDomainMigrate3")
|
|
91
|
+
def testMigrate3WithCompressionParameters(self, mock_migrate3):
|
|
92
|
+
dst_conn = libvirt.open("test:///default")
|
|
93
|
+
dst_dom = dst_conn.lookupByName("test")
|
|
94
|
+
|
|
95
|
+
mock_migrate3.return_value = dst_dom._o
|
|
96
|
+
dst_dom._o = None
|
|
97
|
+
|
|
98
|
+
params = {
|
|
99
|
+
libvirt.VIR_MIGRATE_PARAM_BANDWIDTH: 1024,
|
|
100
|
+
libvirt.VIR_MIGRATE_PARAM_COMPRESSION: "mt",
|
|
101
|
+
libvirt.VIR_MIGRATE_PARAM_COMPRESSION_MT_LEVEL: 9,
|
|
102
|
+
libvirt.VIR_MIGRATE_PARAM_COMPRESSION_MT_THREADS: 4,
|
|
103
|
+
libvirt.VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS: 2,
|
|
104
|
+
}
|
|
105
|
+
flags = libvirt.VIR_MIGRATE_LIVE | libvirt.VIR_MIGRATE_COMPRESSED
|
|
106
|
+
|
|
107
|
+
result = self.dom.migrate3(dst_conn, params, flags)
|
|
108
|
+
|
|
109
|
+
self.assertIsInstance(result, libvirt.virDomain)
|
|
110
|
+
mock_migrate3.assert_called_once()
|
|
111
|
+
call_args = mock_migrate3.call_args
|
|
112
|
+
self.assertTrue(call_args[0][3] & libvirt.VIR_MIGRATE_COMPRESSED)
|
|
113
|
+
|
|
114
|
+
dst_conn.close()
|
|
115
|
+
|
|
116
|
+
@patch("libvirtmod.virDomainMigrateToURI3")
|
|
117
|
+
def testMigrateToURI3WithAutoConverge(self, mock_migrateToURI3):
|
|
118
|
+
mock_migrateToURI3.return_value = 0
|
|
119
|
+
|
|
120
|
+
params = {
|
|
121
|
+
libvirt.VIR_MIGRATE_PARAM_AUTO_CONVERGE_INITIAL: 20,
|
|
122
|
+
libvirt.VIR_MIGRATE_PARAM_AUTO_CONVERGE_INCREMENT: 10,
|
|
123
|
+
}
|
|
124
|
+
flags = (
|
|
125
|
+
libvirt.VIR_MIGRATE_LIVE
|
|
126
|
+
| libvirt.VIR_MIGRATE_PEER2PEER
|
|
127
|
+
| libvirt.VIR_MIGRATE_AUTO_CONVERGE
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
result = self.dom.migrateToURI3("qemu+ssh://dest/system", params, flags)
|
|
131
|
+
|
|
132
|
+
self.assertEqual(result, 0)
|
|
133
|
+
mock_migrateToURI3.assert_called_once()
|
|
134
|
+
call_args = mock_migrateToURI3.call_args
|
|
135
|
+
self.assertTrue(call_args[0][3] & libvirt.VIR_MIGRATE_AUTO_CONVERGE)
|
|
136
|
+
|
|
137
|
+
@patch("libvirtmod.virDomainMigrate3")
|
|
138
|
+
def testMigrate3WithTLSParameters(self, mock_migrate3):
|
|
139
|
+
dst_conn = libvirt.open("test:///default")
|
|
140
|
+
dst_dom = dst_conn.lookupByName("test")
|
|
141
|
+
|
|
142
|
+
mock_migrate3.return_value = dst_dom._o
|
|
143
|
+
dst_dom._o = None
|
|
144
|
+
|
|
145
|
+
params = {
|
|
146
|
+
libvirt.VIR_MIGRATE_PARAM_URI: "qemu+ssh://desthost/system",
|
|
147
|
+
libvirt.VIR_MIGRATE_PARAM_TLS_DESTINATION: "desthost.example.com",
|
|
148
|
+
}
|
|
149
|
+
flags = libvirt.VIR_MIGRATE_LIVE | libvirt.VIR_MIGRATE_TLS
|
|
150
|
+
|
|
151
|
+
result = self.dom.migrate3(dst_conn, params, flags)
|
|
152
|
+
|
|
153
|
+
self.assertIsInstance(result, libvirt.virDomain)
|
|
154
|
+
call_args = mock_migrate3.call_args
|
|
155
|
+
self.assertTrue(call_args[0][3] & libvirt.VIR_MIGRATE_TLS)
|
|
156
|
+
|
|
157
|
+
dst_conn.close()
|
|
158
|
+
|
|
159
|
+
@patch("libvirtmod.virDomainMigrateToURI3")
|
|
160
|
+
def testMigrateToURI3WithParallelConnections(self, mock_migrateToURI3):
|
|
161
|
+
mock_migrateToURI3.return_value = 0
|
|
162
|
+
|
|
163
|
+
params = {
|
|
164
|
+
libvirt.VIR_MIGRATE_PARAM_PARALLEL_CONNECTIONS: 4,
|
|
165
|
+
libvirt.VIR_MIGRATE_PARAM_BANDWIDTH: 4096,
|
|
166
|
+
}
|
|
167
|
+
flags = (
|
|
168
|
+
libvirt.VIR_MIGRATE_LIVE
|
|
169
|
+
| libvirt.VIR_MIGRATE_PEER2PEER
|
|
170
|
+
| libvirt.VIR_MIGRATE_PARALLEL
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
result = self.dom.migrateToURI3("qemu+ssh://dest/system", params, flags)
|
|
174
|
+
|
|
175
|
+
self.assertEqual(result, 0)
|
|
176
|
+
|
|
177
|
+
call_args = mock_migrateToURI3.call_args
|
|
178
|
+
self.assertTrue(call_args[0][3] & libvirt.VIR_MIGRATE_PARALLEL)
|
|
179
|
+
|
|
180
|
+
@patch("libvirtmod.virDomainMigrate3")
|
|
181
|
+
def testMigrate3EmptyParameterDict(self, mock_migrate3):
|
|
182
|
+
dst_conn = libvirt.open("test:///default")
|
|
183
|
+
dst_dom = dst_conn.lookupByName("test")
|
|
184
|
+
|
|
185
|
+
mock_migrate3.return_value = dst_dom._o
|
|
186
|
+
dst_dom._o = None
|
|
187
|
+
|
|
188
|
+
# Empty params dict
|
|
189
|
+
params = {}
|
|
190
|
+
flags = libvirt.VIR_MIGRATE_LIVE
|
|
191
|
+
|
|
192
|
+
result = self.dom.migrate3(dst_conn, params, flags)
|
|
193
|
+
|
|
194
|
+
self.assertIsInstance(result, libvirt.virDomain)
|
|
195
|
+
mock_migrate3.assert_called_once()
|
|
196
|
+
|
|
197
|
+
dst_conn.close()
|
|
198
|
+
|
|
199
|
+
@patch("libvirtmod.virDomainMigrate3")
|
|
200
|
+
def testMigrate3MultipleFlags(self, mock_migrate3):
|
|
201
|
+
dst_conn = libvirt.open("test:///default")
|
|
202
|
+
dst_dom = dst_conn.lookupByName("test")
|
|
203
|
+
|
|
204
|
+
mock_migrate3.return_value = dst_dom._o
|
|
205
|
+
dst_dom._o = None
|
|
206
|
+
|
|
207
|
+
params = {
|
|
208
|
+
libvirt.VIR_MIGRATE_PARAM_BANDWIDTH: 1024,
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
flags = (
|
|
212
|
+
libvirt.VIR_MIGRATE_LIVE
|
|
213
|
+
| libvirt.VIR_MIGRATE_PERSIST_DEST
|
|
214
|
+
| libvirt.VIR_MIGRATE_UNDEFINE_SOURCE
|
|
215
|
+
| libvirt.VIR_MIGRATE_COMPRESSED
|
|
216
|
+
| libvirt.VIR_MIGRATE_AUTO_CONVERGE
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
result = self.dom.migrate3(dst_conn, params, flags)
|
|
220
|
+
|
|
221
|
+
self.assertIsInstance(result, libvirt.virDomain)
|
|
222
|
+
|
|
223
|
+
call_args = mock_migrate3.call_args
|
|
224
|
+
passed_flags = call_args[0][3]
|
|
225
|
+
self.assertTrue(passed_flags & libvirt.VIR_MIGRATE_LIVE)
|
|
226
|
+
self.assertTrue(passed_flags & libvirt.VIR_MIGRATE_PERSIST_DEST)
|
|
227
|
+
self.assertTrue(passed_flags & libvirt.VIR_MIGRATE_UNDEFINE_SOURCE)
|
|
228
|
+
self.assertTrue(passed_flags & libvirt.VIR_MIGRATE_COMPRESSED)
|
|
229
|
+
self.assertTrue(passed_flags & libvirt.VIR_MIGRATE_AUTO_CONVERGE)
|
|
230
|
+
|
|
231
|
+
dst_conn.close()
|
|
232
|
+
|
|
233
|
+
@patch("libvirtmod.virDomainMigrate3")
|
|
234
|
+
def testMigrate3Failure(self, mock_migrate3):
|
|
235
|
+
dst_conn = libvirt.open("test:///default")
|
|
236
|
+
|
|
237
|
+
mock_migrate3.return_value = None
|
|
238
|
+
|
|
239
|
+
params = {}
|
|
240
|
+
flags = libvirt.VIR_MIGRATE_LIVE
|
|
241
|
+
|
|
242
|
+
# raise exception when C layer returns None
|
|
243
|
+
with self.assertRaises(libvirt.libvirtError) as ctx:
|
|
244
|
+
self.dom.migrate3(dst_conn, params, flags)
|
|
245
|
+
|
|
246
|
+
self.assertIn("virDomainMigrate3() failed", str(ctx.exception))
|
|
247
|
+
|
|
248
|
+
dst_conn.close()
|
|
249
|
+
|
|
250
|
+
@patch("libvirtmod.virDomainMigrateToURI3")
|
|
251
|
+
def testMigrateToURI3Failure(self, mock_migrateToURI3):
|
|
252
|
+
mock_migrateToURI3.return_value = -1
|
|
253
|
+
|
|
254
|
+
params = {}
|
|
255
|
+
flags = libvirt.VIR_MIGRATE_LIVE | libvirt.VIR_MIGRATE_PEER2PEER
|
|
256
|
+
|
|
257
|
+
# raise exception on failure
|
|
258
|
+
with self.assertRaises(libvirt.libvirtError):
|
|
259
|
+
self.dom.migrateToURI3("qemu+ssh://dest/system", params, flags)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
class TestLibvirtDomainMigrateLegacyMocked(unittest.TestCase):
|
|
263
|
+
"""Tests for the legacy virDomainMigrate and virDomainMigrate2 APIs.
|
|
264
|
+
|
|
265
|
+
Both virDomainMigrate and virDomainMigrate2 call independent C functionas
|
|
266
|
+
(libvirtmod.virDomainMigrate and libvirtmod.virDomainMigrate2) and have
|
|
267
|
+
their own wrapping logic, so they are tested separately from migrate3.
|
|
268
|
+
"""
|
|
269
|
+
|
|
270
|
+
def setUp(self):
|
|
271
|
+
self.conn = libvirt.open("test:///default")
|
|
272
|
+
self.dom = self.conn.lookupByName("test")
|
|
273
|
+
|
|
274
|
+
def tearDown(self):
|
|
275
|
+
self.dom = None
|
|
276
|
+
self.conn = None
|
|
277
|
+
|
|
278
|
+
@patch("libvirtmod.virDomainMigrate")
|
|
279
|
+
def testMigrateSuccess(self, mock_migrate):
|
|
280
|
+
dst_conn = libvirt.open("test:///default")
|
|
281
|
+
dst_dom = dst_conn.lookupByName("test")
|
|
282
|
+
|
|
283
|
+
mock_migrate.return_value = dst_dom._o
|
|
284
|
+
dst_dom._o = None
|
|
285
|
+
|
|
286
|
+
flags = libvirt.VIR_MIGRATE_LIVE | libvirt.VIR_MIGRATE_PERSIST_DEST
|
|
287
|
+
result = self.dom.migrate(dst_conn, flags, dname="migrated-vm",
|
|
288
|
+
uri="qemu+ssh://desthost/system", bandwidth=1024)
|
|
289
|
+
|
|
290
|
+
self.assertIsInstance(result, libvirt.virDomain)
|
|
291
|
+
mock_migrate.assert_called_once()
|
|
292
|
+
call_args = mock_migrate.call_args
|
|
293
|
+
self.assertEqual(call_args[0][0], self.dom._o)
|
|
294
|
+
self.assertEqual(call_args[0][1], dst_conn._o)
|
|
295
|
+
self.assertEqual(call_args[0][2], flags)
|
|
296
|
+
|
|
297
|
+
dst_conn.close()
|
|
298
|
+
|
|
299
|
+
@patch("libvirtmod.virDomainMigrate")
|
|
300
|
+
def testMigrateWithFlags(self, mock_migrate):
|
|
301
|
+
dst_conn = libvirt.open("test:///default")
|
|
302
|
+
dst_dom = dst_conn.lookupByName("test")
|
|
303
|
+
|
|
304
|
+
mock_migrate.return_value = dst_dom._o
|
|
305
|
+
dst_dom._o = None
|
|
306
|
+
|
|
307
|
+
flags = (
|
|
308
|
+
libvirt.VIR_MIGRATE_LIVE
|
|
309
|
+
| libvirt.VIR_MIGRATE_PERSIST_DEST
|
|
310
|
+
| libvirt.VIR_MIGRATE_UNDEFINE_SOURCE
|
|
311
|
+
)
|
|
312
|
+
result = self.dom.migrate(dst_conn, flags)
|
|
313
|
+
|
|
314
|
+
self.assertIsInstance(result, libvirt.virDomain)
|
|
315
|
+
call_args = mock_migrate.call_args
|
|
316
|
+
passed_flags = call_args[0][2]
|
|
317
|
+
self.assertTrue(passed_flags & libvirt.VIR_MIGRATE_LIVE)
|
|
318
|
+
self.assertTrue(passed_flags & libvirt.VIR_MIGRATE_PERSIST_DEST)
|
|
319
|
+
self.assertTrue(passed_flags & libvirt.VIR_MIGRATE_UNDEFINE_SOURCE)
|
|
320
|
+
|
|
321
|
+
dst_conn.close()
|
|
322
|
+
|
|
323
|
+
@patch("libvirtmod.virDomainMigrate")
|
|
324
|
+
def testMigrateFailure(self, mock_migrate):
|
|
325
|
+
dst_conn = libvirt.open("test:///default")
|
|
326
|
+
|
|
327
|
+
mock_migrate.return_value = None
|
|
328
|
+
|
|
329
|
+
with self.assertRaises(libvirt.libvirtError) as ctx:
|
|
330
|
+
self.dom.migrate(dst_conn, libvirt.VIR_MIGRATE_LIVE)
|
|
331
|
+
|
|
332
|
+
self.assertIn("virDomainMigrate() failed", str(ctx.exception))
|
|
333
|
+
|
|
334
|
+
dst_conn.close()
|
|
335
|
+
|
|
336
|
+
@patch("libvirtmod.virDomainMigrate2")
|
|
337
|
+
def testMigrate2Success(self, mock_migrate2):
|
|
338
|
+
dst_conn = libvirt.open("test:///default")
|
|
339
|
+
dst_dom = dst_conn.lookupByName("test")
|
|
340
|
+
|
|
341
|
+
mock_migrate2.return_value = dst_dom._o
|
|
342
|
+
dst_dom._o = None
|
|
343
|
+
|
|
344
|
+
dxml = "<domain type='test'><name>migrated-vm</name></domain>"
|
|
345
|
+
flags = libvirt.VIR_MIGRATE_LIVE | libvirt.VIR_MIGRATE_PERSIST_DEST
|
|
346
|
+
result = self.dom.migrate2(dst_conn, dxml=dxml, flags=flags,
|
|
347
|
+
dname="migrated-vm")
|
|
348
|
+
|
|
349
|
+
self.assertIsInstance(result, libvirt.virDomain)
|
|
350
|
+
mock_migrate2.assert_called_once()
|
|
351
|
+
call_args = mock_migrate2.call_args
|
|
352
|
+
self.assertEqual(call_args[0][0], self.dom._o)
|
|
353
|
+
self.assertEqual(call_args[0][1], dst_conn._o)
|
|
354
|
+
self.assertEqual(call_args[0][2], dxml)
|
|
355
|
+
self.assertEqual(call_args[0][3], flags)
|
|
356
|
+
|
|
357
|
+
dst_conn.close()
|
|
358
|
+
|
|
359
|
+
@patch("libvirtmod.virDomainMigrate2")
|
|
360
|
+
def testMigrate2WithoutXML(self, mock_migrate2):
|
|
361
|
+
dst_conn = libvirt.open("test:///default")
|
|
362
|
+
dst_dom = dst_conn.lookupByName("test")
|
|
363
|
+
|
|
364
|
+
mock_migrate2.return_value = dst_dom._o
|
|
365
|
+
dst_dom._o = None
|
|
366
|
+
|
|
367
|
+
flags = libvirt.VIR_MIGRATE_LIVE
|
|
368
|
+
result = self.dom.migrate2(dst_conn, flags=flags)
|
|
369
|
+
|
|
370
|
+
self.assertIsInstance(result, libvirt.virDomain)
|
|
371
|
+
call_args = mock_migrate2.call_args
|
|
372
|
+
self.assertIsNone(call_args[0][2])
|
|
373
|
+
|
|
374
|
+
dst_conn.close()
|
|
375
|
+
|
|
376
|
+
@patch("libvirtmod.virDomainMigrate2")
|
|
377
|
+
def testMigrate2Failure(self, mock_migrate2):
|
|
378
|
+
dst_conn = libvirt.open("test:///default")
|
|
379
|
+
|
|
380
|
+
mock_migrate2.return_value = None
|
|
381
|
+
|
|
382
|
+
with self.assertRaises(libvirt.libvirtError) as ctx:
|
|
383
|
+
self.dom.migrate2(dst_conn, flags=libvirt.VIR_MIGRATE_LIVE)
|
|
384
|
+
|
|
385
|
+
self.assertIn("virDomainMigrate2() failed", str(ctx.exception))
|
|
386
|
+
|
|
387
|
+
dst_conn.close()
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
if __name__ == "__main__":
|
|
391
|
+
unittest.main()
|
libvirt_python-12.6.0/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
12.6.0
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import unittest
|
|
2
|
-
import libvirt
|
|
3
|
-
import tempfile
|
|
4
|
-
import contextlib
|
|
5
|
-
import os
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class TestLibvirtConn(unittest.TestCase):
|
|
9
|
-
def setUp(self):
|
|
10
|
-
self.conn = libvirt.open("test:///default")
|
|
11
|
-
|
|
12
|
-
def tearDown(self):
|
|
13
|
-
self.conn = None
|
|
14
|
-
|
|
15
|
-
def testConnDomainList(self):
|
|
16
|
-
doms = self.conn.listAllDomains()
|
|
17
|
-
self.assertEqual(len(doms), 1)
|
|
18
|
-
self.assertEqual(type(doms[0]), libvirt.virDomain)
|
|
19
|
-
self.assertEqual(doms[0].name(), "test")
|
|
20
|
-
|
|
21
|
-
class TestLibvirtConnAuth(unittest.TestCase):
|
|
22
|
-
connXML = """
|
|
23
|
-
<node>
|
|
24
|
-
<auth>
|
|
25
|
-
<user password="2147483647">marin</user>
|
|
26
|
-
<user password="87539319">srinivasa</user>
|
|
27
|
-
</auth>
|
|
28
|
-
</node>"""
|
|
29
|
-
def setUp(self):
|
|
30
|
-
def noop(msg, opaque):
|
|
31
|
-
pass
|
|
32
|
-
libvirt.registerErrorHandler(noop, None)
|
|
33
|
-
|
|
34
|
-
@contextlib.contextmanager
|
|
35
|
-
def tempxmlfile(content):
|
|
36
|
-
try:
|
|
37
|
-
fp = tempfile.NamedTemporaryFile(delete=False,
|
|
38
|
-
prefix="libvirt-python-test",
|
|
39
|
-
suffix=".xml")
|
|
40
|
-
fname = fp.name
|
|
41
|
-
fp.write(content.encode("utf8"))
|
|
42
|
-
fp.close()
|
|
43
|
-
yield fname
|
|
44
|
-
finally:
|
|
45
|
-
os.unlink(fname)
|
|
46
|
-
|
|
47
|
-
def authHelper(self, username, password):
|
|
48
|
-
with TestLibvirtConnAuth.tempxmlfile(self.connXML) as fname:
|
|
49
|
-
magic = 142857
|
|
50
|
-
def authCB(creds, opaque):
|
|
51
|
-
if opaque != magic:
|
|
52
|
-
return -1
|
|
53
|
-
|
|
54
|
-
for cred in creds:
|
|
55
|
-
if (cred[0] == libvirt.VIR_CRED_AUTHNAME and
|
|
56
|
-
username is not None):
|
|
57
|
-
cred[4] = username
|
|
58
|
-
return 0
|
|
59
|
-
elif (cred[0] == libvirt.VIR_CRED_PASSPHRASE and
|
|
60
|
-
password is not None):
|
|
61
|
-
cred[4] = password
|
|
62
|
-
return 0
|
|
63
|
-
return -1
|
|
64
|
-
return 0
|
|
65
|
-
|
|
66
|
-
auth = [[libvirt.VIR_CRED_AUTHNAME,
|
|
67
|
-
libvirt.VIR_CRED_ECHOPROMPT,
|
|
68
|
-
libvirt.VIR_CRED_REALM,
|
|
69
|
-
libvirt.VIR_CRED_PASSPHRASE,
|
|
70
|
-
libvirt.VIR_CRED_NOECHOPROMPT,
|
|
71
|
-
libvirt.VIR_CRED_EXTERNAL],
|
|
72
|
-
authCB, magic]
|
|
73
|
-
|
|
74
|
-
return libvirt.openAuth("test://" + fname,
|
|
75
|
-
auth, 0)
|
|
76
|
-
|
|
77
|
-
def testOpenAuthGood(self):
|
|
78
|
-
conn = self.authHelper("srinivasa", "87539319")
|
|
79
|
-
|
|
80
|
-
def testOpenAuthBad(self):
|
|
81
|
-
try:
|
|
82
|
-
conn = self.authHelper("srinivasa", "2147483647")
|
|
83
|
-
raise Exception("Unexpected open success")
|
|
84
|
-
except libvirt.libvirtError as ex:
|
|
85
|
-
pass
|
|
86
|
-
|
|
87
|
-
def testOpenAuthNone(self):
|
|
88
|
-
try:
|
|
89
|
-
conn = self.authHelper(None, None)
|
|
90
|
-
raise Exception("Unexpected open success")
|
|
91
|
-
except libvirt.libvirtError as ex:
|
|
92
|
-
pass
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|