New upstream version 9.0.0
Guido Günther
1 year, 3 months ago
0 | ( | |
1 | (c-mode . ( | |
2 | (c-file-style . "K&R") | |
3 | (indent-tabs-mode . nil) | |
4 | (c-indent-level . 4) | |
5 | (c-basic-offset . 4) | |
6 | )) | |
7 | ) |
0 | --- | |
1 | # Configuration for Repo Lockdown - https://github.com/dessant/repo-lockdown | |
2 | ||
3 | name: 'Repo Lockdown' | |
4 | ||
5 | on: | |
6 | issues: | |
7 | types: opened | |
8 | pull_request_target: | |
9 | types: opened | |
10 | ||
11 | permissions: | |
12 | pull-requests: write | |
13 | issues: write | |
14 | ||
15 | jobs: | |
16 | action: | |
17 | runs-on: ubuntu-latest | |
18 | steps: | |
19 | - uses: dessant/repo-lockdown@v2 | |
20 | with: | |
21 | issue-comment: | | |
22 | Thank you for your interest in the libvirt project. | |
23 | ||
24 | Since this repository is a read-only mirror of the project's master | |
25 | repostory hosted on GitLab, issues opened here are not processed. | |
26 | ||
27 | We kindly request that new issues are reported to | |
28 | ||
29 | https://gitlab.com/libvirt/libvirt-python/-/issues/new | |
30 | ||
31 | Thank you for your time and understanding. | |
32 | lock-issue: true | |
33 | close-issue: true | |
34 | pr-comment: | | |
35 | Thank you for your interest in the libvirt project. | |
36 | ||
37 | Since this repository is a read-only mirror of the project's master | |
38 | repostory hosted on GitLab, merge requests opened here are not | |
39 | processed. | |
40 | ||
41 | We kindly request that contributors fork the project at | |
42 | ||
43 | https://gitlab.com/libvirt/libvirt-python/ | |
44 | ||
45 | push changes to the fork, and then open a new merge request at | |
46 | ||
47 | https://gitlab.com/libvirt/libvirt-python/-/merge_requests/new | |
48 | ||
49 | Thank you for your time and understanding. | |
50 | lock-pr: true | |
51 | close-pr: true |
0 | build/ | |
1 | dist/ | |
2 | MANIFEST | |
3 | *~ | |
4 | *#*# | |
5 | *.#*# | |
6 | *.py[cod] | |
7 | tags | |
8 | .tox | |
9 | dist/ | |
10 | eggs/ | |
11 | .eggs/ | |
12 | sdist/ | |
13 | *.egg-info/ | |
14 | *.egg |
0 | ||
1 | stages: | |
2 | - containers | |
3 | - builds | |
4 | - sanity_checks | |
5 | ||
6 | .git_build_vars: &git_build_vars | | |
7 | export MAKEFLAGS="-j$(getconf _NPROCESSORS_ONLN)" | |
8 | export SCRATCH_DIR="$PWD/scratch" | |
9 | export VROOT="$SCRATCH_DIR/vroot" | |
10 | export LIBDIR="$VROOT/lib" | |
11 | export LD_LIBRARY_PATH="$LIBDIR" | |
12 | export PATH="$VROOT/bin:$PATH" | |
13 | export PKG_CONFIG_PATH="$LIBDIR/pkgconfig" | |
14 | export CFLAGS="-Werror" | |
15 | ||
16 | .native_git_build_job: | |
17 | script: | |
18 | - *git_build_vars | |
19 | - pushd "$PWD" | |
20 | - mkdir -p "$SCRATCH_DIR" | |
21 | - cd "$SCRATCH_DIR" | |
22 | - git clone --depth 1 https://gitlab.com/libvirt/libvirt.git | |
23 | - cd libvirt | |
24 | - meson build -Ddriver_libvirtd=disabled "--prefix=$VROOT" "--libdir=$LIBDIR" | |
25 | - ninja -C build install | |
26 | - popd | |
27 | - $PYTHON setup.py build | |
28 | - $PYTHON -m pip install . | |
29 | - $PYTHON setup.py test | |
30 | - $PYTHON setup.py sdist | |
31 | - if test -x /usr/bin/rpmbuild && test "$RPM" != "skip" ; | |
32 | then | |
33 | rpmbuild --clean --nodeps --define "_topdir $PWD/rpmbuild" -ta dist/libvirt-python*tar.gz ; | |
34 | mv rpmbuild/RPMS/x86_64/ libvirt-python-rpms ; | |
35 | fi | |
36 | ||
37 | .native_git_build_job_prebuilt_env: | |
38 | extends: | |
39 | - .native_git_build_job | |
40 | - .gitlab_native_build_job_prebuilt_env | |
41 | ||
42 | .native_git_build_job_local_env: | |
43 | extends: | |
44 | - .native_git_build_job | |
45 | - .gitlab_native_build_job_local_env | |
46 | ||
47 | .native_build_job: | |
48 | script: | |
49 | - export MAKEFLAGS="-j$(getconf _NPROCESSORS_ONLN)" | |
50 | - export CFLAGS="-Werror" | |
51 | - $PYTHON setup.py build | |
52 | - $PYTHON -m pip install . | |
53 | - $PYTHON setup.py test | |
54 | - $PYTHON setup.py sdist | |
55 | - if test -x /usr/bin/rpmbuild && test "$RPM" != "skip" ; | |
56 | then | |
57 | rpmbuild --clean --nodeps --define "_topdir $PWD/rpmbuild" -ta dist/libvirt-python*tar.gz ; | |
58 | mv rpmbuild/RPMS/x86_64/ libvirt-python-rpms ; | |
59 | fi | |
60 | ||
61 | .native_build_job_prebuilt_env: | |
62 | extends: | |
63 | - .native_build_job | |
64 | - .gitlab_native_build_job_prebuilt_env | |
65 | ||
66 | .native_build_job_local_env: | |
67 | extends: | |
68 | - .native_build_job | |
69 | - .gitlab_native_build_job_local_env | |
70 | ||
71 | include: '/ci/gitlab.yml' | |
72 | ||
73 | .api_coverage_job: | |
74 | stage: sanity_checks | |
75 | script: | |
76 | - *git_build_vars | |
77 | - LIBVIRT_API_COVERAGE=1 $PYTHON setup.py test | |
78 | allow_failure: true | |
79 | ||
80 | api_coverage_prebuilt_env: | |
81 | extends: | |
82 | - .gitlab_native_build_job_prebuilt_env | |
83 | - .api_coverage_job | |
84 | needs: | |
85 | - job: x86_64-centos-stream-8-git-prebuilt-env | |
86 | artifacts: true | |
87 | variables: | |
88 | NAME: centos-stream-8 | |
89 | ||
90 | api_coverage_local_env: | |
91 | extends: | |
92 | - .gitlab_native_build_job_local_env | |
93 | - .api_coverage_job | |
94 | needs: | |
95 | - job: x86_64-centos-stream-8-git-local-env | |
96 | artifacts: true | |
97 | variables: | |
98 | IMAGE: quay.io/centos/centos:stream8 | |
99 | NAME: centos-stream-8 |
0 | # 'git shortlog --help' and look for mailmap for the format of each line | |
1 | ||
2 | # Email consolidation: | |
3 | # <Preferred address in AUTHORS> <other alias used by same author> | |
4 | ||
5 | <jdenemar@redhat.com> <Jiri.Denemark@gmail.com> | |
6 | <jfehlig@suse.com> <jfehlig@novell.com> | |
7 | <stefanb@us.ibm.com> <stefanb@linux.vnet.ibm.com> | |
8 | ||
9 | # Name consolidation: | |
10 | # Preferred author spelling <preferred email> | |
11 | Alex Jia <ajia@redhat.com> | |
12 | Ján Tomko <jtomko@redhat.com> | |
13 | MATSUDA Daiki <matsudadik@intellilink.co.jp> | |
14 | Serge E. Hallyn <serge.hallyn@canonical.com> | |
15 | Philipp Hahn <hahn@univention.de> |
11 | 11 | Adam Litke <agl@us.ibm.com> |
12 | 12 | Alex Jia <ajia@redhat.com> |
13 | 13 | Andrea Bolognani <abologna@redhat.com> |
14 | Bastian Germann <bage@linutronix.de> | |
14 | 15 | Beraldo Leal <bleal@redhat.com> |
15 | 16 | Boris Fiuczynski <fiuczy@linux.vnet.ibm.com> |
16 | 17 | Brian Rak <brak@gameservers.com> |
18 | Chris Gunn <chrisgun@microsoft.com> | |
17 | 19 | Chris Lalancette <clalance@redhat.com> |
18 | 20 | Claudio Bley <cbley@av-test.de> |
19 | 21 | Cole Robinson <crobinso@redhat.com> |
29 | 31 | Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com> |
30 | 32 | Eric Blake <eblake@redhat.com> |
31 | 33 | Erik Skultety <eskultet@redhat.com> |
34 | Erik Skultety <eskultety@ridgehead.home.lan> | |
32 | 35 | Federico Simoncelli <fsimonce@redhat.com> |
33 | 36 | Giuseppe Scrivano <gscrivan@redhat.com> |
34 | 37 | Guan Qiang <hzguanqiang@corp.netease.com> |
72 | 75 | Peng Hao <peng.hao2@zte.com.cn> |
73 | 76 | Peter Krempa <pkrempa@redhat.com> |
74 | 77 | Philipp Hahn <hahn@univention.de> |
78 | Pino Toscano <ptoscano@redhat.com> | |
75 | 79 | Prabodh Agarwal <prabodh1194@users.noreply.github.com> |
76 | 80 | Pradipta Kr. Banerjee <pradipta.banerjee@gmail.com> |
77 | 81 | Qiaowei Ren <qiaowei.ren@intel.com> |
0 | Libvirt Python Binding Authors | |
1 | ============================== | |
2 | ||
3 | The libvirt python binding is maintained by the | |
4 | libvirt development team, who can be contacted | |
5 | at | |
6 | ||
7 | libvir-list@redhat.com | |
8 | ||
9 | The individual contributors are | |
10 | ||
11 | @AUTHORS@ |
0 | ============================== | |
1 | Contributing to libvirt-python | |
2 | ============================== | |
3 | ||
4 | The libvirt Python API binding accepts code contributions via merge requests | |
5 | on the GitLab project: | |
6 | ||
7 | https://gitlab.com/libvirt/libvirt-python/-/merge_requests | |
8 | ||
9 | It is required that automated CI pipelines succeed before a merge request | |
10 | will be accepted. The global pipeline status for the ``master`` branch is | |
11 | visible at: | |
12 | ||
13 | https://gitlab.com/libvirt/libvirt-python/pipelines | |
14 | ||
15 | CI pipeline results for merge requests will be visible via the contributors' | |
16 | own private repository fork: | |
17 | ||
18 | https://gitlab.com/yourusername/libvirt-python/pipelines | |
19 | ||
20 | Contributions submitted to the project must be in compliance with the | |
21 | Developer Certificate of Origin Version 1.1. This is documented at: | |
22 | ||
23 | https://developercertificate.org/ | |
24 | ||
25 | To indicate compliance, each commit in a series must have a "Signed-off-by" | |
26 | tag with the submitter's name and email address. This can be added by passing | |
27 | the ``-s`` flag to ``git commit`` when creating the patches. |
0 | 2023-01-12 Peter Krempa <pkrempa@redhat.com> | |
1 | ||
2 | override: domain: Implement override for virDomainFDAssociate | |
3 | The bindings generator can't generate proper bindings for FD passing so | |
4 | the bindings need to be implemented manually both the python wrapper and | |
5 | the C backend. | |
6 | ||
7 | ||
8 | ||
9 | 2023-01-06 Erik Skultety <eskultet@redhat.com> | |
10 | ||
11 | ci: manifest: Define RPM artifacts for regular CentOS Stream 8 build | |
12 | Commit 7360326 missed the fact that artifacts were only defined for the | |
13 | libvirt Git type of libvirt-python build (git is cloned, libvirt is | |
14 | built and then libvirt-python) based on the | |
15 | 'native_git_build_job_prebuilt_env' job template whereas libvirt CI | |
16 | expects the RPM artifacts to come from a job based on the | |
17 | 'native_build_job' template instead. | |
18 | ||
19 | Note that this patch is a hotfix to something which requires a proper | |
20 | cleanup to stay consistent with the way we're handling the same thing | |
21 | in libvirt-perl. | |
22 | ||
23 | ||
24 | ||
25 | 2023-01-06 Erik Skultety <eskultet@redhat.com> | |
26 | ||
27 | .gitignore: Ignore more common Python build artifacts | |
28 | ||
29 | ||
30 | 2023-01-05 Erik Skultety <eskultet@redhat.com> | |
31 | ||
32 | ci: manifest: Define artifacts cache | |
33 | After commit 6e0d4d53 we lost RPM artifacts cache breaking the whole | |
34 | integration CI. The reason for that is that we manually defined the | |
35 | artifacts cache in gitlab.yml instead of manifest.yml. Naturally with | |
36 | the next lcitool update, gitlab.yml got overwritten according to | |
37 | manifest.yml which didn't define any artifacts cache. | |
38 | ||
39 | Fixes: 6e0d4d53d51e8aa9d537e404a886eab131e311cc | |
40 | ||
41 | ||
42 | ||
43 | 2023-01-05 Erik Skultety <eskultet@redhat.com> | |
44 | ||
45 | ci: manifest: Replace 'expiry' with 'expire_in' | |
46 | 'expiry' isn't a keyword in lcitool anymore, the only reason why | |
47 | everything has kept working despite lcitool updates is that lcitool | |
48 | sets 'expire_in' to 2 days by default. | |
49 | ||
50 | ||
51 | ||
52 | 2023-01-04 Erik Skultety <eskultety@ridgehead.home.lan> | |
53 | ||
54 | ci: Refresh and add Fedora 37 target | |
55 | ||
56 | ||
57 | 2022-12-01 Jiri Denemark <jdenemar@redhat.com> | |
58 | ||
59 | Post-release version bump to 9.0.0 | |
60 | ||
61 | ||
62 | 2022-11-23 Daniel P. Berrangé <berrange@redhat.com> | |
63 | ||
64 | rpm: add explicit build dep on python3-setuptools | |
65 | We previously got this implicitly via a dep from python3-pytest | |
66 | so never noticed that it was missing. The implicit dep is going | |
67 | away in rawhide real soon. | |
68 | ||
69 | ||
70 | ||
71 | 2022-11-01 Jiri Denemark <jdenemar@redhat.com> | |
72 | ||
73 | Post-release version bump to 8.10.0 | |
74 | ||
75 | ||
76 | 2022-10-13 Peter Krempa <pkrempa@redhat.com> | |
77 | ||
78 | ci: Expose built RPMs as artifacts | |
79 | Expose the artifacts from the centos-stream-8/9 and fedora 35/36 jobs so | |
80 | that the main libvirt integration testing project can consume them. | |
81 | ||
82 | The new libvirt sub-rpm containing a python helper to access QMP | |
83 | directly requires python environment which we didn't yet install in the | |
84 | integration job. | |
85 | ||
86 | ||
87 | ||
88 | 2022-10-10 Chris Gunn <chrisgun@microsoft.com> | |
89 | ||
90 | Fix memory leak in libvirt_virStreamRecv. | |
91 | The libvirt_virStreamRecv function uses a temporary allocated buffer to | |
92 | receive data before copying the data into a Python byte array. But | |
93 | there are some error paths where this buffer is not freed. This change | |
94 | fixes that memory leak. | |
95 | ||
96 | ||
97 | ||
98 | 2022-10-03 Erik Skultety <eskultet@redhat.com> | |
99 | ||
100 | ci: Fix the stage of the api-coverage job | |
101 | The 'extends' stanza supports a list, however there's a merge algorithm | |
102 | in place where a subsequent list entry overwrites all conflicting | |
103 | settings from the previous one - which is exactly what happened here as | |
104 | the gitlab-build-{local,prebuilt}-env job template overwrote | |
105 | api-coverage's stage to 'builds' whereas the original was | |
106 | 'sanity_checks'. | |
107 | ||
108 | Fixes: 4733e2a2d13cb9a85127ba17c04cc29278b31e89 | |
109 | ||
110 | ||
111 | ||
112 | 2022-10-03 Jiri Denemark <jdenemar@redhat.com> | |
113 | ||
114 | Post-release version bump to 8.9.0 | |
115 | ||
116 | ||
117 | 2022-09-30 Daniel P. Berrangé <berrange@redhat.com> | |
118 | ||
119 | ci: refresh with latest lcitool manifest | |
120 | This refresh switches the CI for contributors to be triggered by merge | |
121 | requests. Pushing to a branch in a fork will no longer run CI pipelines, | |
122 | in order to avoid consuming CI minutes. To regain the original behaviour | |
123 | contributors can opt-in to a pipeline on push | |
124 | ||
125 | git push <remote> -o ci.variable=RUN_PIPELINE=1 | |
126 | ||
127 | This variable can also be set globally on the repository, though this is | |
128 | not recommended. Upstream repo pushes to branches will run CI. | |
129 | ||
130 | The use of containers has changed in this update, with only the upstream | |
131 | repo creating containers, in order to avoid consuming contributors' | |
132 | limited storage quotas. A fork with existing container images may delete | |
133 | them. Containers will be rebuilt upstream when pushing commits with CI | |
134 | changes to the default branch. Any other scenario with CI changes will | |
135 | simply install build pre-requisite packages in a throaway environment, | |
136 | using the ci/buildenv/ scripts. These scripts may also be used on a | |
137 | contributor's local machines. | |
138 | ||
139 | With pipelines triggered by merge requests, it is also now possible to | |
140 | workaround the inability of contributors to run pipelines if they have | |
141 | run out of CI quota. A project member can trigger a pipeline from the | |
142 | merge request, which will run in context of upstream, however, note | |
143 | this should only be done after reviewing the code for any malicious | |
144 | CI changes. | |
145 | ||
146 | ||
147 | ||
148 | 2022-09-09 Bastian Germann <bage@linutronix.de> | |
149 | ||
150 | Link libvirtmod_* modules also with libvirt | |
151 | The -lvirt linker flag has to be added to the libvirtmod_qemu and | |
152 | libvirtmod_lxc modules as well. | |
153 | ||
154 | ||
155 | ||
156 | 2022-09-09 Bastian Germann <bage@linutronix.de> | |
157 | ||
158 | Replace uint with unsigned int | |
159 | Mingw-w64 target does not support uint definition. | |
160 | ||
161 | ||
162 | ||
163 | 2022-09-01 Jiri Denemark <jdenemar@redhat.com> | |
164 | ||
165 | Post-release version bump to 8.8.0 | |
166 | ||
167 | ||
168 | 2022-08-01 Jiri Denemark <jdenemar@redhat.com> | |
169 | ||
170 | Post-release version bump to 8.7.0 | |
171 | ||
172 | ||
173 | 2022-07-08 Michal Privoznik <mprivozn@redhat.com> | |
174 | ||
175 | libvirt-utils: Clear error when guessing typed param type | |
176 | Our APIs which accept typed parameters are usually exposed in | |
177 | python as accepting dictionary, for instance: | |
178 | ||
179 | virDomainSetIOThreadParams(..., virTypedParameterPtr params, ...) -> | |
180 | virDomain.setIOThreadParams(..., {}, ...) | |
181 | ||
182 | Now, before calling the C API, the dictionary is processed by | |
183 | virPyDictToTypedParams() which accepts an additional argument: | |
184 | array that hints types for each typed parameter. However, if a | |
185 | key is not in the array we guess what the correct type might be. | |
186 | This is done by attempting conversion from python into string, if | |
187 | that fails then into boolean, then into long, only to fall back | |
188 | to double. Now, for the long type we can have two cases: the | |
189 | value is non-negative (ULL) or it is negative (LL). Therefore, we | |
190 | firstly attempt ULL case and if that fails we stick with the | |
191 | latter. | |
192 | ||
193 | However, after we attempted the ULL conversion, python records an | |
194 | error internally (which is then queried via PyErr_Occurred()), | |
195 | but the error is never cleared out. This leads to spurious paths | |
196 | taken afterwards: e.g. when libvirt_longlongUnwrap() is trying to | |
197 | convert -1, it fails. But not rightfully - the PyErr_Occurred() | |
198 | check it performs has nothing to do with any of its actions, | |
199 | rather than our guessing work done before. | |
200 | ||
201 | Therefore, clear the error after we've guessed the type. | |
202 | ||
203 | ||
204 | ||
205 | 2022-07-08 Michal Privoznik <mprivozn@redhat.com> | |
206 | ||
207 | Add VIR_DOMAIN_IOTHREAD_THREAD_POOL_{MIN,MAX} macros | |
208 | The python version of virDomainSetIOThreadParams | |
209 | (setIOThreadParams()), expects two arguments on input: the thread | |
210 | ID and a dictionary which is then translated into our typed | |
211 | parameters. During this translation we use a helper array which | |
212 | holds type for each typed parameter supported | |
213 | (virPyDomainSetIOThreadParams[]). Otherwise we guess what the | |
214 | correct type is. Now, when introducing | |
215 | VIR_DOMAIN_IOTHREAD_THREAD_POOL_{MIN,MAX} typed params into | |
216 | libvirt I forgot to update the array. Do that now. | |
217 | ||
218 | ||
219 | ||
220 | 2022-07-01 Jiri Denemark <jdenemar@redhat.com> | |
221 | ||
222 | Post-release version bump to 8.6.0 | |
223 | ||
224 | ||
225 | 2022-06-25 Pino Toscano <ptoscano@redhat.com> | |
226 | ||
227 | setup: make 'clean' command compatible again with distutils | |
228 | After the switch of 'my_clean' to a simple Command, the 'clean' command | |
229 | has no more bits for options, resulting in distutils (either external | |
230 | or embedded in setuptools) complaining about it: | |
231 | ||
232 | distutils.errors.DistutilsClassError: command class <class '__main__.my_clean'> must provide 'user_options' attribute (a list of tuples) | |
233 | ||
234 | To overcome that, provide all the standard bits from options, i.e. the | |
235 | 'user_options' list, and the 'initialize_options' & 'finalize_options' | |
236 | methods. In addition, add a dummy 'all' option, as distutils wants it: | |
237 | ||
238 | error: error in [...]/.pydistutils.cfg: command 'my_clean' has no such option 'all' | |
239 | ||
240 | Fixes commit a965c91c6fa1275613edbbef75c0422574eb9ff2 | |
241 | ||
242 | ||
243 | ||
244 | 2022-06-08 Daniel P. Berrangé <berrange@redhat.com> | |
245 | ||
246 | setup: advertize Python 3.9 and 3.10 support | |
247 | Add classifiers that indicate we intend to support python versions | |
248 | 3.9 and 3.10. | |
249 | ||
250 | ||
251 | ||
252 | 2022-06-08 Daniel P. Berrangé <berrange@redhat.com> | |
253 | ||
254 | examples: remove use of deprecated setDaemon method | |
255 | In Python 3.10 the setDaemon method was deprecated. It is redundant | |
256 | since the 'daemon' parameter can be given when creating the thread, | |
257 | or the 'daemon' attribute can be set after it was created. | |
258 | ||
259 | ||
260 | ||
261 | 2022-06-08 Daniel P. Berrangé <berrange@redhat.com> | |
262 | ||
263 | tests: expand AIO tests and add more comments | |
264 | Add a test for one more usage scenario that was possible in the past, | |
265 | whereby libvirt events are registered before starting the asyncio | |
266 | loop, but we let libvirt find the loop associated with the current | |
267 | thread. | |
268 | ||
269 | Skip the test relies on auto-creating an event loop with Python >= 3.10 | |
270 | since it now triggers a deprecation warning which will soon turn into a | |
271 | RuntimeError. | |
272 | ||
273 | ||
274 | ||
275 | 2022-06-08 Daniel P. Berrangé <berrange@redhat.com> | |
276 | ||
277 | tests: use mocks to allow calling virEventRegisterImpl many times | |
278 | We currently have to run each of the test_aio.py test cases in a | |
279 | separate process, because libvirt.virEventRegisterImpl can only be | |
280 | called once per process. This leads to quite unpleasant console | |
281 | output when running tests. | |
282 | ||
283 | By introducing a mock for libvirt.virEventRegisterImpl we can | |
284 | regain the ability to run everything in a single process. The only | |
285 | caveat is that it relies on tests to fully cleanup, but in practice | |
286 | this is ok for our current tests. | |
287 | ||
288 | ||
289 | ||
290 | 2022-06-08 Chris Gunn <chrisgun@microsoft.com> | |
291 | ||
292 | tests: add libvirtaio test coverage | |
293 | ||
294 | ||
295 | 2022-06-08 Daniel P. Berrangé <berrange@redhat.com> | |
296 | ||
297 | libvirtaio: add better docs on best practice usage pattern | |
298 | ||
299 | ||
300 | 2022-06-08 Daniel P. Berrangé <berrange@redhat.com> | |
301 | ||
302 | libvirtio: lazy create the Event object in drain() | |
303 | The drain method uses an asyncio.Event object to be notified when other | |
304 | coroutines have removed all registered callbacks. The Event object needs | |
305 | to be associated with the coroutine that the event loop is running with | |
306 | and currently this is achieved by passing in the 'loop' parameter. | |
307 | ||
308 | Unfortunately Python 3.10 has removed the 'loop' parameter and now the | |
309 | object is associated implicitly with the current thread's event loop. | |
310 | At the time the virEventAsyncIOImpl constructor is called, however, | |
311 | there is no guarantee that an event loop has been set for the thread. | |
312 | The explicitly passed in 'loop' parameter would handle this scenario. | |
313 | ||
314 | For portability with Python >= 3.10 we need to delay creation of the | |
315 | Event object until we have a guarantee that there is a loop associated | |
316 | with the current thread. This is achieved by lazily creating the Event | |
317 | object inside the 'drain' method, which is expected to be invoked from | |
318 | coroutine context and thus ensure a loop is associated. | |
319 | ||
320 | ||
321 | ||
322 | 2022-06-08 Chris Gunn <chrisgun@microsoft.com> | |
323 | ||
324 | libvirtaio: convert to using 'async' / 'await' syntax | |
325 | The 'async' keyword is new in Python 3.5, as a way to declare that a | |
326 | method is a coroutine. This replaces the '@asyncio.coroutine' decorator | |
327 | that is deprecated since 3.8 and scheduled to be removed in 3.11 | |
328 | ||
329 | The 'await' keyword has to be used instead of 'yield' from any | |
330 | coroutines declared with 'async'. | |
331 | ||
332 | [DB: Split off from a larger patch mixing multiple changes] | |
333 | ||
334 | ||
335 | 2022-06-08 Chris Gunn <chrisgun@microsoft.com> | |
336 | ||
337 | libvirtaio: drop back compat for python < 3.4.4 | |
338 | setup.py ensures we have python >= 3.5, so there is no need to do | |
339 | back compat with the 'asyncio.ensure_future' method, which was new | |
340 | in 3.4.4 | |
341 | ||
342 | [DB: Split off from a larger patch mixing multiple changes] | |
343 | ||
344 | ||
345 | 2022-06-01 Jiri Denemark <jdenemar@redhat.com> | |
346 | ||
347 | Post-release version bump to 8.5.0 | |
348 | ||
349 | ||
350 | 2022-05-13 Michal Privoznik <mprivozn@redhat.com> | |
351 | ||
352 | Add an override impl for virDomainRestoreParams and virDomainSaveParams | |
353 | ||
354 | ||
355 | 2022-05-02 Jiri Denemark <jdenemar@redhat.com> | |
356 | ||
357 | Post-release version bump to 8.4.0 | |
358 | ||
359 | ||
360 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
361 | ||
362 | setup: switch to running API coverage test using pytest | |
363 | The API coverage test is no longer a special case. | |
364 | ||
365 | ||
366 | ||
367 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
368 | ||
369 | sanitytest: skip tests when seeing broken lxml implementation | |
370 | The python lxml registers some global callbacks with libxml2. As a | |
371 | result when another user of libxml2 calls APIs, it can trigger the | |
372 | python callbacks that lxml previously registered. Execution of the | |
373 | python callbacks in this case is often unsafe and leads to SEGVs. | |
374 | ||
375 | This hasn't been a problem since the sanitytest.py test has been | |
376 | a standalone program we execute. When it gets turned into a real | |
377 | python unit test, it will run in the same process as all the other | |
378 | tests and trigger the crash. | |
379 | ||
380 | A mitigation was added in lxml 4.5.2 which is good enough to let | |
381 | us continuing using lxml. | |
382 | ||
383 | ||
384 | ||
385 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
386 | ||
387 | sanitytest: turn into a normal python unittest | |
388 | The sanitytest.py file is now using the normal python unittest | |
389 | pattern, though we invoke the one test explicitly for now. | |
390 | ||
391 | ||
392 | ||
393 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
394 | ||
395 | sanitytest: move function/enum identification into a helper method | |
396 | This is a step towards turning the sanitytest.py file into a normal | |
397 | python unittest. | |
398 | ||
399 | Best viewed with the '-b' flag to diff. | |
400 | ||
401 | ||
402 | ||
403 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
404 | ||
405 | sanitytest: move class identification into a helper method | |
406 | This is a step towards turning the sanitytest.py file into a normal | |
407 | python unittest. | |
408 | ||
409 | Best viewed with the '-b' flag to diff. | |
410 | ||
411 | ||
412 | ||
413 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
414 | ||
415 | sanitytest: move initial class method mapping into a helper method | |
416 | This is a step towards turning the sanitytest.py file into a normal | |
417 | python unittest. | |
418 | ||
419 | Best viewed with the '-b' flag to diff. | |
420 | ||
421 | ||
422 | ||
423 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
424 | ||
425 | sanitytest: move class method mapping fixup into a helper method | |
426 | This is a step towards turning the sanitytest.py file into a normal | |
427 | python unittest. | |
428 | ||
429 | Best viewed with the '-b' flag to diff. | |
430 | ||
431 | ||
432 | ||
433 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
434 | ||
435 | sanitytest: move C to python API mapping check into a helper method | |
436 | This is a step towards turning the sanitytest.py file into a normal | |
437 | python unittest. | |
438 | ||
439 | Best viewed with the '-b' flag to diff. | |
440 | ||
441 | ||
442 | ||
443 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
444 | ||
445 | sanitytest: move python to C API mapping check into a helper method | |
446 | This is a step towards turning the sanitytest.py file into a normal | |
447 | python unittest. | |
448 | ||
449 | Best viewed with the '-b' flag to diff. | |
450 | ||
451 | ||
452 | ||
453 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
454 | ||
455 | sanitytest: move C API binding check into a helper method | |
456 | This is a step towards turning the sanitytest.py file into a normal | |
457 | python unittest. | |
458 | ||
459 | Best viewed with the '-b' flag to diff. | |
460 | ||
461 | ||
462 | ||
463 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
464 | ||
465 | sanitytest: stop passing python module path into sanity test | |
466 | We want to move over to make sanitytest.py operate like a more normal | |
467 | test script, which means making it self contained. | |
468 | ||
469 | The setup.py already sets the PYTHONPATH thanks to changes introduced | |
470 | in: | |
471 | ||
472 | commit eaded7bdadf3ccdc4b208ec0ed65a1b23b8b5f69 | |
473 | Author: Daniel P. Berrange <berrange@redhat.com> | |
474 | Date: Tue Mar 18 11:11:48 2014 +0000 | |
475 | ||
476 | Add support for running unit tests with nose | |
477 | ||
478 | so passing the python module path into sanitytest.py is redundant. | |
479 | ||
480 | ||
481 | ||
482 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
483 | ||
484 | sanitytest: stop passing API XML path into sanity test | |
485 | We want to move over to make sanitytest.py operate like a more normal | |
486 | test script, which means making it self contained. | |
487 | ||
488 | The test already knows how to find the libvirt API XML path using | |
489 | pkg-config and if an override location is required, this can be done | |
490 | by pointing $PKG_CONFIG_PATH to a suitable place. | |
491 | ||
492 | ||
493 | ||
494 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
495 | ||
496 | setup: switch from distutils to setuptools | |
497 | The distutils package is deprecated and targetted for deletion in Python | |
498 | 3.12, so we need to switch to setuptools. Thanks to all the preceeding | |
499 | changes this is no more difficult than changing the import statements. | |
500 | ||
501 | Closes https://gitlab.com/libvirt/libvirt-python/-/issues/1 | |
502 | ||
503 | ||
504 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
505 | ||
506 | setup: remove use of distutils.util.get_platform | |
507 | The 'get_platform' function is used to determine the platform specific | |
508 | component of the build output directory containing the loadable | |
509 | modules and python code. There is no nice replacement for this | |
510 | function, but we can achieve our goal by simply scaning for the desired | |
511 | subdirectory, which should exist by the time 'test' runs. | |
512 | ||
513 | ||
514 | ||
515 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
516 | ||
517 | setup: override 'build_ext' / 'build_py' commands rather than 'build' | |
518 | We override the 'build' command to invoke the code generator before the | |
519 | extensions are compiled. The 'build' command, however, is merely a | |
520 | wrapper around several other commands. It is possible for the user to | |
521 | directly invoke those commands, in which case our code generator won't | |
522 | get a chance to run: | |
523 | ||
524 | $ python setup.py build_ext | |
525 | running build_ext | |
526 | building 'libvirtmod' extension | |
527 | creating build/temp.linux-x86_64-3.10 | |
528 | creating build/temp.linux-x86_64-3.10/build | |
529 | gcc ..snip... -c build/libvirt.c -o build/temp.linux-x86_64-3.10/build/libvirt.o | |
530 | cc1: fatal error: build/libvirt.c: No such file or directory | |
531 | compilation terminated. | |
532 | error: command '/usr/lib64/ccache/gcc' failed with exit code 1 | |
533 | ||
534 | To solve this we instead override 'build_ext' and 'build_py'. This in | |
535 | turn means we call the generator to emit C code separately from Python | |
536 | code. | |
537 | ||
538 | ||
539 | ||
540 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
541 | ||
542 | setup: replace distutils.dir_util.remove_tree with shutils | |
543 | The distutils.dir_util.remove_tree method has no compelling benefit | |
544 | over using the standard python shutils module. | |
545 | ||
546 | ||
547 | ||
548 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
549 | ||
550 | setup: replace distutils.spawn with subprocess | |
551 | The distutils.spawn method has no compelling benefit over using the | |
552 | standard python subprocess module. | |
553 | ||
554 | ||
555 | ||
556 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
557 | ||
558 | setup: replace distutils.spawn.find_executable with shutils | |
559 | The distutils.spawn.find_executable method has no compelling benefit | |
560 | over using the standard python shutils module. | |
561 | ||
562 | ||
563 | ||
564 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
565 | ||
566 | setup: introduce an explicit check for pkg-config operation | |
567 | Instead of searching for the pkg-config binary manually, just try to run | |
568 | it and catch the exception raised if it isn't found. Use the --version | |
569 | flag as a way to validate that it is at least somewhat functional. | |
570 | ||
571 | ||
572 | ||
573 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
574 | ||
575 | setup: stop inheriting from 'clean' command | |
576 | The default 'clean' command impl deletes only intermediate files from | |
577 | the 'build' directory. We've overridden it to delete everything. There | |
578 | is no benefit in inheriting from the default impl, given our subclass | |
579 | will delete everything. | |
580 | ||
581 | ||
582 | ||
583 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
584 | ||
585 | setup: drop the 'rpm' command | |
586 | This duplicates funtionality already provided by the 'bdist_rpm' | |
587 | command. | |
588 | ||
589 | ||
590 | ||
591 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
592 | ||
593 | generator: introduce ability to selectively generate code | |
594 | Currently we always generate both the C code and Python code at the same | |
595 | time. To cope with following changes to the build process, we want to be | |
596 | able to generate C and Python separately. | |
597 | ||
598 | ||
599 | ||
600 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
601 | ||
602 | generator: rename methods for code generation | |
603 | The names make it clearer exactly what is being generated by each. | |
604 | ||
605 | ||
606 | ||
607 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
608 | ||
609 | generator: split function skip logic out of C generator | |
610 | The python generator needs to know whether certain functions were | |
611 | skipped in the C generator. This is achieved by the C generator | |
612 | deleting skipped functions as it runs. This is an unhelpful side | |
613 | effect as it makes it impossible to run the python generator | |
614 | without first running the C generator. | |
615 | ||
616 | This refactors buildStubs to get rid of the global side effects | |
617 | it has, by providing some helper functions for buildWrappers | |
618 | to use. | |
619 | ||
620 | ||
621 | ||
622 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
623 | ||
624 | generator: split function type validation out of C generator | |
625 | As a side effect of generating the C code, the buildStubs methods | |
626 | checks for various unsupported types and reports errors. This is | |
627 | an undesirable side effect, if we want to skip C code generation. | |
628 | ||
629 | Splitting function type validation out into a separate method | |
630 | allows better reuse. | |
631 | ||
632 | ||
633 | ||
634 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
635 | ||
636 | generator: split loading of APIs out from writing stubs | |
637 | The buildStubs method has a side effect of loading and parsing the API | |
638 | XML files, which the buildWrappers method then relies on. | |
639 | ||
640 | Splitting API loading into a separate method will facilitate running | |
641 | only the buildWrappers method in future. | |
642 | ||
643 | ||
644 | ||
645 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
646 | ||
647 | generator: merge python wrapper generator methods | |
648 | Instead of having three separate methods for generating python | |
649 | wrappers, merge them all together. | |
650 | ||
651 | ||
652 | ||
653 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
654 | ||
655 | generator: refactor buildWrappers to make it more generic | |
656 | Prepare for using buildWrappers to generate code for the QEMU / LXC | |
657 | APIs too. | |
658 | ||
659 | ||
660 | ||
661 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
662 | ||
663 | generator: simplify some repeated code patterns | |
664 | Now that we're using common data structures for all the main libvirt, | |
665 | QEMU and LXC APIs, several of the functions have code duplication | |
666 | that can be eliminated. | |
667 | ||
668 | ||
669 | ||
670 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
671 | ||
672 | generator: use single function for registering all enums | |
673 | Now that we only use a single dict for tracking all enums, we | |
674 | only need a single function for registering them. | |
675 | ||
676 | ||
677 | ||
678 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
679 | ||
680 | generator: use single dict for tracking all enums | |
681 | A single invokation of the generator only handles processing of one | |
682 | libvirt API module, so there is no need to use separate dicts for | |
683 | tracking enums. | |
684 | ||
685 | ||
686 | ||
687 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
688 | ||
689 | generator: use single function for registering all functions | |
690 | Now that we only use a single dict for tracking all functions, we | |
691 | only need a single function for registering them. | |
692 | ||
693 | ||
694 | ||
695 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
696 | ||
697 | generator: use single dict for tracking all skipped functions | |
698 | A single invokation of the generator only handles processing of one | |
699 | libvirt API module, so there is no need to use separate dicts for | |
700 | tracking skipped functions. | |
701 | ||
702 | ||
703 | ||
704 | 2022-04-21 Daniel P. Berrangé <berrange@redhat.com> | |
705 | ||
706 | generator: use single dict for tracking all functions | |
707 | A single invokation of the generator only handles processing of one | |
708 | libvirt API module, so there is no need to use separate dicts for | |
709 | tracking functions. | |
710 | ||
711 | ||
712 | ||
713 | 2022-04-01 Jiri Denemark <jdenemar@redhat.com> | |
714 | ||
715 | Post-release version bump to 8.3.0 | |
716 | ||
717 | ||
718 | 2022-03-28 Daniel P. Berrangé <berrange@redhat.com> | |
719 | ||
720 | gitlab: switch to using 'pip' for package installation | |
721 | The distutils/setuptools 'install' command is deprecated in favour of | |
722 | 'pip', and with recent versiosn, using it will create a bad install | |
723 | that triggers a traceback on all future use of setuptools: | |
724 | ||
725 | Traceback (most recent call last): | |
726 | File "/builds/berrange/libvirt-python/setup.py", line 328, in <module> | |
727 | setup(name = 'libvirt-python', | |
728 | File "/usr/lib/python3.10/site-packages/setuptools/__init__.py", line 154, in setup | |
729 | _install_setup_requires(attrs) | |
730 | File "/usr/lib/python3.10/site-packages/setuptools/__init__.py", line 143, in _install_setup_requires | |
731 | dist = MinimalDistribution(attrs) | |
732 | File "/usr/lib/python3.10/site-packages/setuptools/__init__.py", line 135, in __init__ | |
733 | super().__init__(filtered) | |
734 | File "/usr/lib/python3.10/site-packages/setuptools/dist.py", line 456, in __init__ | |
735 | for ep in metadata.entry_points(group='distutils.setup_keywords'): | |
736 | File "/usr/lib64/python3.10/importlib/metadata/__init__.py", line 1009, in entry_points | |
737 | return SelectableGroups.load(eps).select(**params) | |
738 | File "/usr/lib64/python3.10/importlib/metadata/__init__.py", line 459, in load | |
739 | ordered = sorted(eps, key=by_group) | |
740 | File "/usr/lib64/python3.10/importlib/metadata/__init__.py", line 1006, in <genexpr> | |
741 | eps = itertools.chain.from_iterable( | |
742 | File "/usr/lib64/python3.10/importlib/metadata/_itertools.py", line 16, in unique_everseen | |
743 | k = key(element) | |
744 | File "/usr/lib64/python3.10/importlib/metadata/__init__.py", line 941, in _normalized_name | |
745 | return self._name_from_stem(stem) or super()._normalized_name | |
746 | File "/usr/lib64/python3.10/importlib/metadata/__init__.py", line 622, in _normalized_name | |
747 | return Prepared.normalize(self.name) | |
748 | File "/usr/lib64/python3.10/importlib/metadata/__init__.py", line 871, in normalize | |
749 | return re.sub(r"[-_.]+", "-", name).lower().replace('-', '_') | |
750 | File "/usr/lib64/python3.10/re.py", line 209, in sub | |
751 | return _compile(pattern, flags).sub(repl, string, count) | |
752 | ||
753 | This is certainly a bug in distutils/setuptools, but given the | |
754 | 'install' command is deprecated, instead of waiting for a fix, | |
755 | just switch to the recommend 'pip install .' command. | |
756 | ||
757 | ||
758 | ||
759 | 2022-03-28 Daniel P. Berrangé <berrange@redhat.com> | |
760 | ||
761 | ci: refresh from lcitool manifest | |
762 | This drops the CentOS 8 job and replaces Fedora 33 with 35. | |
763 | ||
764 | ||
765 | ||
766 | 2022-03-10 Michal Privoznik <mprivozn@redhat.com> | |
767 | ||
768 | Implement virDomainQemuMonitorCommandWithFiles() override | |
769 | With libvirt-8.2.0 there's a new API: | |
770 | virDomainQemuMonitorCommandWithFiles(). Since the API has both | |
771 | input and output arguments we need to provide an alternative | |
772 | implementation. Moreover, since FD passing works only on | |
773 | UNIX-like systems we can query the returned FDs for their flags | |
774 | and construct mode for python File object. | |
775 | ||
776 | ||
777 | ||
778 | 2022-03-01 Jiri Denemark <jdenemar@redhat.com> | |
779 | ||
780 | Post-release version bump to 8.2.0 | |
781 | ||
782 | ||
783 | 2022-02-11 Daniel P. Berrangé <berrange@redhat.com> | |
784 | ||
785 | add missing files to MANIFEST.in | |
786 | ||
787 | ||
788 | 2022-01-14 Jiri Denemark <jdenemar@redhat.com> | |
789 | ||
790 | Post-release version bump to 8.1.0 | |
791 | ||
792 | ||
0 | 793 | 2022-01-05 Daniel P. Berrangé <berrange@redhat.com> |
1 | 794 | |
2 | 795 | Add an override impl for virDomainSetLaunchSecurityState |
0 | libvirt Python Bindings Hacking | |
1 | =============================== | |
2 | ||
3 | Most of the libvirt python binding code is automatically generated | |
4 | using the script generator.py, and the API description that the | |
5 | libvirt library installs at the location shown by pkg-config, with | |
6 | this command: | |
7 | ||
8 | $ pkg-config --variable libvirt_api libvirt | |
9 | /usr/share/libvirt/api/libvirt-api.xml | |
10 | ||
11 | Some of the API descriptions in the primary XML files are not directly | |
12 | usable by the code generator. Thus there are overrides in | |
13 | ||
14 | - libvirt-override-api.xml | |
15 | - libvirt-qemu-override-api.xml | |
16 | - libvirt-lxc-override-api.xml | |
17 | ||
18 | For stuff which the generator can't cope with at all there are some | |
19 | hand written source files | |
20 | ||
21 | - libvirt-override.c - low level binding to libvirt.so | |
22 | - libvirt-qemu-override.c - low level binding to libvirt-qemu.so | |
23 | - libvirt-lxc-override.c - low level binding to libvirt-lxc.so | |
24 | ||
25 | - libvirt-override.py - high level overrides in the global namespace | |
26 | - libvirt-override-virConnect.py - high level overrides in | |
27 | the virConnect class | |
28 | - libvirt-override-virDomain.py - high level overrides in | |
29 | the virDomain class | |
30 | - libvirt-override-virDomainCheckpoint.py - high level overrides in | |
31 | the virDomainCheckpoint class | |
32 | - libvirt-override-virDomainSnapshot.py - high level overrides in | |
33 | the virDomainSnapshot class | |
34 | - libvirt-override-virStoragePool.py - high level overrides in | |
35 | the virStoragePool class | |
36 | - libvirt-override-virStream.py - high level overrides in | |
37 | the virStream class |
0 | 0 | # file GENERATED by distutils, do NOT edit |
1 | 1 | AUTHORS |
2 | CONTRIBUTING.rst | |
2 | 3 | COPYING |
3 | 4 | COPYING.LESSER |
4 | 5 | ChangeLog |
6 | HACKING | |
5 | 7 | MANIFEST |
6 | 8 | MANIFEST.in |
7 | 9 | README |
25 | 27 | libvirt-utils.c |
26 | 28 | libvirt-utils.h |
27 | 29 | libvirtaio.py |
30 | requirements-test.txt | |
28 | 31 | sanitytest.py |
29 | 32 | setup.py |
30 | 33 | tox.ini |
31 | 34 | typewrappers.c |
32 | 35 | typewrappers.h |
36 | examples/README | |
33 | 37 | examples/consolecallback.py |
38 | examples/dhcpleases.py | |
34 | 39 | examples/dominfo.py |
35 | 40 | examples/domipaddrs.py |
36 | 41 | examples/domrestore.py |
45 | 50 | examples/guest-vcpus/guest-vcpu.py |
46 | 51 | tests/test_conn.py |
47 | 52 | tests/test_domain.py |
53 | tests/test_domain_checkpoint.py | |
54 | tests/test_domain_snapshot.py | |
55 | tests/test_interface.py | |
56 | tests/test_network.py | |
57 | tests/test_nodedev.py | |
58 | tests/test_storage.py |
0 | 0 | include AUTHORS |
1 | 1 | include COPYING |
2 | 2 | include COPYING.LESSER |
3 | include CONTRIBUTING.rst | |
4 | include HACKING | |
3 | 5 | include ChangeLog |
6 | include examples/README | |
4 | 7 | include examples/consolecallback.py |
8 | include examples/dhcpleases.py | |
5 | 9 | include examples/domipaddrs.py |
6 | 10 | include examples/dominfo.py |
7 | 11 | include examples/domrestore.py |
37 | 41 | include MANIFEST |
38 | 42 | include MANIFEST.in |
39 | 43 | include README |
44 | include requirements-test.txt | |
40 | 45 | include sanitytest.py |
41 | 46 | include setup.py |
42 | 47 | include tests/test_conn.py |
43 | 48 | include tests/test_domain.py |
49 | include tests/test_domain_checkpoint.py | |
50 | include tests/test_domain_snapshot.py | |
51 | include tests/test_interface.py | |
52 | include tests/test_network.py | |
53 | include tests/test_nodedev.py | |
54 | include tests/test_storage.py | |
44 | 55 | include tox.ini |
45 | 56 | include typewrappers.c |
46 | 57 | include typewrappers.h |
0 | # Shim wrapper around setup.py to allow for familiar build targets | |
1 | ||
2 | PYTHON ?= python | |
3 | ||
4 | all: | |
5 | $(PYTHON) setup.py build | |
6 | ||
7 | install: all | |
8 | $(PYTHON) setup.py install | |
9 | ||
10 | clean: | |
11 | $(PYTHON) setup.py clean | |
12 | ||
13 | check: all | |
14 | $(PYTHON) setup.py test | |
15 | ||
16 | rpm: | |
17 | $(PYTHON) setup.py rpm |
0 | Metadata-Version: 1.1 | |
0 | Metadata-Version: 2.1 | |
1 | 1 | Name: libvirt-python |
2 | Version: 8.0.0 | |
2 | Version: 9.0.0 | |
3 | 3 | Summary: The libvirt virtualization API python binding |
4 | 4 | Home-page: http://www.libvirt.org |
5 | Author: Libvirt Maintainers | |
6 | Author-email: libvir-list@redhat.com | |
5 | Maintainer: Libvirt Maintainers | |
6 | Maintainer-email: libvir-list@redhat.com | |
7 | 7 | License: LGPLv2+ |
8 | Description: The libvirt-python package provides a module that permits applications | |
9 | written in the Python 3.x programming language to call the interface | |
10 | supplied by the libvirt library, to manage the virtualization capabilities | |
11 | of recent versions of Linux (and other OSes). | |
12 | Platform: UNKNOWN | |
13 | 8 | Classifier: Development Status :: 5 - Production/Stable |
14 | 9 | Classifier: Intended Audience :: Developers |
15 | 10 | Classifier: License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+) |
19 | 14 | Classifier: Programming Language :: Python :: 3.6 |
20 | 15 | Classifier: Programming Language :: Python :: 3.7 |
21 | 16 | Classifier: Programming Language :: Python :: 3.8 |
17 | Classifier: Programming Language :: Python :: 3.9 | |
18 | Classifier: Programming Language :: Python :: 3.10 | |
19 | License-File: COPYING | |
20 | License-File: COPYING.LESSER | |
21 | License-File: AUTHORS.in | |
22 | ||
23 | The libvirt-python package provides a module that permits applications | |
24 | written in the Python 3.x programming language to call the interface | |
25 | supplied by the libvirt library, to manage the virtualization capabilities | |
26 | of recent versions of Linux (and other OSes). |
0 | .ctags | |
1 | .dir-locals.el | |
2 | .gitignore | |
3 | .gitlab-ci.yml | |
4 | .mailmap | |
5 | AUTHORS | |
6 | AUTHORS.in | |
7 | CONTRIBUTING.rst | |
8 | COPYING | |
9 | COPYING.LESSER | |
10 | ChangeLog | |
11 | HACKING | |
12 | MANIFEST | |
13 | MANIFEST.in | |
14 | Makefile | |
15 | README | |
16 | generator.py | |
17 | libvirt-lxc-override-api.xml | |
18 | libvirt-lxc-override.c | |
19 | libvirt-override-api.xml | |
20 | libvirt-override-virConnect.py | |
21 | libvirt-override-virDomain.py | |
22 | libvirt-override-virDomainCheckpoint.py | |
23 | libvirt-override-virDomainSnapshot.py | |
24 | libvirt-override-virNetwork.py | |
25 | libvirt-override-virStoragePool.py | |
26 | libvirt-override-virStream.py | |
27 | libvirt-override.c | |
28 | libvirt-override.py | |
29 | libvirt-python.spec | |
30 | libvirt-python.spec.in | |
31 | libvirt-qemu-override-api.xml | |
32 | libvirt-qemu-override.c | |
33 | libvirt-qemu-override.py | |
34 | libvirt-utils.c | |
35 | libvirt-utils.h | |
36 | libvirtaio.py | |
37 | requirements-test.txt | |
38 | setup.py | |
39 | tox.ini | |
40 | typewrappers.c | |
41 | typewrappers.h | |
42 | .github/workflows/lockdown.yml | |
43 | ci/gitlab.yml | |
44 | ci/manifest.yml | |
45 | ci/buildenv/centos-stream-8.sh | |
46 | ci/buildenv/centos-stream-9.sh | |
47 | ci/buildenv/debian-10.sh | |
48 | ci/buildenv/debian-sid.sh | |
49 | ci/buildenv/fedora-36.sh | |
50 | ci/buildenv/fedora-37.sh | |
51 | ci/buildenv/fedora-rawhide.sh | |
52 | ci/buildenv/opensuse-leap-153.sh | |
53 | ci/buildenv/opensuse-tumbleweed.sh | |
54 | ci/buildenv/ubuntu-2004.sh | |
55 | ci/buildenv/ubuntu-2204.sh | |
56 | ci/containers/centos-stream-8.Dockerfile | |
57 | ci/containers/centos-stream-9.Dockerfile | |
58 | ci/containers/debian-10.Dockerfile | |
59 | ci/containers/debian-sid.Dockerfile | |
60 | ci/containers/fedora-36.Dockerfile | |
61 | ci/containers/fedora-37.Dockerfile | |
62 | ci/containers/fedora-rawhide.Dockerfile | |
63 | ci/containers/opensuse-leap-153.Dockerfile | |
64 | ci/containers/opensuse-tumbleweed.Dockerfile | |
65 | ci/containers/ubuntu-2004.Dockerfile | |
66 | ci/containers/ubuntu-2204.Dockerfile | |
67 | ci/gitlab/build-templates.yml | |
68 | ci/gitlab/builds.yml | |
69 | ci/gitlab/container-templates.yml | |
70 | ci/gitlab/containers.yml | |
71 | ci/gitlab/sanity-checks.yml | |
72 | examples/README | |
73 | examples/consolecallback.py | |
74 | examples/dhcpleases.py | |
75 | examples/dominfo.py | |
76 | examples/domipaddrs.py | |
77 | examples/domrestore.py | |
78 | examples/domsave.py | |
79 | examples/domstart.py | |
80 | examples/esxlist.py | |
81 | examples/event-test.py | |
82 | examples/nodestats.py | |
83 | examples/sparsestream.py | |
84 | examples/topology.py | |
85 | examples/guest-vcpus/guest-vcpu-daemon.py | |
86 | examples/guest-vcpus/guest-vcpu.py | |
87 | tests/eventmock.py | |
88 | tests/test_aio.py | |
89 | tests/test_api_coverage.py | |
90 | tests/test_conn.py | |
91 | tests/test_domain.py | |
92 | tests/test_domain_checkpoint.py | |
93 | tests/test_domain_snapshot.py | |
94 | tests/test_interface.py | |
95 | tests/test_network.py | |
96 | tests/test_nodedev.py | |
97 | tests/test_storage.py⏎ |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | function install_buildenv() { | |
7 | dnf distro-sync -y | |
8 | dnf install 'dnf-command(config-manager)' -y | |
9 | dnf config-manager --set-enabled -y powertools | |
10 | dnf install -y centos-release-advanced-virtualization | |
11 | dnf install -y epel-release | |
12 | dnf install -y epel-next-release | |
13 | dnf install -y \ | |
14 | ca-certificates \ | |
15 | ccache \ | |
16 | cpp \ | |
17 | gcc \ | |
18 | gettext \ | |
19 | git \ | |
20 | glib2-devel \ | |
21 | glibc-devel \ | |
22 | glibc-langpack-en \ | |
23 | gnutls-devel \ | |
24 | libnl3-devel \ | |
25 | libtirpc-devel \ | |
26 | libvirt-devel \ | |
27 | libxml2 \ | |
28 | libxml2-devel \ | |
29 | libxslt \ | |
30 | make \ | |
31 | meson \ | |
32 | ninja-build \ | |
33 | perl \ | |
34 | pkgconfig \ | |
35 | python3 \ | |
36 | python3-devel \ | |
37 | python3-docutils \ | |
38 | python3-lxml \ | |
39 | python3-pip \ | |
40 | python3-pytest \ | |
41 | python3-setuptools \ | |
42 | rpcgen \ | |
43 | rpm-build | |
44 | rpm -qa | sort > /packages.txt | |
45 | mkdir -p /usr/libexec/ccache-wrappers | |
46 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc | |
47 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc | |
48 | } | |
49 | ||
50 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" | |
51 | export LANG="en_US.UTF-8" | |
52 | export MAKE="/usr/bin/make" | |
53 | export NINJA="/usr/bin/ninja" | |
54 | export PYTHON="/usr/bin/python3" |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | function install_buildenv() { | |
7 | dnf distro-sync -y | |
8 | dnf install 'dnf-command(config-manager)' -y | |
9 | dnf config-manager --set-enabled -y crb | |
10 | dnf install -y epel-release | |
11 | dnf install -y epel-next-release | |
12 | dnf install -y \ | |
13 | ca-certificates \ | |
14 | ccache \ | |
15 | gcc \ | |
16 | git \ | |
17 | glibc-langpack-en \ | |
18 | libvirt-devel \ | |
19 | pkgconfig \ | |
20 | python3 \ | |
21 | python3-devel \ | |
22 | python3-lxml \ | |
23 | python3-pip \ | |
24 | python3-pytest \ | |
25 | python3-setuptools \ | |
26 | rpm-build | |
27 | rpm -qa | sort > /packages.txt | |
28 | mkdir -p /usr/libexec/ccache-wrappers | |
29 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc | |
30 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc | |
31 | } | |
32 | ||
33 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" | |
34 | export LANG="en_US.UTF-8" | |
35 | export PYTHON="/usr/bin/python3" |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | function install_buildenv() { | |
7 | export DEBIAN_FRONTEND=noninteractive | |
8 | apt-get update | |
9 | apt-get dist-upgrade -y | |
10 | apt-get install --no-install-recommends -y \ | |
11 | ca-certificates \ | |
12 | ccache \ | |
13 | gcc \ | |
14 | git \ | |
15 | libvirt-dev \ | |
16 | locales \ | |
17 | pkgconf \ | |
18 | python3 \ | |
19 | python3-dev \ | |
20 | python3-lxml \ | |
21 | python3-pip \ | |
22 | python3-pytest \ | |
23 | python3-setuptools | |
24 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen | |
25 | dpkg-reconfigure locales | |
26 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt | |
27 | mkdir -p /usr/libexec/ccache-wrappers | |
28 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc | |
29 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc | |
30 | } | |
31 | ||
32 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" | |
33 | export LANG="en_US.UTF-8" | |
34 | export PYTHON="/usr/bin/python3" |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | function install_buildenv() { | |
7 | export DEBIAN_FRONTEND=noninteractive | |
8 | apt-get update | |
9 | apt-get dist-upgrade -y | |
10 | apt-get install --no-install-recommends -y \ | |
11 | ca-certificates \ | |
12 | ccache \ | |
13 | gcc \ | |
14 | git \ | |
15 | libvirt-dev \ | |
16 | locales \ | |
17 | pkgconf \ | |
18 | python3 \ | |
19 | python3-dev \ | |
20 | python3-lxml \ | |
21 | python3-pip \ | |
22 | python3-pytest \ | |
23 | python3-setuptools | |
24 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen | |
25 | dpkg-reconfigure locales | |
26 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt | |
27 | mkdir -p /usr/libexec/ccache-wrappers | |
28 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc | |
29 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc | |
30 | } | |
31 | ||
32 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" | |
33 | export LANG="en_US.UTF-8" | |
34 | export PYTHON="/usr/bin/python3" |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | function install_buildenv() { | |
7 | dnf update -y | |
8 | dnf install -y \ | |
9 | ca-certificates \ | |
10 | ccache \ | |
11 | gcc \ | |
12 | git \ | |
13 | glibc-langpack-en \ | |
14 | libvirt-devel \ | |
15 | pkgconfig \ | |
16 | python3 \ | |
17 | python3-devel \ | |
18 | python3-lxml \ | |
19 | python3-pip \ | |
20 | python3-pytest \ | |
21 | python3-setuptools \ | |
22 | rpm-build | |
23 | rpm -qa | sort > /packages.txt | |
24 | mkdir -p /usr/libexec/ccache-wrappers | |
25 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc | |
26 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc | |
27 | } | |
28 | ||
29 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" | |
30 | export LANG="en_US.UTF-8" | |
31 | export PYTHON="/usr/bin/python3" |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | function install_buildenv() { | |
7 | dnf update -y | |
8 | dnf install -y \ | |
9 | ca-certificates \ | |
10 | ccache \ | |
11 | gcc \ | |
12 | git \ | |
13 | glibc-langpack-en \ | |
14 | libvirt-devel \ | |
15 | pkgconfig \ | |
16 | python3 \ | |
17 | python3-devel \ | |
18 | python3-lxml \ | |
19 | python3-pip \ | |
20 | python3-pytest \ | |
21 | python3-setuptools \ | |
22 | rpm-build | |
23 | rpm -qa | sort > /packages.txt | |
24 | mkdir -p /usr/libexec/ccache-wrappers | |
25 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc | |
26 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc | |
27 | } | |
28 | ||
29 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" | |
30 | export LANG="en_US.UTF-8" | |
31 | export PYTHON="/usr/bin/python3" |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | function install_buildenv() { | |
7 | dnf update -y --nogpgcheck fedora-gpg-keys | |
8 | dnf distro-sync -y | |
9 | dnf install -y \ | |
10 | ca-certificates \ | |
11 | ccache \ | |
12 | gcc \ | |
13 | git \ | |
14 | glibc-langpack-en \ | |
15 | libvirt-devel \ | |
16 | pkgconfig \ | |
17 | python3 \ | |
18 | python3-devel \ | |
19 | python3-lxml \ | |
20 | python3-pip \ | |
21 | python3-pytest \ | |
22 | python3-setuptools \ | |
23 | rpm-build | |
24 | rpm -qa | sort > /packages.txt | |
25 | mkdir -p /usr/libexec/ccache-wrappers | |
26 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc | |
27 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc | |
28 | } | |
29 | ||
30 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" | |
31 | export LANG="en_US.UTF-8" | |
32 | export PYTHON="/usr/bin/python3" |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | function install_buildenv() { | |
7 | zypper update -y | |
8 | zypper install -y \ | |
9 | ca-certificates \ | |
10 | ccache \ | |
11 | gcc \ | |
12 | git \ | |
13 | glibc-locale \ | |
14 | libvirt-devel \ | |
15 | pkgconfig \ | |
16 | python3-base \ | |
17 | python3-devel \ | |
18 | python3-lxml \ | |
19 | python3-pip \ | |
20 | python3-pytest \ | |
21 | python3-setuptools \ | |
22 | rpm-build | |
23 | rpm -qa | sort > /packages.txt | |
24 | mkdir -p /usr/libexec/ccache-wrappers | |
25 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc | |
26 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc | |
27 | } | |
28 | ||
29 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" | |
30 | export LANG="en_US.UTF-8" | |
31 | export PYTHON="/usr/bin/python3" |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | function install_buildenv() { | |
7 | zypper dist-upgrade -y | |
8 | zypper install -y \ | |
9 | ca-certificates \ | |
10 | ccache \ | |
11 | gcc \ | |
12 | git \ | |
13 | glibc-locale \ | |
14 | libvirt-devel \ | |
15 | pkgconfig \ | |
16 | python3-base \ | |
17 | python3-devel \ | |
18 | python3-lxml \ | |
19 | python3-pip \ | |
20 | python3-pytest \ | |
21 | python3-setuptools \ | |
22 | rpm-build | |
23 | rpm -qa | sort > /packages.txt | |
24 | mkdir -p /usr/libexec/ccache-wrappers | |
25 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc | |
26 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc | |
27 | } | |
28 | ||
29 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" | |
30 | export LANG="en_US.UTF-8" | |
31 | export PYTHON="/usr/bin/python3" |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | function install_buildenv() { | |
7 | export DEBIAN_FRONTEND=noninteractive | |
8 | apt-get update | |
9 | apt-get dist-upgrade -y | |
10 | apt-get install --no-install-recommends -y \ | |
11 | ca-certificates \ | |
12 | ccache \ | |
13 | gcc \ | |
14 | git \ | |
15 | libvirt-dev \ | |
16 | locales \ | |
17 | pkgconf \ | |
18 | python3 \ | |
19 | python3-dev \ | |
20 | python3-lxml \ | |
21 | python3-pip \ | |
22 | python3-pytest \ | |
23 | python3-setuptools | |
24 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen | |
25 | dpkg-reconfigure locales | |
26 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt | |
27 | mkdir -p /usr/libexec/ccache-wrappers | |
28 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc | |
29 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc | |
30 | } | |
31 | ||
32 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" | |
33 | export LANG="en_US.UTF-8" | |
34 | export PYTHON="/usr/bin/python3" |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | function install_buildenv() { | |
7 | export DEBIAN_FRONTEND=noninteractive | |
8 | apt-get update | |
9 | apt-get dist-upgrade -y | |
10 | apt-get install --no-install-recommends -y \ | |
11 | ca-certificates \ | |
12 | ccache \ | |
13 | gcc \ | |
14 | git \ | |
15 | libvirt-dev \ | |
16 | locales \ | |
17 | pkgconf \ | |
18 | python3 \ | |
19 | python3-dev \ | |
20 | python3-lxml \ | |
21 | python3-pip \ | |
22 | python3-pytest \ | |
23 | python3-setuptools | |
24 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen | |
25 | dpkg-reconfigure locales | |
26 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt | |
27 | mkdir -p /usr/libexec/ccache-wrappers | |
28 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc | |
29 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc | |
30 | } | |
31 | ||
32 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" | |
33 | export LANG="en_US.UTF-8" | |
34 | export PYTHON="/usr/bin/python3" |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | FROM quay.io/centos/centos:stream8 | |
7 | ||
8 | RUN dnf distro-sync -y && \ | |
9 | dnf install 'dnf-command(config-manager)' -y && \ | |
10 | dnf config-manager --set-enabled -y powertools && \ | |
11 | dnf install -y centos-release-advanced-virtualization && \ | |
12 | dnf install -y epel-release && \ | |
13 | dnf install -y epel-next-release && \ | |
14 | dnf install -y \ | |
15 | ca-certificates \ | |
16 | ccache \ | |
17 | cpp \ | |
18 | gcc \ | |
19 | gettext \ | |
20 | git \ | |
21 | glib2-devel \ | |
22 | glibc-devel \ | |
23 | glibc-langpack-en \ | |
24 | gnutls-devel \ | |
25 | libnl3-devel \ | |
26 | libtirpc-devel \ | |
27 | libvirt-devel \ | |
28 | libxml2 \ | |
29 | libxml2-devel \ | |
30 | libxslt \ | |
31 | make \ | |
32 | meson \ | |
33 | ninja-build \ | |
34 | perl \ | |
35 | pkgconfig \ | |
36 | python3 \ | |
37 | python3-devel \ | |
38 | python3-docutils \ | |
39 | python3-lxml \ | |
40 | python3-pip \ | |
41 | python3-pytest \ | |
42 | python3-setuptools \ | |
43 | rpcgen \ | |
44 | rpm-build && \ | |
45 | dnf autoremove -y && \ | |
46 | dnf clean all -y && \ | |
47 | rpm -qa | sort > /packages.txt && \ | |
48 | mkdir -p /usr/libexec/ccache-wrappers && \ | |
49 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ | |
50 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc | |
51 | ||
52 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" | |
53 | ENV LANG "en_US.UTF-8" | |
54 | ENV MAKE "/usr/bin/make" | |
55 | ENV NINJA "/usr/bin/ninja" | |
56 | ENV PYTHON "/usr/bin/python3" |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | FROM quay.io/centos/centos:stream9 | |
7 | ||
8 | RUN dnf distro-sync -y && \ | |
9 | dnf install 'dnf-command(config-manager)' -y && \ | |
10 | dnf config-manager --set-enabled -y crb && \ | |
11 | dnf install -y epel-release && \ | |
12 | dnf install -y epel-next-release && \ | |
13 | dnf install -y \ | |
14 | ca-certificates \ | |
15 | ccache \ | |
16 | gcc \ | |
17 | git \ | |
18 | glibc-langpack-en \ | |
19 | libvirt-devel \ | |
20 | pkgconfig \ | |
21 | python3 \ | |
22 | python3-devel \ | |
23 | python3-lxml \ | |
24 | python3-pip \ | |
25 | python3-pytest \ | |
26 | python3-setuptools \ | |
27 | rpm-build && \ | |
28 | dnf autoremove -y && \ | |
29 | dnf clean all -y && \ | |
30 | rpm -qa | sort > /packages.txt && \ | |
31 | mkdir -p /usr/libexec/ccache-wrappers && \ | |
32 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ | |
33 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc | |
34 | ||
35 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" | |
36 | ENV LANG "en_US.UTF-8" | |
37 | ENV PYTHON "/usr/bin/python3" |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | FROM docker.io/library/debian:10-slim | |
7 | ||
8 | RUN export DEBIAN_FRONTEND=noninteractive && \ | |
9 | apt-get update && \ | |
10 | apt-get install -y eatmydata && \ | |
11 | eatmydata apt-get dist-upgrade -y && \ | |
12 | eatmydata apt-get install --no-install-recommends -y \ | |
13 | ca-certificates \ | |
14 | ccache \ | |
15 | gcc \ | |
16 | git \ | |
17 | libvirt-dev \ | |
18 | locales \ | |
19 | pkgconf \ | |
20 | python3 \ | |
21 | python3-dev \ | |
22 | python3-lxml \ | |
23 | python3-pip \ | |
24 | python3-pytest \ | |
25 | python3-setuptools && \ | |
26 | eatmydata apt-get autoremove -y && \ | |
27 | eatmydata apt-get autoclean -y && \ | |
28 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ | |
29 | dpkg-reconfigure locales && \ | |
30 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ | |
31 | mkdir -p /usr/libexec/ccache-wrappers && \ | |
32 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ | |
33 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc | |
34 | ||
35 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" | |
36 | ENV LANG "en_US.UTF-8" | |
37 | ENV PYTHON "/usr/bin/python3" |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | FROM docker.io/library/debian:sid-slim | |
7 | ||
8 | RUN export DEBIAN_FRONTEND=noninteractive && \ | |
9 | apt-get update && \ | |
10 | apt-get install -y eatmydata && \ | |
11 | eatmydata apt-get dist-upgrade -y && \ | |
12 | eatmydata apt-get install --no-install-recommends -y \ | |
13 | ca-certificates \ | |
14 | ccache \ | |
15 | gcc \ | |
16 | git \ | |
17 | libvirt-dev \ | |
18 | locales \ | |
19 | pkgconf \ | |
20 | python3 \ | |
21 | python3-dev \ | |
22 | python3-lxml \ | |
23 | python3-pip \ | |
24 | python3-pytest \ | |
25 | python3-setuptools && \ | |
26 | eatmydata apt-get autoremove -y && \ | |
27 | eatmydata apt-get autoclean -y && \ | |
28 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ | |
29 | dpkg-reconfigure locales && \ | |
30 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ | |
31 | mkdir -p /usr/libexec/ccache-wrappers && \ | |
32 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ | |
33 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc | |
34 | ||
35 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" | |
36 | ENV LANG "en_US.UTF-8" | |
37 | ENV PYTHON "/usr/bin/python3" |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | FROM registry.fedoraproject.org/fedora:36 | |
7 | ||
8 | RUN dnf install -y nosync && \ | |
9 | echo -e '#!/bin/sh\n\ | |
10 | if test -d /usr/lib64\n\ | |
11 | then\n\ | |
12 | export LD_PRELOAD=/usr/lib64/nosync/nosync.so\n\ | |
13 | else\n\ | |
14 | export LD_PRELOAD=/usr/lib/nosync/nosync.so\n\ | |
15 | fi\n\ | |
16 | exec "$@"' > /usr/bin/nosync && \ | |
17 | chmod +x /usr/bin/nosync && \ | |
18 | nosync dnf update -y && \ | |
19 | nosync dnf install -y \ | |
20 | ca-certificates \ | |
21 | ccache \ | |
22 | gcc \ | |
23 | git \ | |
24 | glibc-langpack-en \ | |
25 | libvirt-devel \ | |
26 | pkgconfig \ | |
27 | python3 \ | |
28 | python3-devel \ | |
29 | python3-lxml \ | |
30 | python3-pip \ | |
31 | python3-pytest \ | |
32 | python3-setuptools \ | |
33 | rpm-build && \ | |
34 | nosync dnf autoremove -y && \ | |
35 | nosync dnf clean all -y && \ | |
36 | rpm -qa | sort > /packages.txt && \ | |
37 | mkdir -p /usr/libexec/ccache-wrappers && \ | |
38 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ | |
39 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc | |
40 | ||
41 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" | |
42 | ENV LANG "en_US.UTF-8" | |
43 | ENV PYTHON "/usr/bin/python3" |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | FROM registry.fedoraproject.org/fedora:37 | |
7 | ||
8 | RUN dnf install -y nosync && \ | |
9 | echo -e '#!/bin/sh\n\ | |
10 | if test -d /usr/lib64\n\ | |
11 | then\n\ | |
12 | export LD_PRELOAD=/usr/lib64/nosync/nosync.so\n\ | |
13 | else\n\ | |
14 | export LD_PRELOAD=/usr/lib/nosync/nosync.so\n\ | |
15 | fi\n\ | |
16 | exec "$@"' > /usr/bin/nosync && \ | |
17 | chmod +x /usr/bin/nosync && \ | |
18 | nosync dnf update -y && \ | |
19 | nosync dnf install -y \ | |
20 | ca-certificates \ | |
21 | ccache \ | |
22 | gcc \ | |
23 | git \ | |
24 | glibc-langpack-en \ | |
25 | libvirt-devel \ | |
26 | pkgconfig \ | |
27 | python3 \ | |
28 | python3-devel \ | |
29 | python3-lxml \ | |
30 | python3-pip \ | |
31 | python3-pytest \ | |
32 | python3-setuptools \ | |
33 | rpm-build && \ | |
34 | nosync dnf autoremove -y && \ | |
35 | nosync dnf clean all -y && \ | |
36 | rpm -qa | sort > /packages.txt && \ | |
37 | mkdir -p /usr/libexec/ccache-wrappers && \ | |
38 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ | |
39 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc | |
40 | ||
41 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" | |
42 | ENV LANG "en_US.UTF-8" | |
43 | ENV PYTHON "/usr/bin/python3" |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | FROM registry.fedoraproject.org/fedora:rawhide | |
7 | ||
8 | RUN dnf update -y --nogpgcheck fedora-gpg-keys && \ | |
9 | dnf install -y nosync && \ | |
10 | echo -e '#!/bin/sh\n\ | |
11 | if test -d /usr/lib64\n\ | |
12 | then\n\ | |
13 | export LD_PRELOAD=/usr/lib64/nosync/nosync.so\n\ | |
14 | else\n\ | |
15 | export LD_PRELOAD=/usr/lib/nosync/nosync.so\n\ | |
16 | fi\n\ | |
17 | exec "$@"' > /usr/bin/nosync && \ | |
18 | chmod +x /usr/bin/nosync && \ | |
19 | nosync dnf distro-sync -y && \ | |
20 | nosync dnf install -y \ | |
21 | ca-certificates \ | |
22 | ccache \ | |
23 | gcc \ | |
24 | git \ | |
25 | glibc-langpack-en \ | |
26 | libvirt-devel \ | |
27 | pkgconfig \ | |
28 | python3 \ | |
29 | python3-devel \ | |
30 | python3-lxml \ | |
31 | python3-pip \ | |
32 | python3-pytest \ | |
33 | python3-setuptools \ | |
34 | rpm-build && \ | |
35 | nosync dnf autoremove -y && \ | |
36 | nosync dnf clean all -y && \ | |
37 | rpm -qa | sort > /packages.txt && \ | |
38 | mkdir -p /usr/libexec/ccache-wrappers && \ | |
39 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ | |
40 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc | |
41 | ||
42 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" | |
43 | ENV LANG "en_US.UTF-8" | |
44 | ENV PYTHON "/usr/bin/python3" |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | FROM registry.opensuse.org/opensuse/leap:15.3 | |
7 | ||
8 | RUN zypper update -y && \ | |
9 | zypper install -y \ | |
10 | ca-certificates \ | |
11 | ccache \ | |
12 | gcc \ | |
13 | git \ | |
14 | glibc-locale \ | |
15 | libvirt-devel \ | |
16 | pkgconfig \ | |
17 | python3-base \ | |
18 | python3-devel \ | |
19 | python3-lxml \ | |
20 | python3-pip \ | |
21 | python3-pytest \ | |
22 | python3-setuptools \ | |
23 | rpm-build && \ | |
24 | zypper clean --all && \ | |
25 | rpm -qa | sort > /packages.txt && \ | |
26 | mkdir -p /usr/libexec/ccache-wrappers && \ | |
27 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ | |
28 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc | |
29 | ||
30 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" | |
31 | ENV LANG "en_US.UTF-8" | |
32 | ENV PYTHON "/usr/bin/python3" |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | FROM registry.opensuse.org/opensuse/tumbleweed:latest | |
7 | ||
8 | RUN zypper dist-upgrade -y && \ | |
9 | zypper install -y \ | |
10 | ca-certificates \ | |
11 | ccache \ | |
12 | gcc \ | |
13 | git \ | |
14 | glibc-locale \ | |
15 | libvirt-devel \ | |
16 | pkgconfig \ | |
17 | python3-base \ | |
18 | python3-devel \ | |
19 | python3-lxml \ | |
20 | python3-pip \ | |
21 | python3-pytest \ | |
22 | python3-setuptools \ | |
23 | rpm-build && \ | |
24 | zypper clean --all && \ | |
25 | rpm -qa | sort > /packages.txt && \ | |
26 | mkdir -p /usr/libexec/ccache-wrappers && \ | |
27 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ | |
28 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc | |
29 | ||
30 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" | |
31 | ENV LANG "en_US.UTF-8" | |
32 | ENV PYTHON "/usr/bin/python3" |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | FROM docker.io/library/ubuntu:20.04 | |
7 | ||
8 | RUN export DEBIAN_FRONTEND=noninteractive && \ | |
9 | apt-get update && \ | |
10 | apt-get install -y eatmydata && \ | |
11 | eatmydata apt-get dist-upgrade -y && \ | |
12 | eatmydata apt-get install --no-install-recommends -y \ | |
13 | ca-certificates \ | |
14 | ccache \ | |
15 | gcc \ | |
16 | git \ | |
17 | libvirt-dev \ | |
18 | locales \ | |
19 | pkgconf \ | |
20 | python3 \ | |
21 | python3-dev \ | |
22 | python3-lxml \ | |
23 | python3-pip \ | |
24 | python3-pytest \ | |
25 | python3-setuptools && \ | |
26 | eatmydata apt-get autoremove -y && \ | |
27 | eatmydata apt-get autoclean -y && \ | |
28 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ | |
29 | dpkg-reconfigure locales && \ | |
30 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ | |
31 | mkdir -p /usr/libexec/ccache-wrappers && \ | |
32 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ | |
33 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc | |
34 | ||
35 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" | |
36 | ENV LANG "en_US.UTF-8" | |
37 | ENV PYTHON "/usr/bin/python3" |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | FROM docker.io/library/ubuntu:22.04 | |
7 | ||
8 | RUN export DEBIAN_FRONTEND=noninteractive && \ | |
9 | apt-get update && \ | |
10 | apt-get install -y eatmydata && \ | |
11 | eatmydata apt-get dist-upgrade -y && \ | |
12 | eatmydata apt-get install --no-install-recommends -y \ | |
13 | ca-certificates \ | |
14 | ccache \ | |
15 | gcc \ | |
16 | git \ | |
17 | libvirt-dev \ | |
18 | locales \ | |
19 | pkgconf \ | |
20 | python3 \ | |
21 | python3-dev \ | |
22 | python3-lxml \ | |
23 | python3-pip \ | |
24 | python3-pytest \ | |
25 | python3-setuptools && \ | |
26 | eatmydata apt-get autoremove -y && \ | |
27 | eatmydata apt-get autoclean -y && \ | |
28 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ | |
29 | dpkg-reconfigure locales && \ | |
30 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ | |
31 | mkdir -p /usr/libexec/ccache-wrappers && \ | |
32 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ | |
33 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc | |
34 | ||
35 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" | |
36 | ENV LANG "en_US.UTF-8" | |
37 | ENV PYTHON "/usr/bin/python3" |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | ||
7 | # | |
8 | # We use pre-built containers for any pipelines that are: | |
9 | # | |
10 | # - Validating code committed on default upstream branch | |
11 | # - Validating patches targeting default upstream branch | |
12 | # which do not have CI changes | |
13 | # | |
14 | # We use a local build env for any pipelines that are: | |
15 | # | |
16 | # - Validating code committed to a non-default upstream branch | |
17 | # - Validating patches targeting a non-default upstream branch | |
18 | # - Validating patches targeting default upstream branch which | |
19 | # include CI changes | |
20 | # - Validating code committed to a fork branch | |
21 | # | |
22 | # Note: the rules across the prebuilt_env and local_env templates | |
23 | # should be logical inverses, such that jobs are mutually exclusive | |
24 | # | |
25 | .gitlab_native_build_job_prebuilt_env: | |
26 | image: $CI_REGISTRY/$RUN_UPSTREAM_NAMESPACE/libvirt-python/ci-$NAME:latest | |
27 | stage: builds | |
28 | interruptible: true | |
29 | before_script: | |
30 | - cat /packages.txt | |
31 | rules: | |
32 | # upstream: pushes to the default branch | |
33 | - if: '$CI_PROJECT_NAMESPACE == $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $JOB_OPTIONAL' | |
34 | when: manual | |
35 | allow_failure: true | |
36 | - if: '$CI_PROJECT_NAMESPACE == $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' | |
37 | when: on_success | |
38 | ||
39 | # upstream: other web/api/scheduled pipelines targeting the default branch | |
40 | - if: '$CI_PROJECT_NAMESPACE == $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE =~ /(web|api|schedule)/ && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH && $JOB_OPTIONAL' | |
41 | when: manual | |
42 | allow_failure: true | |
43 | - if: '$CI_PROJECT_NAMESPACE == $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE =~ /(web|api|schedule)/ && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH' | |
44 | when: on_success | |
45 | ||
46 | # upstream+forks: merge requests targeting the default branch, without CI changes | |
47 | - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH' | |
48 | changes: | |
49 | - ci/gitlab/container-templates.yml | |
50 | - ci/containers/$NAME.Dockerfile | |
51 | when: never | |
52 | - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH && $JOB_OPTIONAL' | |
53 | when: manual | |
54 | allow_failure: true | |
55 | - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH' | |
56 | when: on_success | |
57 | ||
58 | # upstream+forks: that's all folks | |
59 | - when: never | |
60 | ||
61 | .gitlab_native_build_job_local_env: | |
62 | image: $IMAGE | |
63 | stage: builds | |
64 | interruptible: true | |
65 | before_script: | |
66 | - source ci/buildenv/$NAME.sh | |
67 | - install_buildenv | |
68 | - cat /packages.txt | |
69 | rules: | |
70 | # upstream: pushes to a non-default branch | |
71 | - if: '$CI_PROJECT_NAMESPACE == $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH && $JOB_OPTIONAL' | |
72 | when: manual | |
73 | allow_failure: true | |
74 | - if: '$CI_PROJECT_NAMESPACE == $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH' | |
75 | when: on_success | |
76 | ||
77 | - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE && $JOB_OPTIONAL' | |
78 | when: manual | |
79 | allow_failure: true | |
80 | - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE' | |
81 | when: on_success | |
82 | ||
83 | # upstream: other web/api/scheduled pipelines targeting non-default branches | |
84 | - if: '$CI_PROJECT_NAMESPACE == $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE =~ /(web|api|schedule)/ && $CI_COMMIT_REF_NAME != $CI_DEFAULT_BRANCH && $JOB_OPTIONAL' | |
85 | when: manual | |
86 | allow_failure: true | |
87 | - if: '$CI_PROJECT_NAMESPACE == $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE =~ /(web|api|schedule)/ && $CI_COMMIT_REF_NAME != $CI_DEFAULT_BRANCH' | |
88 | when: on_success | |
89 | ||
90 | # forks: other web/api/scheduled pipelines | |
91 | - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE =~ /(web|api|schedule)/ && $JOB_OPTIONAL' | |
92 | when: manual | |
93 | allow_failure: true | |
94 | - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE =~ /(web|api|schedule)/' | |
95 | when: on_success | |
96 | ||
97 | # upstream+forks: merge requests targeting the default branch, with CI changes | |
98 | - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH && $JOB_OPTIONAL' | |
99 | changes: | |
100 | - ci/gitlab/container-templates.yml | |
101 | - ci/containers/$NAME.Dockerfile | |
102 | when: manual | |
103 | allow_failure: true | |
104 | - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH' | |
105 | changes: | |
106 | - ci/gitlab/container-templates.yml | |
107 | - ci/containers/$NAME.Dockerfile | |
108 | when: on_success | |
109 | ||
110 | # upstream+forks: merge requests targeting non-default branches | |
111 | - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME != $CI_DEFAULT_BRANCH && $JOB_OPTIONAL' | |
112 | when: manual | |
113 | allow_failure: true | |
114 | - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME != $CI_DEFAULT_BRANCH' | |
115 | when: on_success | |
116 | ||
117 | # upstream+forks: that's all folks | |
118 | - when: never |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | ||
7 | # Native build jobs | |
8 | ||
9 | x86_64-centos-stream-8-prebuilt-env: | |
10 | extends: .native_build_job_prebuilt_env | |
11 | needs: | |
12 | - job: x86_64-centos-stream-8-container | |
13 | optional: true | |
14 | allow_failure: false | |
15 | variables: | |
16 | NAME: centos-stream-8 | |
17 | artifacts: | |
18 | expire_in: 1 hour | |
19 | paths: | |
20 | - libvirt-python-rpms | |
21 | ||
22 | x86_64-centos-stream-8-local-env: | |
23 | extends: .native_build_job_local_env | |
24 | needs: [] | |
25 | allow_failure: false | |
26 | variables: | |
27 | IMAGE: quay.io/centos/centos:stream8 | |
28 | NAME: centos-stream-8 | |
29 | artifacts: | |
30 | expire_in: 1 hour | |
31 | paths: | |
32 | - libvirt-python-rpms | |
33 | ||
34 | ||
35 | x86_64-centos-stream-8-git-prebuilt-env: | |
36 | extends: .native_git_build_job_prebuilt_env | |
37 | needs: | |
38 | - job: x86_64-centos-stream-8-container | |
39 | optional: true | |
40 | allow_failure: false | |
41 | variables: | |
42 | NAME: centos-stream-8 | |
43 | artifacts: | |
44 | expire_in: 2 days | |
45 | paths: | |
46 | - scratch | |
47 | - build | |
48 | ||
49 | x86_64-centos-stream-8-git-local-env: | |
50 | extends: .native_git_build_job_local_env | |
51 | needs: [] | |
52 | allow_failure: false | |
53 | variables: | |
54 | IMAGE: quay.io/centos/centos:stream8 | |
55 | NAME: centos-stream-8 | |
56 | artifacts: | |
57 | expire_in: 2 days | |
58 | paths: | |
59 | - scratch | |
60 | - build | |
61 | ||
62 | ||
63 | x86_64-centos-stream-9-prebuilt-env: | |
64 | extends: .native_build_job_prebuilt_env | |
65 | needs: | |
66 | - job: x86_64-centos-stream-9-container | |
67 | optional: true | |
68 | allow_failure: false | |
69 | variables: | |
70 | NAME: centos-stream-9 | |
71 | artifacts: | |
72 | expire_in: 1 hour | |
73 | paths: | |
74 | - libvirt-python-rpms | |
75 | ||
76 | x86_64-centos-stream-9-local-env: | |
77 | extends: .native_build_job_local_env | |
78 | needs: [] | |
79 | allow_failure: false | |
80 | variables: | |
81 | IMAGE: quay.io/centos/centos:stream9 | |
82 | NAME: centos-stream-9 | |
83 | artifacts: | |
84 | expire_in: 1 hour | |
85 | paths: | |
86 | - libvirt-python-rpms | |
87 | ||
88 | ||
89 | x86_64-debian-10-prebuilt-env: | |
90 | extends: .native_build_job_prebuilt_env | |
91 | needs: | |
92 | - job: x86_64-debian-10-container | |
93 | optional: true | |
94 | allow_failure: false | |
95 | variables: | |
96 | NAME: debian-10 | |
97 | ||
98 | x86_64-debian-10-local-env: | |
99 | extends: .native_build_job_local_env | |
100 | needs: [] | |
101 | allow_failure: false | |
102 | variables: | |
103 | IMAGE: docker.io/library/debian:10-slim | |
104 | NAME: debian-10 | |
105 | ||
106 | ||
107 | x86_64-debian-sid-prebuilt-env: | |
108 | extends: .native_build_job_prebuilt_env | |
109 | needs: | |
110 | - job: x86_64-debian-sid-container | |
111 | optional: true | |
112 | allow_failure: false | |
113 | variables: | |
114 | NAME: debian-sid | |
115 | ||
116 | x86_64-debian-sid-local-env: | |
117 | extends: .native_build_job_local_env | |
118 | needs: [] | |
119 | allow_failure: false | |
120 | variables: | |
121 | IMAGE: docker.io/library/debian:sid-slim | |
122 | NAME: debian-sid | |
123 | ||
124 | ||
125 | x86_64-fedora-36-prebuilt-env: | |
126 | extends: .native_build_job_prebuilt_env | |
127 | needs: | |
128 | - job: x86_64-fedora-36-container | |
129 | optional: true | |
130 | allow_failure: false | |
131 | variables: | |
132 | NAME: fedora-36 | |
133 | artifacts: | |
134 | expire_in: 1 hour | |
135 | paths: | |
136 | - libvirt-python-rpms | |
137 | ||
138 | x86_64-fedora-36-local-env: | |
139 | extends: .native_build_job_local_env | |
140 | needs: [] | |
141 | allow_failure: false | |
142 | variables: | |
143 | IMAGE: registry.fedoraproject.org/fedora:36 | |
144 | NAME: fedora-36 | |
145 | artifacts: | |
146 | expire_in: 1 hour | |
147 | paths: | |
148 | - libvirt-python-rpms | |
149 | ||
150 | ||
151 | x86_64-fedora-37-prebuilt-env: | |
152 | extends: .native_build_job_prebuilt_env | |
153 | needs: | |
154 | - job: x86_64-fedora-37-container | |
155 | optional: true | |
156 | allow_failure: false | |
157 | variables: | |
158 | NAME: fedora-37 | |
159 | artifacts: | |
160 | expire_in: 1 hour | |
161 | paths: | |
162 | - libvirt-python-rpms | |
163 | ||
164 | x86_64-fedora-37-local-env: | |
165 | extends: .native_build_job_local_env | |
166 | needs: [] | |
167 | allow_failure: false | |
168 | variables: | |
169 | IMAGE: registry.fedoraproject.org/fedora:37 | |
170 | NAME: fedora-37 | |
171 | artifacts: | |
172 | expire_in: 1 hour | |
173 | paths: | |
174 | - libvirt-python-rpms | |
175 | ||
176 | ||
177 | x86_64-fedora-rawhide-prebuilt-env: | |
178 | extends: .native_build_job_prebuilt_env | |
179 | needs: | |
180 | - job: x86_64-fedora-rawhide-container | |
181 | optional: true | |
182 | allow_failure: false | |
183 | variables: | |
184 | NAME: fedora-rawhide | |
185 | ||
186 | x86_64-fedora-rawhide-local-env: | |
187 | extends: .native_build_job_local_env | |
188 | needs: [] | |
189 | allow_failure: false | |
190 | variables: | |
191 | IMAGE: registry.fedoraproject.org/fedora:rawhide | |
192 | NAME: fedora-rawhide | |
193 | ||
194 | ||
195 | x86_64-opensuse-leap-153-prebuilt-env: | |
196 | extends: .native_build_job_prebuilt_env | |
197 | needs: | |
198 | - job: x86_64-opensuse-leap-153-container | |
199 | optional: true | |
200 | allow_failure: false | |
201 | variables: | |
202 | NAME: opensuse-leap-153 | |
203 | RPM: skip | |
204 | ||
205 | x86_64-opensuse-leap-153-local-env: | |
206 | extends: .native_build_job_local_env | |
207 | needs: [] | |
208 | allow_failure: false | |
209 | variables: | |
210 | IMAGE: registry.opensuse.org/opensuse/leap:15.3 | |
211 | NAME: opensuse-leap-153 | |
212 | RPM: skip | |
213 | ||
214 | ||
215 | x86_64-opensuse-tumbleweed-prebuilt-env: | |
216 | extends: .native_build_job_prebuilt_env | |
217 | needs: | |
218 | - job: x86_64-opensuse-tumbleweed-container | |
219 | optional: true | |
220 | allow_failure: false | |
221 | variables: | |
222 | NAME: opensuse-tumbleweed | |
223 | RPM: skip | |
224 | ||
225 | x86_64-opensuse-tumbleweed-local-env: | |
226 | extends: .native_build_job_local_env | |
227 | needs: [] | |
228 | allow_failure: false | |
229 | variables: | |
230 | IMAGE: registry.opensuse.org/opensuse/tumbleweed:latest | |
231 | NAME: opensuse-tumbleweed | |
232 | RPM: skip | |
233 | ||
234 | ||
235 | x86_64-ubuntu-2004-prebuilt-env: | |
236 | extends: .native_build_job_prebuilt_env | |
237 | needs: | |
238 | - job: x86_64-ubuntu-2004-container | |
239 | optional: true | |
240 | allow_failure: false | |
241 | variables: | |
242 | NAME: ubuntu-2004 | |
243 | ||
244 | x86_64-ubuntu-2004-local-env: | |
245 | extends: .native_build_job_local_env | |
246 | needs: [] | |
247 | allow_failure: false | |
248 | variables: | |
249 | IMAGE: docker.io/library/ubuntu:20.04 | |
250 | NAME: ubuntu-2004 | |
251 | ||
252 | ||
253 | x86_64-ubuntu-2204-prebuilt-env: | |
254 | extends: .native_build_job_prebuilt_env | |
255 | needs: | |
256 | - job: x86_64-ubuntu-2204-container | |
257 | optional: true | |
258 | allow_failure: false | |
259 | variables: | |
260 | NAME: ubuntu-2204 | |
261 | ||
262 | x86_64-ubuntu-2204-local-env: | |
263 | extends: .native_build_job_local_env | |
264 | needs: [] | |
265 | allow_failure: false | |
266 | variables: | |
267 | IMAGE: docker.io/library/ubuntu:22.04 | |
268 | NAME: ubuntu-2204 |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | ||
7 | # We want to publish containers with tag 'latest': | |
8 | # | |
9 | # - In upstream, for push to default branch with CI changes. | |
10 | # - In upstream, on request, for scheduled/manual pipelines | |
11 | # against default branch | |
12 | # | |
13 | # Note: never publish from merge requests since they have non-committed code | |
14 | # | |
15 | .container_job: | |
16 | image: docker:stable | |
17 | stage: containers | |
18 | interruptible: false | |
19 | needs: [] | |
20 | services: | |
21 | - docker:dind | |
22 | before_script: | |
23 | - export TAG="$CI_REGISTRY_IMAGE/ci-$NAME:latest" | |
24 | - docker info | |
25 | - docker login "$CI_REGISTRY" -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" | |
26 | script: | |
27 | - docker build --tag "$TAG" -f "ci/containers/$NAME.Dockerfile" ci/containers ; | |
28 | - docker push "$TAG" | |
29 | after_script: | |
30 | - docker logout | |
31 | rules: | |
32 | # upstream: publish containers if there were CI changes on the default branch | |
33 | - if: '$CI_PROJECT_NAMESPACE == $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' | |
34 | when: on_success | |
35 | changes: | |
36 | - ci/gitlab/container-templates.yml | |
37 | - ci/containers/$NAME.Dockerfile | |
38 | ||
39 | # upstream: allow force re-publishing containers on default branch for web/api/scheduled pipelines | |
40 | - if: '$CI_PROJECT_NAMESPACE == $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE =~ /(web|api|schedule)/ && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH && $RUN_CONTAINER_BUILDS == "1"' | |
41 | when: on_success | |
42 | ||
43 | # upstream+forks: that's all folks | |
44 | - when: never |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | ||
7 | # Native container jobs | |
8 | ||
9 | x86_64-centos-stream-8-container: | |
10 | extends: .container_job | |
11 | allow_failure: false | |
12 | variables: | |
13 | NAME: centos-stream-8 | |
14 | ||
15 | ||
16 | x86_64-centos-stream-9-container: | |
17 | extends: .container_job | |
18 | allow_failure: false | |
19 | variables: | |
20 | NAME: centos-stream-9 | |
21 | ||
22 | ||
23 | x86_64-debian-10-container: | |
24 | extends: .container_job | |
25 | allow_failure: false | |
26 | variables: | |
27 | NAME: debian-10 | |
28 | ||
29 | ||
30 | x86_64-debian-sid-container: | |
31 | extends: .container_job | |
32 | allow_failure: false | |
33 | variables: | |
34 | NAME: debian-sid | |
35 | ||
36 | ||
37 | x86_64-fedora-36-container: | |
38 | extends: .container_job | |
39 | allow_failure: false | |
40 | variables: | |
41 | NAME: fedora-36 | |
42 | ||
43 | ||
44 | x86_64-fedora-37-container: | |
45 | extends: .container_job | |
46 | allow_failure: false | |
47 | variables: | |
48 | NAME: fedora-37 | |
49 | ||
50 | ||
51 | x86_64-fedora-rawhide-container: | |
52 | extends: .container_job | |
53 | allow_failure: false | |
54 | variables: | |
55 | NAME: fedora-rawhide | |
56 | ||
57 | ||
58 | x86_64-opensuse-leap-153-container: | |
59 | extends: .container_job | |
60 | allow_failure: false | |
61 | variables: | |
62 | NAME: opensuse-leap-153 | |
63 | ||
64 | ||
65 | x86_64-opensuse-tumbleweed-container: | |
66 | extends: .container_job | |
67 | allow_failure: false | |
68 | variables: | |
69 | NAME: opensuse-tumbleweed | |
70 | ||
71 | ||
72 | x86_64-ubuntu-2004-container: | |
73 | extends: .container_job | |
74 | allow_failure: false | |
75 | variables: | |
76 | NAME: ubuntu-2004 | |
77 | ||
78 | ||
79 | x86_64-ubuntu-2204-container: | |
80 | extends: .container_job | |
81 | allow_failure: false | |
82 | variables: | |
83 | NAME: ubuntu-2204 |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | ||
7 | check-dco: | |
8 | stage: sanity_checks | |
9 | needs: [] | |
10 | image: registry.gitlab.com/libvirt/libvirt-ci/check-dco:master | |
11 | interruptible: true | |
12 | script: | |
13 | - /check-dco "$RUN_UPSTREAM_NAMESPACE" | |
14 | rules: | |
15 | # upstream+forks: Run pipelines on MR | |
16 | - if: '$CI_PIPELINE_SOURCE =~ "merge_request_event"' | |
17 | when: on_success | |
18 | ||
19 | # forks: pushes to branches with pipeline requested | |
20 | - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH && $RUN_PIPELINE' | |
21 | when: on_success | |
22 | ||
23 | # upstream+forks: that's all folks | |
24 | - when: never | |
25 | variables: | |
26 | GIT_DEPTH: 1000 |
0 | # THIS FILE WAS AUTO-GENERATED | |
1 | # | |
2 | # $ lcitool manifest ci/manifest.yml | |
3 | # | |
4 | # https://gitlab.com/libvirt/libvirt-ci | |
5 | ||
6 | ||
7 | # Variables that can be set to control the behaviour of | |
8 | # pipelines that are run | |
9 | # | |
10 | # - RUN_PIPELINE - force creation of a CI pipeline when | |
11 | # pushing to a branch in a forked repository. Official | |
12 | # CI pipelines are triggered when merge requests are | |
13 | # created/updated. Setting this variable to a non-empty | |
14 | # value allows CI testing prior to opening a merge request. | |
15 | # | |
16 | # - RUN_CONTAINER_BUILDS - CI pipelines in upstream only | |
17 | # publish containers if CI file changes are detected. | |
18 | # Setting this variable to a non-empty value will force | |
19 | # re-publishing, even when no file changes are detected. | |
20 | # Typically to use from a scheduled job once a month. | |
21 | # | |
22 | # - RUN_UPSTREAM_NAMESPACE - the upstream namespace is | |
23 | # configured to default to 'libvirt'. When testing | |
24 | # changes to CI it might be useful to use a different | |
25 | # upstream. Setting this variable will override the | |
26 | # namespace considered to be upstream. | |
27 | # | |
28 | # These can be set as git push options | |
29 | # | |
30 | # $ git push -o ci.variable=RUN_PIPELINE=1 | |
31 | # | |
32 | # Aliases can be set for common usage | |
33 | # | |
34 | # $ git config --local alias.push-ci "push -o ci.variable=RUN_PIPELINE=1" | |
35 | # | |
36 | # Allowing the less verbose invocation | |
37 | # | |
38 | # $ git push-ci | |
39 | # | |
40 | # Pipeline variables can also be set in the repository | |
41 | # pipeline config globally, or set against scheduled pipelines | |
42 | ||
43 | ||
44 | variables: | |
45 | RUN_UPSTREAM_NAMESPACE: libvirt | |
46 | ||
47 | ||
48 | workflow: | |
49 | rules: | |
50 | # upstream+forks: Avoid duplicate pipelines on pushes, if a MR is open | |
51 | - if: '$CI_PIPELINE_SOURCE == "push" && $CI_OPEN_MERGE_REQUESTS' | |
52 | when: never | |
53 | ||
54 | # upstream+forks: Avoid pipelines on tag pushes | |
55 | - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_TAG' | |
56 | when: never | |
57 | ||
58 | # upstream+forks: Allow pipelines in scenarios we've figured out job rules | |
59 | - if: '$CI_PIPELINE_SOURCE =~ /^(push|merge_request_event|api|web|schedule)$/' | |
60 | when: always | |
61 | ||
62 | # upstream+forks: Avoid all other pipelines | |
63 | - when: never | |
64 | ||
65 | ||
66 | debug: | |
67 | image: docker.io/library/alpine:3 | |
68 | stage: sanity_checks | |
69 | interruptible: true | |
70 | needs: [] | |
71 | script: | |
72 | - printenv | sort | |
73 | rules: | |
74 | - if: '$RUN_DEBUG' | |
75 | when: always | |
76 | ||
77 | include: | |
78 | - local: '/ci/gitlab/container-templates.yml' | |
79 | - local: '/ci/gitlab/build-templates.yml' | |
80 | - local: '/ci/gitlab/sanity-checks.yml' | |
81 | - local: '/ci/gitlab/containers.yml' | |
82 | - local: '/ci/gitlab/builds.yml' |
0 | projects: | |
1 | - libvirt-python | |
2 | - libvirt+dist | |
3 | ||
4 | gitlab: | |
5 | namespace: libvirt | |
6 | project: libvirt-python | |
7 | ||
8 | targets: | |
9 | ||
10 | centos-stream-8: | |
11 | projects: | |
12 | - libvirt-python | |
13 | - libvirt+minimal | |
14 | - libvirt+dist | |
15 | ||
16 | jobs: | |
17 | - arch: x86_64 | |
18 | artifacts: | |
19 | expire_in: 1 hour | |
20 | paths: | |
21 | - libvirt-python-rpms | |
22 | ||
23 | - arch: x86_64 | |
24 | template: .native_git_build_job | |
25 | suffix: -git | |
26 | artifacts: | |
27 | expire_in: 2 days | |
28 | paths: | |
29 | - scratch | |
30 | - build | |
31 | ||
32 | centos-stream-9: | |
33 | jobs: | |
34 | - arch: x86_64 | |
35 | artifacts: | |
36 | expire_in: 1 hour | |
37 | paths: | |
38 | - libvirt-python-rpms | |
39 | ||
40 | debian-10: x86_64 | |
41 | ||
42 | debian-sid: x86_64 | |
43 | ||
44 | fedora-36: | |
45 | jobs: | |
46 | - arch: x86_64 | |
47 | artifacts: | |
48 | expire_in: 1 hour | |
49 | paths: | |
50 | - libvirt-python-rpms | |
51 | ||
52 | fedora-37: | |
53 | jobs: | |
54 | - arch: x86_64 | |
55 | artifacts: | |
56 | expire_in: 1 hour | |
57 | paths: | |
58 | - libvirt-python-rpms | |
59 | ||
60 | fedora-rawhide: x86_64 | |
61 | ||
62 | opensuse-leap-153: | |
63 | jobs: | |
64 | - arch: x86_64 | |
65 | variables: | |
66 | RPM: skip | |
67 | ||
68 | opensuse-tumbleweed: | |
69 | jobs: | |
70 | - arch: x86_64 | |
71 | variables: | |
72 | RPM: skip | |
73 | ||
74 | ubuntu-2004: x86_64 | |
75 | ||
76 | ubuntu-2204: x86_64 |
0 | Some simple examples on how to use the Python API for libvirt | |
1 | ||
2 | The examples are: | |
3 | ||
4 | dominfo.py - print information about a running domU based on the results of | |
5 | virDomainGetInfo and virDomainGetXMLDesc | |
6 | domstart.py - create a domU from an XML description if the domU isn't | |
7 | running yet | |
8 | domsave.py - save all running domU's into a directory | |
9 | domrestore.py - restore domU's from their saved files in a directory | |
10 | esxlist.py - list active domains of an VMware ESX host and print some info. | |
11 | also demonstrates how to use the libvirt.openAuth() method | |
12 | dhcpleases.py - list dhcp leases for a given virtual network | |
13 | domipaddrs.py - list IP addresses for guest domains | |
14 | guest-vcpus - two helpers to make the guest agent event useful with agent based | |
15 | vCPU state modification | |
16 | nodestats.py - print total memory and free memory for each host NUMA node and | |
17 | the memory strictly bound to certain host nodes for each running | |
18 | domain. | |
19 | ||
20 | Some additional notes for the esxlist.py example: | |
21 | ||
22 | You may see remote errors complaining about missing certificates: | |
23 | ||
24 | Cannot access CA certificate '/usr/local/etc/pki/CA/cacert.pem': No such file | |
25 | or directory | |
26 | ||
27 | This is expected, libvirt tries to find network and storage drivers for ESX, | |
28 | but those are not implemented yet (November 2009). While searching for this | |
29 | drivers, libvirt may try to start a local libvirtd instance, but fails because | |
30 | of the missing certificates. It'll warn about that: | |
31 | ||
32 | Failed to find the network: Is the daemon running? | |
33 | ||
34 | This is also expected and can be ignored. |
0 | #!/usr/bin/env python3 | |
1 | """ | |
2 | Print leases info for a given virtual network | |
3 | """ | |
4 | ||
5 | import libvirt | |
6 | import time | |
7 | from argparse import ArgumentParser | |
8 | ||
9 | ||
10 | parser = ArgumentParser(description=__doc__) | |
11 | parser.add_argument("uri", nargs="?", default=None) | |
12 | parser.add_argument("network") | |
13 | args = parser.parse_args() | |
14 | ||
15 | try: | |
16 | conn = libvirt.open(args.uri) | |
17 | except libvirt.libvirtError: | |
18 | print("Unable to open connection to libvirt") | |
19 | exit(1) | |
20 | ||
21 | try: | |
22 | net = conn.networkLookupByName(args.network) | |
23 | except libvirt.libvirtError: | |
24 | print("Network %s not found" % args.network) | |
25 | exit(0) | |
26 | ||
27 | leases = net.DHCPLeases() | |
28 | if not leases: | |
29 | print("Failed to get leases for %s" % net.name()) | |
30 | exit(0) | |
31 | ||
32 | ||
33 | def toIPAddrType(addrType: int) -> str: | |
34 | if addrType == libvirt.VIR_IP_ADDR_TYPE_IPV4: | |
35 | return "ipv4" | |
36 | elif addrType == libvirt.VIR_IP_ADDR_TYPE_IPV6: | |
37 | return "ipv6" | |
38 | return "Unknown" | |
39 | ||
40 | ||
41 | print(" {0:20} {1:18} {2:9} {3:25} {4:15} {5}".format("Expiry Time", | |
42 | "MAC address", | |
43 | "Protocol", | |
44 | "IP address", | |
45 | "Hostname", | |
46 | "Client ID or DUID")) | |
47 | print("-" * 115) | |
48 | ||
49 | for lease in leases: | |
50 | print(" {0:20} {1:18} {2:9} {3:25} {4:15} {5}".format( | |
51 | time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(lease['expirytime'])), | |
52 | lease['mac'], | |
53 | toIPAddrType(lease['type']), | |
54 | "{}/{}".format(lease['ipaddr'], lease['prefix']), | |
55 | lease['hostname'], | |
56 | lease['clientid'] | |
57 | )) |
437 | 437 | def virEventLoopPollStart() -> None: |
438 | 438 | global eventLoopThread |
439 | 439 | virEventLoopPollRegister() |
440 | eventLoopThread = threading.Thread(target=virEventLoopPollRun, name="libvirtEventLoop") | |
441 | eventLoopThread.setDaemon(True) | |
440 | eventLoopThread = threading.Thread(target=virEventLoopPollRun, | |
441 | name="libvirtEventLoop", | |
442 | daemon=True) | |
442 | 443 | eventLoopThread.start() |
443 | 444 | |
444 | 445 | |
448 | 449 | import asyncio |
449 | 450 | loop = asyncio.new_event_loop() |
450 | 451 | libvirtaio.virEventRegisterAsyncIOImpl(loop=loop) |
451 | eventLoopThread = threading.Thread(target=virEventLoopAIORun, args=(loop,), name="libvirtEventLoop") | |
452 | eventLoopThread.setDaemon(True) | |
452 | eventLoopThread = threading.Thread(target=virEventLoopAIORun, | |
453 | args=(loop,), | |
454 | name="libvirtEventLoop", | |
455 | daemon=True) | |
453 | 456 | eventLoopThread.start() |
454 | 457 | |
455 | 458 | |
456 | 459 | def virEventLoopNativeStart() -> None: |
457 | 460 | global eventLoopThread |
458 | 461 | libvirt.virEventRegisterDefaultImpl() |
459 | eventLoopThread = threading.Thread(target=virEventLoopNativeRun, name="libvirtEventLoop") | |
460 | eventLoopThread.setDaemon(True) | |
462 | eventLoopThread = threading.Thread(target=virEventLoopNativeRun, | |
463 | name="libvirtEventLoop", | |
464 | daemon=True) | |
461 | 465 | eventLoopThread.start() |
462 | 466 | |
463 | 467 |
15 | 15 | EnumType = Dict[str, EnumValue] |
16 | 16 | |
17 | 17 | functions = {} # type: Dict[str, FunctionType] |
18 | lxc_functions = {} # type: Dict[str, FunctionType] | |
19 | qemu_functions = {} # type: Dict[str, FunctionType] | |
20 | 18 | enums = defaultdict(dict) # type: Dict[str, EnumType] # { enumType: { enumConstant: enumValue } } |
21 | lxc_enums = defaultdict(dict) # type: Dict[str, EnumType] # { enumType: { enumConstant: enumValue } } | |
22 | qemu_enums = defaultdict(dict) # type: Dict[str, EnumType] # { enumType: { enumConstant: enumValue } } | |
23 | 19 | event_ids = [] # type: List[str] |
24 | 20 | params = [] # type: List[Tuple[str, str]] # [ (paramName, paramValue)... ] |
25 | 21 | |
101 | 97 | self.function_return_field = attrs.get('field', '') |
102 | 98 | elif tag == 'enum': |
103 | 99 | # enums come from header files, hence virterror.h |
104 | if attrs['file'] in libvirt_headers + ["virerror", "virterror"]: | |
100 | files = libvirt_headers + ["virerror", | |
101 | "virterror", | |
102 | "libvirt-lxc", | |
103 | "libvirt-qemu"] | |
104 | if attrs['file'] in files: | |
105 | 105 | enum(attrs['type'], attrs['name'], attrs['value']) |
106 | elif attrs['file'] == "libvirt-lxc": | |
107 | lxc_enum(attrs['type'], attrs['name'], attrs['value']) | |
108 | elif attrs['file'] == "libvirt-qemu": | |
109 | qemu_enum(attrs['type'], attrs['name'], attrs['value']) | |
110 | 106 | elif tag == "macro": |
111 | 107 | if "string" in attrs: |
112 | 108 | params.append((attrs['name'], attrs['string'])) |
118 | 114 | # functions come from source files, hence 'virerror.c' |
119 | 115 | if self.function: |
120 | 116 | assert self.function_return |
121 | if self.function_module in libvirt_headers + \ | |
122 | ["event", "virevent", "virerror", "virterror"]: | |
117 | ||
118 | modules = libvirt_headers + ["event", | |
119 | "virevent", | |
120 | "virerror", | |
121 | "virterror", | |
122 | "libvirt-lxc", | |
123 | "libvirt-qemu"] | |
124 | files = ["python", "python-lxc", "python-qemu"] | |
125 | ||
126 | if (self.function_module in modules or | |
127 | self.function_file in files): | |
123 | 128 | function(self.function, self.function_descr, |
124 | 129 | self.function_return, self.function_args, |
125 | 130 | self.function_file, self.function_module, |
126 | 131 | self.function_cond) |
127 | elif self.function_module == "libvirt-lxc": | |
128 | lxc_function(self.function, self.function_descr, | |
129 | self.function_return, self.function_args, | |
130 | self.function_file, self.function_module, | |
131 | self.function_cond) | |
132 | elif self.function_module == "libvirt-qemu": | |
133 | qemu_function(self.function, self.function_descr, | |
134 | self.function_return, self.function_args, | |
135 | self.function_file, self.function_module, | |
136 | self.function_cond) | |
137 | elif self.function_file == "python": | |
138 | function(self.function, self.function_descr, | |
139 | self.function_return, self.function_args, | |
140 | self.function_file, self.function_module, | |
141 | self.function_cond) | |
142 | elif self.function_file == "python-lxc": | |
143 | lxc_function(self.function, self.function_descr, | |
144 | self.function_return, self.function_args, | |
145 | self.function_file, self.function_module, | |
146 | self.function_cond) | |
147 | elif self.function_file == "python-qemu": | |
148 | qemu_function(self.function, self.function_descr, | |
149 | self.function_return, self.function_args, | |
150 | self.function_file, self.function_module, | |
151 | self.function_cond) | |
152 | 132 | self.in_function = False |
153 | 133 | elif tag == 'arg': |
154 | 134 | if self.in_function: |
176 | 156 | if name == "virConnectListDomains": |
177 | 157 | name = "virConnectListDomainsID" |
178 | 158 | functions[name] = (desc, ret, args, file, module, cond) |
179 | ||
180 | ||
181 | def qemu_function(name: str, desc: str, ret: ArgumentType, args: List[ArgumentType], file: str, module: str, cond: str) -> None: | |
182 | if onlyOverrides and name not in qemu_functions: | |
183 | return | |
184 | qemu_functions[name] = (desc, ret, args, file, module, cond) | |
185 | ||
186 | ||
187 | def lxc_function(name: str, desc: str, ret: ArgumentType, args: List[ArgumentType], file: str, module: str, cond: str) -> None: | |
188 | if onlyOverrides and name not in lxc_functions: | |
189 | return | |
190 | lxc_functions[name] = (desc, ret, args, file, module, cond) | |
191 | 159 | |
192 | 160 | |
193 | 161 | def enum(type: str, name: str, value: EnumValue) -> None: |
212 | 180 | value = 1 |
213 | 181 | elif value == 'VIR_DOMAIN_AFFECT_CONFIG': |
214 | 182 | value = 2 |
215 | if onlyOverrides and name not in enums[type]: | |
216 | return | |
217 | enums[type][name] = value | |
218 | ||
219 | ||
220 | def lxc_enum(type: str, name: str, value: EnumValue) -> None: | |
221 | if onlyOverrides and name not in lxc_enums[type]: | |
222 | return | |
223 | lxc_enums[type][name] = value | |
224 | ||
225 | ||
226 | def qemu_enum(type: str, name: str, value: EnumValue) -> None: | |
227 | if value == 'VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_BLOCK': | |
183 | elif value == 'VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_BLOCK': | |
228 | 184 | value = -2 |
229 | 185 | elif value == 'VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_DEFAULT': |
230 | 186 | value = -1 |
231 | 187 | elif value == 'VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_NOWAIT': |
232 | 188 | value = 0 |
233 | if onlyOverrides and name not in qemu_enums[type]: | |
189 | ||
190 | if onlyOverrides and name not in enums[type]: | |
234 | 191 | return |
235 | qemu_enums[type][name] = value | |
192 | enums[type][name] = value | |
236 | 193 | |
237 | 194 | |
238 | 195 | ####################################################################### |
241 | 198 | # be exposed as-is on the Python interface |
242 | 199 | # |
243 | 200 | ####################################################################### |
244 | ||
245 | functions_skipped = { | |
246 | "virConnectListDomains", | |
247 | } | |
248 | lxc_functions_skipped = set() # type: Set[str] | |
249 | qemu_functions_skipped = set() # type: Set[str] | |
250 | 201 | |
251 | 202 | skipped_types = { |
252 | 203 | # 'int *': "usually a return type", |
341 | 292 | 'const virDomainSnapshot *': ('O', "virDomainSnapshot", "virDomainSnapshotPtr", "virDomainSnapshotPtr"), |
342 | 293 | } # type: Dict[str, Tuple[str, str, str, str]] |
343 | 294 | |
344 | ||
345 | unknown_types = defaultdict(list) # type: Dict[str, List[str]] | |
346 | 295 | |
347 | 296 | ####################################################################### |
348 | 297 | # |
481 | 430 | 'virDomainAuthorizedSSHKeysSet', |
482 | 431 | 'virDomainGetMessages', |
483 | 432 | 'virNodeDeviceGetAutostart', |
484 | } | |
485 | ||
486 | lxc_skip_impl = { | |
433 | 'virDomainSaveParams', | |
434 | 'virDomainRestoreParams', | |
435 | ||
487 | 436 | 'virDomainLxcOpenNamespace', |
488 | } | |
489 | ||
490 | qemu_skip_impl = { | |
437 | ||
491 | 438 | 'virDomainQemuMonitorCommand', |
492 | 439 | 'virDomainQemuAgentCommand', |
493 | 440 | } |
536 | 483 | 'virConnectListAllSecrets', # overridden in virConnect.py |
537 | 484 | 'virConnectGetAllDomainStats', # overridden in virConnect.py |
538 | 485 | 'virDomainListGetStats', # overridden in virConnect.py |
486 | 'virDomainFDAssociate', # overridden in virDomain.py | |
539 | 487 | |
540 | 488 | 'virStreamRecvAll', # Pure python libvirt-override-virStream.py |
541 | 489 | 'virStreamSendAll', # Pure python libvirt-override-virStream.py |
615 | 563 | 'virDomainFSInfoFree', # only useful in C, python code uses list |
616 | 564 | 'virDomainIOThreadInfoFree', # only useful in C, python code uses list |
617 | 565 | 'virDomainInterfaceFree', # only useful in C, python code uses list |
618 | } | |
619 | ||
620 | lxc_skip_function = { | |
566 | ||
621 | 567 | "virDomainLxcEnterNamespace", |
622 | 568 | "virDomainLxcEnterSecurityLabel", |
623 | } | |
624 | qemu_skip_function = { | |
569 | ||
625 | 570 | # "virDomainQemuAttach", |
626 | 571 | 'virConnectDomainQemuMonitorEventRegister', # overridden in -qemu.py |
627 | 572 | 'virConnectDomainQemuMonitorEventDeregister', # overridden in -qemu.py |
573 | 'virDomainQemuMonitorCommandWithFiles', # overridden in -qemu.py | |
628 | 574 | } |
629 | 575 | |
630 | 576 | # Generate C code, but skip python impl |
633 | 579 | # be exposed in bindings |
634 | 580 | } |
635 | 581 | |
636 | lxc_function_skip_python_impl = set() # type: Set[str] | |
637 | qemu_function_skip_python_impl = set() # type: Set[str] | |
638 | ||
639 | 582 | function_skip_index_one = { |
640 | 583 | "virDomainRevertToSnapshot", |
641 | 584 | } |
642 | 585 | |
643 | 586 | |
644 | def print_function_wrapper(module: str, name: str, output: IO[str], export: IO[str], include: IO[str]) -> int: | |
587 | def validate_function(name): | |
588 | (desc, ret, args, file, mod, cond) = functions[name] | |
589 | ||
590 | if name in skip_function: | |
591 | return [] | |
592 | if name in skip_impl: | |
593 | return [] | |
594 | ||
595 | failed = False | |
596 | unknown = [] | |
597 | for a_name, a_type, a_info in args: | |
598 | # This should be correct | |
599 | if a_type[0:6] == "const ": | |
600 | a_type = a_type[6:] | |
601 | ||
602 | if a_type in skipped_types: | |
603 | return [] | |
604 | ||
605 | if a_type not in py_types: | |
606 | unknown.append(a_type) | |
607 | ||
608 | r_type, r_info, r_field = ret | |
609 | if r_type in skipped_types: | |
610 | return [] | |
611 | if r_type != 'void' and r_type not in py_types: | |
612 | unknown.append(r_type) | |
613 | ||
614 | return unknown | |
615 | ||
616 | ||
617 | def validate_functions(): | |
618 | unknown_types = defaultdict(list) # type: Dict[str, List[str]] | |
619 | funcs_failed = [] # type: List[str] | |
620 | ||
621 | for name in sorted(functions): | |
622 | unknown = validate_function(name) | |
623 | if unknown: | |
624 | funcs_failed.append(name) | |
625 | for thetype in unknown: | |
626 | unknown_types[thetype].append(name) | |
627 | ||
628 | if unknown_types: | |
629 | print("Missing type converters: ") | |
630 | for type, count in unknown_types.items(): | |
631 | print("%s:%d " % (type, len(count))) | |
632 | ||
633 | for f in funcs_failed: | |
634 | print("ERROR: failed %s" % f) | |
635 | ||
636 | if funcs_failed: | |
637 | return -1 | |
638 | ||
639 | return 0 | |
640 | ||
641 | ||
642 | def skip_both_impl(name: str) -> bool: | |
643 | if name in skip_function: | |
644 | return True | |
645 | ||
646 | (desc, ret, args, file, mod, cond) = functions[name] | |
647 | ||
648 | for a_name, a_type, a_info in args: | |
649 | # This should be correct | |
650 | if a_type[0:6] == "const ": | |
651 | a_type = a_type[6:] | |
652 | ||
653 | if a_type in skipped_types: | |
654 | return True | |
655 | ||
656 | r_type, r_info, r_field = ret | |
657 | if r_type in skipped_types: | |
658 | return True | |
659 | ||
660 | return False | |
661 | ||
662 | ||
663 | def skip_c_impl(name: str) -> bool: | |
664 | if skip_both_impl(name): | |
665 | return True | |
666 | ||
667 | if name in skip_impl: | |
668 | return True | |
669 | ||
670 | return False | |
671 | ||
672 | ||
673 | def skip_py_impl(name: str) -> bool: | |
674 | if skip_both_impl(name): | |
675 | return True | |
676 | ||
677 | if name in function_skip_python_impl: | |
678 | return True | |
679 | ||
680 | return False | |
681 | ||
682 | ||
683 | def print_function_wrapper(package: str, name: str, output: IO[str], export: IO[str], include: IO[str]) -> bool: | |
645 | 684 | """ |
646 | :returns: -1 on failure, 0 on skip, 1 on success. | |
685 | :returns: True if generated, False if skipped | |
647 | 686 | """ |
648 | try: | |
649 | if module == "libvirt": | |
650 | (desc, ret, args, file, mod, cond) = functions[name] | |
651 | skip_function2, skip_impl2 = skip_function, skip_impl | |
652 | elif module == "libvirt-lxc": | |
653 | (desc, ret, args, file, mod, cond) = lxc_functions[name] | |
654 | skip_function2, skip_impl2 = lxc_skip_function, lxc_skip_impl | |
655 | elif module == "libvirt-qemu": | |
656 | (desc, ret, args, file, mod, cond) = qemu_functions[name] | |
657 | skip_function2, skip_impl2 = qemu_skip_function, qemu_skip_impl | |
658 | else: | |
659 | raise ValueError(module) | |
660 | except Exception: | |
661 | print("failed to get function %s infos" % name) | |
662 | return -1 | |
663 | ||
664 | if name in skip_function2: | |
665 | return 0 | |
666 | if name in skip_impl2: | |
667 | # Don't delete the function entry in the caller. | |
668 | return 1 | |
687 | (desc, ret, args, file, mod, cond) = functions[name] | |
688 | ||
689 | if skip_c_impl(name): | |
690 | return False | |
669 | 691 | |
670 | 692 | c_call = "" |
671 | 693 | format = "" |
699 | 721 | c_call += ", " |
700 | 722 | c_call += "%s" % (a_name) |
701 | 723 | else: |
702 | if a_type in skipped_types: | |
703 | return 0 | |
704 | unknown_types[a_type].append(name) | |
705 | return -1 | |
724 | raise Exception("Unexpected type %s in function %s" % (a_type, name)) | |
706 | 725 | if format: |
707 | 726 | format += ":%s" % (name) |
708 | 727 | |
732 | 751 | ret_convert += " free(c_retval);\n" |
733 | 752 | ret_convert += " return py_retval;\n" |
734 | 753 | else: |
735 | if r_type in skipped_types: | |
736 | return 0 | |
737 | unknown_types[r_type].append(name) | |
738 | return -1 | |
754 | raise Exception("Unexpected type %s in function %s" % (r_type, name)) | |
739 | 755 | |
740 | 756 | if cond: |
741 | 757 | include.write("#if %s\n" % cond) |
743 | 759 | output.write("#if %s\n" % cond) |
744 | 760 | |
745 | 761 | include.write("PyObject * ") |
746 | if module == "libvirt": | |
747 | include.write("libvirt_%s(PyObject *self, PyObject *args);\n" % (name)) | |
748 | export.write(" { (char *)\"%s\", libvirt_%s, METH_VARARGS, NULL },\n" % | |
749 | (name, name)) | |
750 | elif module == "libvirt-lxc": | |
751 | include.write("libvirt_lxc_%s(PyObject *self, PyObject *args);\n" % (name)) | |
752 | export.write(" { (char *)\"%s\", libvirt_lxc_%s, METH_VARARGS, NULL },\n" % | |
753 | (name, name)) | |
754 | elif module == "libvirt-qemu": | |
755 | include.write("libvirt_qemu_%s(PyObject *self, PyObject *args);\n" % (name)) | |
756 | export.write(" { (char *)\"%s\", libvirt_qemu_%s, METH_VARARGS, NULL },\n" % | |
757 | (name, name)) | |
762 | include.write("%s_%s(PyObject *self, PyObject *args);\n" % (package, name)) | |
763 | export.write(" { (char *)\"%s\", %s_%s, METH_VARARGS, NULL },\n" % | |
764 | (name, package, name)) | |
758 | 765 | |
759 | 766 | if file == "python": |
760 | 767 | # Those have been manually generated |
762 | 769 | include.write("#endif\n") |
763 | 770 | export.write("#endif\n") |
764 | 771 | output.write("#endif\n") |
765 | return 1 | |
772 | return True | |
766 | 773 | if file == "python_accessor" and r_type != "void" and not r_field: |
767 | 774 | # Those have been manually generated |
768 | 775 | if cond: |
769 | 776 | include.write("#endif\n") |
770 | 777 | export.write("#endif\n") |
771 | 778 | output.write("#endif\n") |
772 | return 1 | |
779 | return True | |
773 | 780 | |
774 | 781 | output.write("PyObject *\n") |
775 | if module == "libvirt": | |
776 | output.write("libvirt_%s(PyObject *self ATTRIBUTE_UNUSED," % (name)) | |
777 | elif module == "libvirt-lxc": | |
778 | output.write("libvirt_lxc_%s(PyObject *self ATTRIBUTE_UNUSED," % (name)) | |
779 | elif module == "libvirt-qemu": | |
780 | output.write("libvirt_qemu_%s(PyObject *self ATTRIBUTE_UNUSED," % (name)) | |
782 | output.write("%s_%s(PyObject *self ATTRIBUTE_UNUSED," % (package, name)) | |
781 | 783 | output.write(" PyObject *args") |
782 | 784 | if format == "": |
783 | 785 | output.write(" ATTRIBUTE_UNUSED") |
805 | 807 | export.write("#endif /* %s */\n" % cond) |
806 | 808 | output.write("#endif /* %s */\n" % cond) |
807 | 809 | |
808 | if module == "libvirt": | |
809 | if name in function_skip_python_impl: | |
810 | return 0 | |
811 | elif module == "libvirt-lxc": | |
812 | if name in lxc_function_skip_python_impl: | |
813 | return 0 | |
814 | elif module == "libvirt-qemu": | |
815 | if name in qemu_function_skip_python_impl: | |
816 | return 0 | |
817 | return 1 | |
810 | return True | |
818 | 811 | |
819 | 812 | |
820 | 813 | def print_c_pointer(classname: str, output: IO[str], export: IO[str], include: IO[str]) -> None: |
839 | 832 | (classname, classname)) |
840 | 833 | |
841 | 834 | |
842 | def buildStubs(module: str, api_xml: str) -> int: | |
835 | def load_apis(module: str, api_xml: str): | |
843 | 836 | global onlyOverrides |
844 | ||
845 | if module not in ["libvirt", "libvirt-qemu", "libvirt-lxc"]: | |
846 | print("ERROR: Unknown module type: %s" % module) | |
847 | return -1 | |
848 | ||
849 | if module == "libvirt": | |
850 | funcs = functions | |
851 | funcs_skipped = functions_skipped | |
852 | elif module == "libvirt-lxc": | |
853 | funcs = lxc_functions | |
854 | funcs_skipped = lxc_functions_skipped | |
855 | elif module == "libvirt-qemu": | |
856 | funcs = qemu_functions | |
857 | funcs_skipped = qemu_functions_skipped | |
858 | 837 | |
859 | 838 | try: |
860 | 839 | onlyOverrides = False |
864 | 843 | print(api_xml, ":", msg) |
865 | 844 | sys.exit(1) |
866 | 845 | |
867 | n = len(funcs) | |
846 | n = len(functions) | |
868 | 847 | if not quiet: |
869 | 848 | print("Found %d functions in %s" % ((n), api_xml)) |
870 | 849 | |
881 | 860 | if not quiet: |
882 | 861 | # XXX: This is not right, same function already in @functions |
883 | 862 | # will be overwritten. |
884 | print("Found %d functions in %s" % (len(funcs) - n, override_api_xml)) | |
863 | print("Found %d functions in %s" % (len(functions) - n, override_api_xml)) | |
864 | ||
865 | ||
866 | def emit_c_code(module: str) -> None: | |
867 | package = module.replace('-', '_') | |
868 | ||
885 | 869 | nb_wrap = 0 |
886 | failed = 0 | |
887 | skipped = 0 | |
888 | funcs_failed = [] # type: List[str] | |
889 | 870 | |
890 | 871 | header_file = "build/%s.h" % module |
891 | 872 | export_file = "build/%s-export.c" % module |
904 | 885 | wrapper.write("#include \"typewrappers.h\"\n") |
905 | 886 | wrapper.write("#include \"build/%s.h\"\n\n" % (module,)) |
906 | 887 | |
907 | for function in sorted(funcs): | |
908 | # Skip the functions which are not for the module | |
909 | ret = print_function_wrapper(module, function, wrapper, export, include) | |
910 | if ret < 0: | |
911 | failed += 1 | |
912 | funcs_failed.append(function) | |
913 | del funcs[function] | |
914 | if ret == 0: | |
915 | skipped += 1 | |
916 | funcs_skipped.add(function) | |
917 | del funcs[function] | |
918 | if ret == 1: | |
888 | for function in sorted(functions): | |
889 | if print_function_wrapper(package, function, wrapper, export, include): | |
919 | 890 | nb_wrap += 1 |
920 | 891 | |
921 | 892 | if module == "libvirt": |
933 | 904 | |
934 | 905 | if not quiet: |
935 | 906 | print("Generated %d wrapper functions" % nb_wrap) |
936 | ||
937 | if unknown_types: | |
938 | print("Missing type converters: ") | |
939 | for type, count in unknown_types.items(): | |
940 | print("%s:%d " % (type, len(count))) | |
941 | ||
942 | for f in funcs_failed: | |
943 | print("ERROR: failed %s" % f) | |
944 | ||
945 | if failed > 0: | |
946 | return -1 | |
947 | if unknown_types: | |
948 | return -1 | |
949 | return 0 | |
950 | 907 | |
951 | 908 | |
952 | 909 | ####################################################################### |
1281 | 1238 | |
1282 | 1239 | |
1283 | 1240 | def writeDoc(module: str, name: str, args: List[ArgumentType], indent: str, output: IO) -> None: |
1284 | if module == "libvirt": | |
1285 | funcs = functions | |
1286 | elif module == "libvirt-lxc": | |
1287 | funcs = lxc_functions | |
1288 | elif module == "libvirt-qemu": | |
1289 | funcs = qemu_functions | |
1290 | if not funcs[name][0]: | |
1241 | if not functions[name][0]: | |
1291 | 1242 | return |
1292 | val = funcs[name][0] | |
1243 | val = functions[name][0] | |
1293 | 1244 | val = val.replace("NULL", "None") |
1294 | 1245 | sep = '\n%s' % (indent,) |
1295 | 1246 | output.write('%s"""%s """\n' % (indent, sep.join(val.splitlines()))) |
1296 | 1247 | |
1297 | 1248 | |
1298 | def buildWrappers(module: str) -> None: | |
1299 | if not module == "libvirt": | |
1300 | print("ERROR: Unknown module type: %s" % module) | |
1301 | return None | |
1249 | def emit_py_code(module: str) -> None: | |
1250 | package = module.replace('-', '_') | |
1251 | if module == "libvirt": | |
1252 | pymod = "libvirtmod" | |
1253 | cygmod = "cygvirtmod" | |
1254 | elif module == "libvirt-lxc": | |
1255 | pymod = "libvirtmod_lxc" | |
1256 | cygmod = "cygvirtmod_lxc" | |
1257 | elif module == "libvirt-qemu": | |
1258 | pymod = "libvirtmod_qemu" | |
1259 | cygmod = "cygvirtmod_qemu" | |
1260 | else: | |
1261 | raise Exception("Unknown module '%s'" % module) | |
1302 | 1262 | |
1303 | 1263 | for tinfo in classes_type.values(): |
1304 | 1264 | function_classes[tinfo[2]] = [] |
1329 | 1289 | ctypes_processed.add(type) |
1330 | 1290 | |
1331 | 1291 | for name, (desc, ret, args, file, mod, cond) in functions.items(): |
1292 | if skip_py_impl(name): | |
1293 | continue | |
1294 | ||
1332 | 1295 | for type in ctypes: |
1333 | 1296 | classe = classes_type[type][2] |
1334 | 1297 | |
1348 | 1311 | info = (0, func, name, ret, args, file, mod) |
1349 | 1312 | function_classes['None'].append(info) |
1350 | 1313 | |
1351 | classes_file = "build/%s.py" % module | |
1314 | classes_file = "build/%s.py" % package | |
1352 | 1315 | extra_file = "%s-override.py" % module |
1353 | 1316 | extra = None |
1354 | 1317 | |
1367 | 1330 | classes.write("#\n") |
1368 | 1331 | classes.write("# WARNING WARNING WARNING WARNING\n") |
1369 | 1332 | classes.write("#\n") |
1333 | classes.write("try:\n") | |
1334 | classes.write(" import %s # type: ignore\n" % pymod) | |
1335 | classes.write("except ImportError as lib_e:\n") | |
1336 | classes.write(" try:\n") | |
1337 | classes.write(" import %s as %s # type: ignore\n" % (cygmod, pymod)) | |
1338 | classes.write(" except ImportError as cyg_e:\n") | |
1339 | classes.write(" if \"No module named\" in str(cyg_e):\n") | |
1340 | classes.write(" raise lib_e\n\n") | |
1341 | ||
1342 | if module != "libvirt": | |
1343 | classes.write("import libvirt\n") | |
1344 | classes.write("\n") | |
1345 | ||
1370 | 1346 | if extra: |
1347 | classes.write("# WARNING WARNING WARNING WARNING\n") | |
1348 | classes.write("#\n") | |
1349 | classes.write("# Manually written part of python bindings for %s\n" % module) | |
1371 | 1350 | classes.writelines(extra.readlines()) |
1372 | 1351 | classes.write("#\n") |
1373 | 1352 | classes.write("# WARNING WARNING WARNING WARNING\n") |
1374 | 1353 | classes.write("#\n") |
1375 | classes.write("# Automatically written part of python bindings for libvirt\n") | |
1354 | classes.write("# Automatically written part of python bindings for %s\n" % module) | |
1376 | 1355 | classes.write("#\n") |
1377 | 1356 | classes.write("# WARNING WARNING WARNING WARNING\n") |
1378 | 1357 | if extra: |
1412 | 1391 | classes.write(" ret = ") |
1413 | 1392 | else: |
1414 | 1393 | classes.write(" ") |
1415 | classes.write("libvirtmod.%s(" % name) | |
1394 | classes.write("%s.%s(" % (pymod, name)) | |
1416 | 1395 | for n, (a_name, a_type, a_info) in enumerate(args): |
1417 | 1396 | if n != 0: |
1418 | 1397 | classes.write(", ") |
1465 | 1444 | |
1466 | 1445 | classes.write("\n") |
1467 | 1446 | |
1468 | for classname in classes_list: | |
1447 | modclasses = [] | |
1448 | if module == "libvirt": | |
1449 | modclasses = classes_list | |
1450 | for classname in modclasses: | |
1469 | 1451 | PARENTS = { |
1470 | 1452 | "virConnect": "self._conn", |
1471 | 1453 | "virDomain": "self._dom", |
1506 | 1488 | if classname in classes_destructors: |
1507 | 1489 | classes.write(" def __del__(self):\n") |
1508 | 1490 | classes.write(" if self._o is not None:\n") |
1509 | classes.write(" libvirtmod.%s(self._o)\n" % | |
1510 | classes_destructors[classname]) | |
1491 | classes.write(" %s.%s(self._o)\n" % | |
1492 | (pymod, classes_destructors[classname])) | |
1511 | 1493 | classes.write(" self._o = None\n\n") |
1512 | 1494 | destruct = classes_destructors[classname] |
1513 | 1495 | |
1526 | 1508 | |
1527 | 1509 | classes.write(" def c_pointer(self):\n") |
1528 | 1510 | classes.write(" \"\"\"Get C pointer to underlying object\"\"\"\n") |
1529 | classes.write(" return libvirtmod.%s_pointer(self._o)\n\n" % | |
1530 | classname) | |
1511 | classes.write(" return %s.%s_pointer(self._o)\n\n" % | |
1512 | (pymod, classname)) | |
1531 | 1513 | |
1532 | 1514 | flist = function_classes[classname] |
1533 | 1515 | oldfile = "" |
1572 | 1554 | classes.write(" ret = ") |
1573 | 1555 | else: |
1574 | 1556 | classes.write(" ") |
1575 | classes.write("libvirtmod.%s(" % name) | |
1557 | classes.write("%s.%s(" % (pymod, name)) | |
1576 | 1558 | for n, (a_name, a_type, a_info) in enumerate(args): |
1577 | 1559 | if n != 0: |
1578 | 1560 | classes.write(", ") |
1644 | 1626 | |
1645 | 1627 | classes.write("\n") |
1646 | 1628 | # Append "<classname>.py" to class def, iff it exists |
1647 | try: | |
1648 | extra = open("libvirt-override-%s.py" % (classname,), "r") | |
1629 | class_override = "%s-override-%s.py" % (module, classname) | |
1630 | if os.path.exists(class_override): | |
1631 | extra = open(class_override, "r") | |
1649 | 1632 | classes.write(" #\n") |
1650 | 1633 | classes.write(" # %s methods from %s.py (hand coded)\n" % (classname, classname)) |
1651 | 1634 | classes.write(" #\n") |
1658 | 1641 | |
1659 | 1642 | def shouldSkip(lines: List[str]) -> bool: |
1660 | 1643 | for line in lines: |
1661 | offset = line.find("libvirtmod.") | |
1644 | offset = line.find(pymod + ".") | |
1662 | 1645 | if offset != -1: |
1663 | 1646 | func = line[offset + 11:] |
1664 | 1647 | offset = func.find("(") |
1665 | 1648 | func = func[0:offset] |
1666 | if func not in functions_skipped: | |
1649 | if not skip_c_impl(func) and func != "virConnectListDomains": | |
1667 | 1650 | return True |
1668 | 1651 | return False |
1669 | 1652 | |
1690 | 1673 | classes.writelines(cached) |
1691 | 1674 | classes.write("\n") |
1692 | 1675 | extra.close() |
1693 | except Exception: | |
1694 | pass | |
1676 | ||
1677 | direct_functions = {} | |
1678 | if module != "libvirt": | |
1679 | direct_functions = functions | |
1680 | ||
1681 | classes.write("#\n# Functions from module %s\n#\n\n" % module) | |
1682 | ||
1683 | # | |
1684 | # Generate functions directly, no classes | |
1685 | # | |
1686 | for name, (desc, ret, args, file, mod, cond) in sorted(direct_functions.items()): | |
1687 | if skip_py_impl(name): | |
1688 | continue | |
1689 | func = nameFixup(name, 'None', '', '') | |
1690 | classes.write("def %s(" % func) | |
1691 | for n, (a_name, a_type, a_info) in enumerate(args): | |
1692 | if n != 0: | |
1693 | classes.write(", ") | |
1694 | classes.write("%s" % a_name) | |
1695 | classes.write("):\n") | |
1696 | writeDoc(module, name, args, ' ', classes) | |
1697 | ||
1698 | r_type, r_info, r_field = ret | |
1699 | if r_type != "void": | |
1700 | classes.write(" ret = ") | |
1701 | else: | |
1702 | classes.write(" ") | |
1703 | classes.write("%s.%s(" % (pymod, name)) | |
1704 | ||
1705 | conn = None | |
1706 | ||
1707 | for n, (a_name, a_type, a_info) in enumerate(args): | |
1708 | if a_type == "virConnectPtr": | |
1709 | conn = a_name | |
1710 | ||
1711 | if n != 0: | |
1712 | classes.write(", ") | |
1713 | if a_type in ["virDomainPtr", "virConnectPtr"]: | |
1714 | # FIXME: This might have problem if the function | |
1715 | # has multiple args which are objects. | |
1716 | classes.write("%s.%s" % (a_name, "_o")) | |
1717 | else: | |
1718 | classes.write("%s" % a_name) | |
1719 | classes.write(")\n") | |
1720 | ||
1721 | if r_type != "void": | |
1722 | classes.write(" if ret is None:\n" | |
1723 | " raise libvirt.libvirtError('%s() failed')\n" % (name,)) | |
1724 | if r_type == "virDomainPtr": | |
1725 | classes.write(" __tmp = libvirt.virDomain(%s, _obj=ret)\n" % (conn,)) | |
1726 | classes.write(" return __tmp\n") | |
1727 | else: | |
1728 | classes.write(" return ret\n") | |
1729 | ||
1730 | classes.write("\n") | |
1695 | 1731 | |
1696 | 1732 | # |
1697 | 1733 | # Generate enum constants |
1727 | 1763 | classes.write("%s = %s\n" % (name, value)) |
1728 | 1764 | classes.write("\n") |
1729 | 1765 | |
1730 | classes.write("# typed parameter names\n") | |
1731 | for name, value in params: | |
1732 | classes.write("%s = \"%s\"\n" % (name, value)) | |
1766 | if params: | |
1767 | classes.write("# typed parameter names\n") | |
1768 | for name, value in params: | |
1769 | classes.write("%s = \"%s\"\n" % (name, value)) | |
1733 | 1770 | |
1734 | 1771 | classes.close() |
1735 | 1772 | |
1736 | ||
1737 | def qemuBuildWrappers(module: str) -> None: | |
1738 | if not module == "libvirt-qemu": | |
1739 | print("ERROR: only libvirt-qemu is supported") | |
1740 | return None | |
1741 | ||
1742 | extra_file = "%s-override.py" % module | |
1743 | extra = None | |
1744 | ||
1745 | fd = open("build/libvirt_qemu.py", "w") | |
1746 | ||
1747 | if os.path.exists(extra_file): | |
1748 | extra = open(extra_file, "r") | |
1749 | fd.write("#\n") | |
1750 | fd.write("# WARNING WARNING WARNING WARNING\n") | |
1751 | fd.write("#\n") | |
1752 | fd.write("# This file is automatically written by generator.py. Any changes\n") | |
1753 | fd.write("# made here will be lost.\n") | |
1754 | fd.write("#\n") | |
1755 | fd.write("# To change the manually written methods edit %s-override.py\n" % (module,)) | |
1756 | fd.write("# To change the automatically written methods edit generator.py\n") | |
1757 | fd.write("#\n") | |
1758 | fd.write("# WARNING WARNING WARNING WARNING\n") | |
1759 | fd.write("#\n") | |
1760 | fd.write("# Automatically written part of python bindings for libvirt\n") | |
1761 | fd.write("#\n") | |
1762 | ||
1763 | fd.write("try:\n") | |
1764 | fd.write(" import libvirtmod_qemu\n") | |
1765 | fd.write("except ImportError as lib_e:\n") | |
1766 | fd.write(" try:\n") | |
1767 | fd.write(" import cygvirtmod_qemu as libvirtmod_qemu\n") | |
1768 | fd.write(" except ImportError as cyg_e:\n") | |
1769 | fd.write(" if \"No module named\" in str(cyg_e):\n") | |
1770 | fd.write(" raise lib_e\n\n") | |
1771 | ||
1772 | fd.write("import libvirt\n\n") | |
1773 | fd.write("# WARNING WARNING WARNING WARNING\n") | |
1774 | fd.write("#\n") | |
1775 | if extra: | |
1776 | fd.writelines(extra.readlines()) | |
1777 | fd.write("#\n") | |
1778 | if extra: | |
1779 | extra.close() | |
1780 | ||
1781 | fd.write("# WARNING WARNING WARNING WARNING\n") | |
1782 | fd.write("#\n") | |
1783 | fd.write("#\n# Functions from module %s\n#\n\n" % module) | |
1784 | # | |
1785 | # Generate functions directly, no classes | |
1786 | # | |
1787 | for name, (desc, ret, args, file, mod, cond) in sorted(qemu_functions.items()): | |
1788 | func = nameFixup(name, 'None', '', '') | |
1789 | fd.write("def %s(" % func) | |
1790 | for n, (a_name, a_type, a_info) in enumerate(args): | |
1791 | if n != 0: | |
1792 | fd.write(", ") | |
1793 | fd.write("%s" % a_name) | |
1794 | fd.write("):\n") | |
1795 | writeDoc(module, name, args, ' ', fd) | |
1796 | ||
1797 | r_type, r_info, r_field = ret | |
1798 | if r_type != "void": | |
1799 | fd.write(" ret = ") | |
1800 | else: | |
1801 | fd.write(" ") | |
1802 | fd.write("libvirtmod_qemu.%s(" % name) | |
1803 | ||
1804 | conn = None | |
1805 | ||
1806 | for n, (a_name, a_type, a_info) in enumerate(args): | |
1807 | if a_type == "virConnectPtr": | |
1808 | conn = a_name | |
1809 | ||
1810 | if n != 0: | |
1811 | fd.write(", ") | |
1812 | if a_type in ["virDomainPtr", "virConnectPtr"]: | |
1813 | # FIXME: This might have problem if the function | |
1814 | # has multiple args which are objects. | |
1815 | fd.write("%s.%s" % (a_name, "_o")) | |
1816 | else: | |
1817 | fd.write("%s" % a_name) | |
1818 | fd.write(")\n") | |
1819 | ||
1820 | if r_type != "void": | |
1821 | fd.write(" if ret is None:\n" | |
1822 | " raise libvirt.libvirtError('%s() failed')\n" % (name,)) | |
1823 | if r_type == "virDomainPtr": | |
1824 | fd.write(" __tmp = libvirt.virDomain(%s, _obj=ret)\n" % (conn,)) | |
1825 | fd.write(" return __tmp\n") | |
1826 | else: | |
1827 | fd.write(" return ret\n") | |
1828 | ||
1829 | fd.write("\n") | |
1830 | ||
1831 | # | |
1832 | # Generate enum constants | |
1833 | # | |
1834 | for type, enum in sorted(qemu_enums.items()): | |
1835 | fd.write("# %s\n" % type) | |
1836 | for name, value in sorted(enum.items(), key=lambda i: (int(i[1]), i[0])): | |
1837 | fd.write("%s = %s\n" % (name, value)) | |
1838 | fd.write("\n") | |
1839 | ||
1840 | fd.close() | |
1841 | ||
1842 | ||
1843 | def lxcBuildWrappers(module: str) -> None: | |
1844 | if not module == "libvirt-lxc": | |
1845 | print("ERROR: only libvirt-lxc is supported") | |
1846 | return None | |
1847 | ||
1848 | extra_file = "%s-override.py" % module | |
1849 | extra = None | |
1850 | ||
1851 | fd = open("build/libvirt_lxc.py", "w") | |
1852 | ||
1853 | if os.path.exists(extra_file): | |
1854 | extra = open(extra_file, "r") | |
1855 | fd.write("#\n") | |
1856 | fd.write("# WARNING WARNING WARNING WARNING\n") | |
1857 | fd.write("#\n") | |
1858 | fd.write("# This file is automatically written by generator.py. Any changes\n") | |
1859 | fd.write("# made here will be lost.\n") | |
1860 | fd.write("#\n") | |
1861 | fd.write("# To change the manually written methods edit %s-override.py\n" % (module,)) | |
1862 | fd.write("# To change the automatically written methods edit generator.py\n") | |
1863 | fd.write("#\n") | |
1864 | fd.write("# WARNING WARNING WARNING WARNING\n") | |
1865 | fd.write("#\n") | |
1866 | if extra: | |
1867 | fd.writelines(extra.readlines()) | |
1868 | fd.write("#\n") | |
1869 | fd.write("# WARNING WARNING WARNING WARNING\n") | |
1870 | fd.write("#\n") | |
1871 | fd.write("# Automatically written part of python bindings for libvirt\n") | |
1872 | fd.write("#\n") | |
1873 | fd.write("# WARNING WARNING WARNING WARNING\n") | |
1874 | if extra: | |
1875 | extra.close() | |
1876 | ||
1877 | fd.write("try:\n") | |
1878 | fd.write(" import libvirtmod_lxc\n") | |
1879 | fd.write("except ImportError as lib_e:\n") | |
1880 | fd.write(" try:\n") | |
1881 | fd.write(" import cygvirtmod_lxc as libvirtmod_lxc\n") | |
1882 | fd.write(" except ImportError as cyg_e:\n") | |
1883 | fd.write(" if \"No module named\" in str(cyg_e):\n") | |
1884 | fd.write(" raise lib_e\n\n") | |
1885 | ||
1886 | fd.write("import libvirt\n\n") | |
1887 | fd.write("#\n# Functions from module %s\n#\n\n" % module) | |
1888 | # | |
1889 | # Generate functions directly, no classes | |
1890 | # | |
1891 | for name, (desc, ret, args, file, mod, cond) in sorted(lxc_functions.items()): | |
1892 | func = nameFixup(name, 'None', '', '') | |
1893 | fd.write("def %s(" % func) | |
1894 | for n, (a_name, a_type, a_info) in enumerate(args): | |
1895 | if n != 0: | |
1896 | fd.write(", ") | |
1897 | fd.write("%s" % a_name) | |
1898 | fd.write("):\n") | |
1899 | writeDoc(module, name, args, ' ', fd) | |
1900 | ||
1901 | r_type, r_info, r_field = ret | |
1902 | if r_type != "void": | |
1903 | fd.write(" ret = ") | |
1904 | else: | |
1905 | fd.write(" ") | |
1906 | fd.write("libvirtmod_lxc.%s(" % name) | |
1907 | ||
1908 | conn = None | |
1909 | ||
1910 | for n, (a_name, a_type, a_info) in enumerate(args): | |
1911 | if a_type == "virConnectPtr": | |
1912 | conn = a_name | |
1913 | ||
1914 | if n != 0: | |
1915 | fd.write(", ") | |
1916 | if a_type in ["virDomainPtr", "virConnectPtr"]: | |
1917 | # FIXME: This might have problem if the function | |
1918 | # has multiple args which are objects. | |
1919 | fd.write("%s.%s" % (a_name, "_o")) | |
1920 | else: | |
1921 | fd.write("%s" % a_name) | |
1922 | fd.write(")\n") | |
1923 | ||
1924 | if r_type != "void": | |
1925 | fd.write(" if ret is None:\n" | |
1926 | " raise libvirt.libvirtError('%s() failed')\n" % (name,)) | |
1927 | if r_type == "virDomainPtr": | |
1928 | fd.write(" __tmp = libvirt.virDomain(%s, _obj=ret)\n" % (conn,)) | |
1929 | fd.write(" return __tmp\n") | |
1930 | else: | |
1931 | fd.write(" return ret\n") | |
1932 | ||
1933 | fd.write("\n") | |
1934 | ||
1935 | # | |
1936 | # Generate enum constants | |
1937 | # | |
1938 | for type, enum in sorted(lxc_enums.items()): | |
1939 | fd.write("# %s\n" % type) | |
1940 | for name, value in sorted(enum.items(), key=lambda i: (int(i[1]), i[0])): | |
1941 | fd.write("%s = %s\n" % (name, value)) | |
1942 | fd.write("\n") | |
1943 | ||
1944 | fd.close() | |
1945 | ||
1773 | if sys.argv[1] not in ["libvirt", "libvirt-lxc", "libvirt-qemu"]: | |
1774 | print("ERROR: unknown module %s" % sys.argv[1]) | |
1775 | sys.exit(1) | |
1776 | ||
1777 | load_apis(sys.argv[1], sys.argv[2]) | |
1778 | ||
1779 | if validate_functions() < 0: | |
1780 | sys.exit(1) | |
1946 | 1781 | |
1947 | 1782 | quiet = False |
1948 | 1783 | if not os.path.exists("build"): |
1949 | 1784 | os.mkdir("build") |
1950 | 1785 | |
1951 | if buildStubs(sys.argv[1], sys.argv[2]) < 0: | |
1952 | sys.exit(1) | |
1953 | ||
1954 | if sys.argv[1] == "libvirt": | |
1955 | buildWrappers(sys.argv[1]) | |
1956 | elif sys.argv[1] == "libvirt-lxc": | |
1957 | lxcBuildWrappers(sys.argv[1]) | |
1958 | elif sys.argv[1] == "libvirt-qemu": | |
1959 | qemuBuildWrappers(sys.argv[1]) | |
1960 | else: | |
1961 | print("ERROR: unknown module %s" % sys.argv[1]) | |
1962 | sys.exit(1) | |
1786 | output = None | |
1787 | if len(sys.argv) == 4: | |
1788 | output = sys.argv[3] | |
1789 | if output == "c" or output is None: | |
1790 | emit_c_code(sys.argv[1]) | |
1791 | ||
1792 | if output == "py" or output is None: | |
1793 | emit_py_code(sys.argv[1]) | |
1963 | 1794 | |
1964 | 1795 | sys.exit(0) |
851 | 851 | <arg name='params' type='virTypedParameterPtr' info='pointer to launch security state objects'/> |
852 | 852 | <arg name='flags' type='unsigned int' info='currently used, set to 0.'/> |
853 | 853 | </function> |
854 | <function name='virDomainSaveParams' file='python'> | |
855 | <info>This method will suspend a domain and save its memory contents to a file on disk.</info> | |
856 | <return type='int' info='0 in case of success and -1 in case of failure'/> | |
857 | <arg name='domain' type='virDomainPtr' info='pointer to domain object'/> | |
858 | <arg name='params' type='virTypedParameterPtr' info='pointer to save parameter objects'/> | |
859 | <arg name='flags' type='int' info='an OR'ed set of virDomainSaveRestoreFlags'/> | |
860 | </function> | |
861 | <function name='virDomainRestoreParams' file='python'> | |
862 | <info>This method will restore a domain saved to disk.</info> | |
863 | <return type='int' info='0 in case of success and -1 in case of failure'/> | |
864 | <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> | |
865 | <arg name='params' type='virTypedParameterPtr' info='pointer to save parameter objects'/> | |
866 | <arg name='flags' type='int' info='an OR'ed set of virDomainSaveRestoreFlags'/> | |
867 | </function> | |
854 | 868 | </symbols> |
855 | 869 | </api> |
79 | 79 | if ret == -1: |
80 | 80 | raise libvirtError('virDomainSetTime() failed') |
81 | 81 | return ret |
82 | ||
83 | def FDAssociate(self, name: str, files: List[int], flags: int = 0) -> int: | |
84 | """Associate the array of FDs passed as @fds with the domain object | |
85 | under @name. The FDs are associated as long as the connection used to | |
86 | associated exists and are disposed of afterwards. FD may still be kept | |
87 | open by the hypervisor for as long as it's needed. | |
88 | ||
89 | Security labelling (e.g. via the selinux) may be applied on the passed | |
90 | FDs when requiredg for usage by the VM. By default libvirt does not | |
91 | restore the seclabels on the FDs afterwards to avoid keeping it open | |
92 | unnecessarily. | |
93 | ||
94 | Restoring of the security label can be requested by passing either | |
95 | VIR_DOMAIN_FD_ASSOCIATE_SECLABEL_RESTORE for a best-effort attempt to | |
96 | restore the security label after use. Requesting the restore of | |
97 | security label will require that the file descriptors are kept open for | |
98 | the whole time they are used by the hypervisor, or other additional | |
99 | overhead. | |
100 | ||
101 | In certain cases usage of the fd group would imply read-only access. | |
102 | Passing VIR_DOMAIN_FD_ASSOCIATE_SECLABEL_WRITABLE in @flags ensures | |
103 | that a writable security label is picked in case when the file | |
104 | represented by the fds may be used in write mode. """ | |
105 | ret = libvirtmod.virDomainFDAssociate(self._o, name, files, flags) | |
106 | if ret == -1: | |
107 | raise libvirtError('virDomainFDAssociate() failed') | |
108 | return ret | |
109 |
1694 | 1694 | { VIR_DOMAIN_IOTHREAD_POLL_MAX_NS, VIR_TYPED_PARAM_ULLONG }, |
1695 | 1695 | { VIR_DOMAIN_IOTHREAD_POLL_GROW, VIR_TYPED_PARAM_UINT }, |
1696 | 1696 | { VIR_DOMAIN_IOTHREAD_POLL_SHRINK, VIR_TYPED_PARAM_UINT }, |
1697 | # if LIBVIR_CHECK_VERSION(8, 5, 0) | |
1698 | { VIR_DOMAIN_IOTHREAD_THREAD_POOL_MIN, VIR_TYPED_PARAM_INT }, | |
1699 | { VIR_DOMAIN_IOTHREAD_THREAD_POOL_MAX, VIR_TYPED_PARAM_INT }, | |
1700 | # endif /* LIBVIR_CHECK_VERSION(8, 5, 0) */ | |
1697 | 1701 | }; |
1698 | 1702 | |
1699 | 1703 | static PyObject * |
7921 | 7925 | buf[ret > -1 ? ret : 0] = '\0'; |
7922 | 7926 | DEBUG("StreamRecv ret=%d strlen=%d\n", ret, (int) strlen(buf)); |
7923 | 7927 | |
7924 | if (ret == -2) | |
7928 | if (ret == -2) { | |
7929 | VIR_FREE(buf); | |
7925 | 7930 | return libvirt_intWrap(ret); |
7926 | if (ret < 0) | |
7927 | return VIR_PY_NONE; | |
7931 | } | |
7932 | if (ret < 0) { | |
7933 | VIR_FREE(buf); | |
7934 | return VIR_PY_NONE; | |
7935 | } | |
7928 | 7936 | rv = libvirt_charPtrSizeWrap((char *) buf, (Py_ssize_t) ret); |
7929 | 7937 | VIR_FREE(buf); |
7930 | 7938 | return rv; |
10694 | 10702 | return libvirt_intWrap(c_retval); |
10695 | 10703 | } |
10696 | 10704 | #endif /* LIBVIR_CHECK_VERSION(8, 0, 0) */ |
10705 | ||
10706 | ||
10707 | #if LIBVIR_CHECK_VERSION(8, 4, 0) | |
10708 | static virPyTypedParamsHint virPyDomainSaveParams[] = { | |
10709 | { VIR_DOMAIN_SAVE_PARAM_FILE, VIR_TYPED_PARAM_STRING }, | |
10710 | { VIR_DOMAIN_SAVE_PARAM_DXML, VIR_TYPED_PARAM_STRING }, | |
10711 | }; | |
10712 | ||
10713 | ||
10714 | static PyObject * | |
10715 | libvirt_virDomainSaveParams(PyObject *self ATTRIBUTE_UNUSED, | |
10716 | PyObject *args) | |
10717 | { | |
10718 | PyObject *pyobj_dom = NULL; | |
10719 | PyObject *pyobj_dict = NULL; | |
10720 | virDomainPtr dom; | |
10721 | virTypedParameterPtr params = NULL; | |
10722 | int nparams = 0; | |
10723 | unsigned int flags = 0; | |
10724 | int c_retval; | |
10725 | ||
10726 | if (!PyArg_ParseTuple(args, (char *)"OO|I:virDomainSaveParams", | |
10727 | &pyobj_dom, &pyobj_dict, &flags)) | |
10728 | return NULL; | |
10729 | ||
10730 | if (PyDict_Check(pyobj_dict)) { | |
10731 | if (virPyDictToTypedParams(pyobj_dict, ¶ms, &nparams, | |
10732 | virPyDomainSaveParams, | |
10733 | VIR_N_ELEMENTS(virPyDomainSaveParams)) < 0) { | |
10734 | return NULL; | |
10735 | } | |
10736 | } else { | |
10737 | PyErr_Format(PyExc_TypeError, "Save params must be a dictionary"); | |
10738 | return NULL; | |
10739 | } | |
10740 | ||
10741 | dom = (virDomainPtr) PyvirDomain_Get(pyobj_dom); | |
10742 | ||
10743 | LIBVIRT_BEGIN_ALLOW_THREADS; | |
10744 | c_retval = virDomainSaveParams(dom, params, nparams, flags); | |
10745 | LIBVIRT_END_ALLOW_THREADS; | |
10746 | ||
10747 | virTypedParamsFree(params, nparams); | |
10748 | ||
10749 | return libvirt_intWrap(c_retval); | |
10750 | } | |
10751 | ||
10752 | static PyObject * | |
10753 | libvirt_virDomainRestoreParams(PyObject *self ATTRIBUTE_UNUSED, | |
10754 | PyObject *args) | |
10755 | { | |
10756 | PyObject *pyobj_conn = NULL; | |
10757 | PyObject *pyobj_dict = NULL; | |
10758 | virConnectPtr conn; | |
10759 | virTypedParameterPtr params = NULL; | |
10760 | int nparams = 0; | |
10761 | unsigned int flags = 0; | |
10762 | int c_retval; | |
10763 | ||
10764 | if (!PyArg_ParseTuple(args, (char *)"OO|I:virDomainRestoreParams", | |
10765 | &pyobj_conn, &pyobj_dict, &flags)) | |
10766 | return NULL; | |
10767 | ||
10768 | if (PyDict_Check(pyobj_dict)) { | |
10769 | if (virPyDictToTypedParams(pyobj_dict, ¶ms, &nparams, | |
10770 | virPyDomainSaveParams, | |
10771 | VIR_N_ELEMENTS(virPyDomainSaveParams)) < 0) { | |
10772 | return NULL; | |
10773 | } | |
10774 | } else { | |
10775 | PyErr_Format(PyExc_TypeError, "Restore params must be a dictionary"); | |
10776 | return NULL; | |
10777 | } | |
10778 | ||
10779 | conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); | |
10780 | ||
10781 | LIBVIRT_BEGIN_ALLOW_THREADS; | |
10782 | c_retval = virDomainRestoreParams(conn, params, nparams, flags); | |
10783 | LIBVIRT_END_ALLOW_THREADS; | |
10784 | ||
10785 | virTypedParamsFree(params, nparams); | |
10786 | ||
10787 | return libvirt_intWrap(c_retval); | |
10788 | } | |
10789 | #endif /* LIBVIR_CHECK_VERSION(8, 4, 0) */ | |
10790 | ||
10791 | ||
10792 | #if LIBVIR_CHECK_VERSION(9, 0, 0) | |
10793 | static PyObject * | |
10794 | libvirt_virDomainFDAssociate(PyObject *self ATTRIBUTE_UNUSED, | |
10795 | PyObject *args) | |
10796 | { | |
10797 | PyObject *py_retval = NULL; | |
10798 | int c_retval; | |
10799 | virDomainPtr domain; | |
10800 | PyObject *pyobj_domain; | |
10801 | PyObject *pyobj_files; | |
10802 | const char *name = NULL; | |
10803 | unsigned int flags; | |
10804 | unsigned int nfiles; | |
10805 | int *files = NULL; | |
10806 | ssize_t i; | |
10807 | ||
10808 | if (!PyArg_ParseTuple(args, (char *)"OsOI:virDomainFDAssociate", | |
10809 | &pyobj_domain, &name, &pyobj_files, &flags)) | |
10810 | return NULL; | |
10811 | domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain); | |
10812 | ||
10813 | nfiles = PyList_Size(pyobj_files); | |
10814 | ||
10815 | if (VIR_ALLOC_N(files, nfiles) < 0) | |
10816 | return PyErr_NoMemory(); | |
10817 | ||
10818 | for (i = 0; i < nfiles; i++) { | |
10819 | PyObject *pyfd; | |
10820 | int fd; | |
10821 | ||
10822 | pyfd = PyList_GetItem(pyobj_files, i); | |
10823 | ||
10824 | if (libvirt_intUnwrap(pyfd, &fd) < 0) | |
10825 | goto cleanup; | |
10826 | ||
10827 | files[i] = fd; | |
10828 | } | |
10829 | ||
10830 | LIBVIRT_BEGIN_ALLOW_THREADS; | |
10831 | c_retval = virDomainFDAssociate(domain, name, nfiles, files, flags); | |
10832 | LIBVIRT_END_ALLOW_THREADS; | |
10833 | ||
10834 | py_retval = libvirt_intWrap((int) c_retval); | |
10835 | ||
10836 | cleanup: | |
10837 | VIR_FREE(files); | |
10838 | return py_retval; | |
10839 | } | |
10840 | #endif /* LIBVIR_CHECK_VERSION(9, 0, 0) */ | |
10841 | ||
10842 | ||
10697 | 10843 | |
10698 | 10844 | /************************************************************************ |
10699 | 10845 | * * |
10972 | 11118 | #if LIBVIR_CHECK_VERSION(8, 0, 0) |
10973 | 11119 | {(char *) "virDomainSetLaunchSecurityState", libvirt_virDomainSetLaunchSecurityState, METH_VARARGS, NULL}, |
10974 | 11120 | #endif /* LIBVIR_CHECK_VERSION(8, 0, 0) */ |
11121 | #if LIBVIR_CHECK_VERSION(8, 4, 0) | |
11122 | {(char *) "virDomainSaveParams", libvirt_virDomainSaveParams, METH_VARARGS, NULL}, | |
11123 | {(char *) "virDomainRestoreParams", libvirt_virDomainRestoreParams, METH_VARARGS, NULL}, | |
11124 | #endif /* LIBVIR_CHECK_VERSION(8, 4, 0) */ | |
11125 | #if LIBVIR_CHECK_VERSION(9, 0, 0) | |
11126 | {(char *) "virDomainFDAssociate", libvirt_virDomainFDAssociate, METH_VARARGS, NULL}, | |
11127 | #endif /* LIBVIR_CHECK_VERSION(9, 0, 0) */ | |
10975 | 11128 | {NULL, NULL, 0, NULL} |
10976 | 11129 | }; |
10977 | 11130 |
0 | # | |
1 | # Manually written part of python bindings for libvirt | |
2 | # | |
3 | ||
4 | # On cygwin, the DLL is called cygvirtmod.dll | |
5 | try: | |
6 | import libvirtmod # type: ignore | |
7 | except ImportError as lib_e: | |
8 | try: | |
9 | import cygvirtmod as libvirtmod # type: ignore | |
10 | except ImportError as cyg_e: | |
11 | if "No module named" in str(cyg_e): | |
12 | raise lib_e | |
13 | 0 | |
14 | 1 | from types import TracebackType |
15 | 2 | from typing import Any, Callable, Dict, List, Optional, overload, Tuple, Type, TypeVar, Union |
13 | 13 | |
14 | 14 | Summary: The libvirt virtualization API python3 binding |
15 | 15 | Name: libvirt-python |
16 | Version: 8.0.0 | |
16 | Version: 9.0.0 | |
17 | 17 | Release: 1%{?dist} |
18 | 18 | Source0: https://libvirt.org/sources/python/%{name}-%{version}.tar.gz |
19 | 19 | Url: https://libvirt.org |
22 | 22 | BuildRequires: python3-devel |
23 | 23 | BuildRequires: python3-pytest |
24 | 24 | BuildRequires: python3-lxml |
25 | BuildRequires: python3-setuptools | |
25 | 26 | BuildRequires: gcc |
26 | 27 | |
27 | 28 | # Don't want provides for python shared objects |
0 | # -*- rpm-spec -*- | |
1 | ||
2 | # This spec file assumes you are building on a Fedora or RHEL version | |
3 | # that's still supported by the vendor. It may work on other distros | |
4 | # or versions, but no effort will be made to ensure that going forward | |
5 | %define min_rhel 8 | |
6 | %define min_fedora 33 | |
7 | ||
8 | %if (0%{?fedora} && 0%{?fedora} >= %{min_fedora}) || (0%{?rhel} && 0%{?rhel} >= %{min_rhel}) | |
9 | %define supported_platform 1 | |
10 | %else | |
11 | %define supported_platform 0 | |
12 | %endif | |
13 | ||
14 | Summary: The libvirt virtualization API python3 binding | |
15 | Name: libvirt-python | |
16 | Version: @PY_VERSION@ | |
17 | Release: 1%{?dist} | |
18 | Source0: https://libvirt.org/sources/python/%{name}-%{version}.tar.gz | |
19 | Url: https://libvirt.org | |
20 | License: LGPLv2+ | |
21 | BuildRequires: libvirt-devel == %{version} | |
22 | BuildRequires: python3-devel | |
23 | BuildRequires: python3-pytest | |
24 | BuildRequires: python3-lxml | |
25 | BuildRequires: python3-setuptools | |
26 | BuildRequires: gcc | |
27 | ||
28 | # Don't want provides for python shared objects | |
29 | %{?filter_provides_in: %filter_provides_in %{python3_sitearch}/.*\.so} | |
30 | %{?filter_setup} | |
31 | ||
32 | %description | |
33 | The libvirt-python package contains a module that permits applications | |
34 | written in the Python programming language to use the interface | |
35 | supplied by the libvirt library to use the virtualization capabilities | |
36 | of recent versions of Linux (and other OSes). | |
37 | ||
38 | %package -n python3-libvirt | |
39 | Summary: The libvirt virtualization API python3 binding | |
40 | Url: http://libvirt.org | |
41 | License: LGPLv2+ | |
42 | %{?python_provide:%python_provide python3-libvirt} | |
43 | Provides: libvirt-python3 = %{version}-%{release} | |
44 | Obsoletes: libvirt-python3 <= 3.6.0-1%{?dist} | |
45 | ||
46 | %description -n python3-libvirt | |
47 | The python3-libvirt package contains a module that permits applications | |
48 | written in the Python 3.x programming language to use the interface | |
49 | supplied by the libvirt library to use the virtualization capabilities | |
50 | of recent versions of Linux (and other OSes). | |
51 | ||
52 | %prep | |
53 | %setup -q | |
54 | ||
55 | # Unset execute bit for example scripts; it can introduce spurious | |
56 | # RPM dependencies, like /usr/bin/python3 | |
57 | # for the -python3 package | |
58 | find examples -type f -exec chmod 0644 \{\} \; | |
59 | ||
60 | %build | |
61 | %if ! %{supported_platform} | |
62 | echo "This RPM requires either Fedora >= %{min_fedora} or RHEL >= %{min_rhel}" | |
63 | exit 1 | |
64 | %endif | |
65 | ||
66 | %py3_build | |
67 | ||
68 | %install | |
69 | %py3_install | |
70 | ||
71 | %check | |
72 | %{__python3} setup.py test | |
73 | ||
74 | %files -n python3-libvirt | |
75 | %doc ChangeLog AUTHORS README COPYING COPYING.LESSER examples/ | |
76 | %{python3_sitearch}/libvirt.py* | |
77 | %{python3_sitearch}/libvirtaio.py* | |
78 | %{python3_sitearch}/libvirt_qemu.py* | |
79 | %{python3_sitearch}/libvirt_lxc.py* | |
80 | %{python3_sitearch}/__pycache__/libvirt.cpython-*.py* | |
81 | %{python3_sitearch}/__pycache__/libvirt_qemu.cpython-*.py* | |
82 | %{python3_sitearch}/__pycache__/libvirt_lxc.cpython-*.py* | |
83 | %{python3_sitearch}/__pycache__/libvirtaio.cpython-*.py* | |
84 | %{python3_sitearch}/libvirtmod* | |
85 | %{python3_sitearch}/*egg-info | |
86 | ||
87 | %changelog |
19 | 19 | #include "typewrappers.h" |
20 | 20 | #include "libvirt-utils.h" |
21 | 21 | #include "build/libvirt-qemu.h" |
22 | #ifndef __CYGWIN__ | |
23 | # include <fcntl.h> | |
24 | #endif | |
22 | 25 | |
23 | 26 | #ifndef __CYGWIN__ |
24 | 27 | extern PyObject *PyInit_libvirtmod_qemu(void); |
323 | 326 | return py_retval; |
324 | 327 | } |
325 | 328 | #endif /* LIBVIR_CHECK_VERSION(1, 2, 3) */ |
329 | ||
330 | #if LIBVIR_CHECK_VERSION(8, 2, 0) | |
331 | static PyObject * | |
332 | libvirt_qemu_virDomainQemuMonitorCommandWithFiles(PyObject *self ATTRIBUTE_UNUSED, | |
333 | PyObject *args) | |
334 | { | |
335 | PyObject *pyobj_domain; | |
336 | const char *cmd; | |
337 | PyObject *pyobj_files; | |
338 | unsigned int flags; | |
339 | virDomainPtr domain; | |
340 | unsigned int ninfiles; | |
341 | int *infiles = NULL; | |
342 | unsigned int noutfiles = 0; | |
343 | int *outfiles = NULL; | |
344 | char *result = NULL; | |
345 | ssize_t i; | |
346 | PyObject *py_outfiles = NULL; | |
347 | PyObject *py_retval = NULL; | |
348 | int c_retval; | |
349 | ||
350 | if (!PyArg_ParseTuple(args, | |
351 | (char *) "Os|OI:virDomainQemuMonitorCommandWithFiles", | |
352 | &pyobj_domain, &cmd, &pyobj_files, &flags)) | |
353 | return NULL; | |
354 | domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain); | |
355 | ||
356 | ninfiles = PyList_Size(pyobj_files); | |
357 | ||
358 | if (VIR_ALLOC_N(infiles, ninfiles) < 0) | |
359 | return PyErr_NoMemory(); | |
360 | ||
361 | for (i = 0; i < ninfiles; i++) { | |
362 | PyObject *pyfd; | |
363 | int fd; | |
364 | ||
365 | pyfd = PyList_GetItem(pyobj_files, i); | |
366 | ||
367 | if (libvirt_intUnwrap(pyfd, &fd) < 0) | |
368 | goto cleanup; | |
369 | ||
370 | infiles[i] = fd; | |
371 | } | |
372 | ||
373 | LIBVIRT_BEGIN_ALLOW_THREADS; | |
374 | c_retval = virDomainQemuMonitorCommandWithFiles(domain, cmd, ninfiles, infiles, | |
375 | &noutfiles, &outfiles, &result, flags); | |
376 | LIBVIRT_END_ALLOW_THREADS; | |
377 | ||
378 | if (c_retval < 0) { | |
379 | py_retval = VIR_PY_NONE; | |
380 | goto cleanup; | |
381 | } | |
382 | ||
383 | if (!(py_outfiles = PyList_New(0)) || | |
384 | !(py_retval = PyTuple_New(2))) { | |
385 | goto error; | |
386 | } | |
387 | ||
388 | for (i = 0; i < noutfiles; i++) { | |
389 | int fd = outfiles[i]; | |
390 | const char *mode = "r+b"; | |
391 | ||
392 | /* Since FD passing works only on UNIX-like systems, we can do this. */ | |
393 | #ifndef __CYGWIN__ | |
394 | int fflags; | |
395 | ||
396 | if ((fflags = fcntl(fd, F_GETFL)) < 0) | |
397 | goto error; | |
398 | ||
399 | switch (fflags & (O_ACCMODE | O_APPEND)) { | |
400 | case O_RDONLY: | |
401 | mode = "rb"; | |
402 | break; | |
403 | case O_WRONLY: | |
404 | mode = "wb"; | |
405 | break; | |
406 | case O_RDWR: | |
407 | mode = "r+b"; | |
408 | break; | |
409 | case O_WRONLY | O_APPEND: | |
410 | mode = "ab"; | |
411 | break; | |
412 | case O_RDWR | O_APPEND: | |
413 | mode = "a+b"; | |
414 | break; | |
415 | } | |
416 | #endif | |
417 | ||
418 | VIR_PY_LIST_APPEND_GOTO(py_outfiles, PyFile_FromFd(fd, NULL, mode, 0, NULL, NULL, NULL, 1), error); | |
419 | } | |
420 | ||
421 | VIR_PY_TUPLE_SET_GOTO(py_retval, 0, libvirt_charPtrWrap(result), error); | |
422 | VIR_PY_TUPLE_SET_GOTO(py_retval, 1, py_outfiles, error); | |
423 | /* stolen by py_retval */ | |
424 | py_outfiles = NULL; | |
425 | ||
426 | cleanup: | |
427 | Py_XDECREF(py_outfiles); | |
428 | VIR_FREE(result); | |
429 | VIR_FREE(outfiles); | |
430 | VIR_FREE(infiles); | |
431 | return py_retval; | |
432 | ||
433 | error: | |
434 | while (noutfiles > 0) { | |
435 | VIR_FORCE_CLOSE(outfiles[--noutfiles]); | |
436 | } | |
437 | Py_CLEAR(py_retval); | |
438 | goto cleanup; | |
439 | } | |
440 | #endif /* LIBVIR_CHECK_VERSION(8, 2, 0) */ | |
326 | 441 | |
327 | 442 | /************************************************************************ |
328 | 443 | * * |
339 | 454 | {(char *) "virConnectDomainQemuMonitorEventRegister", libvirt_qemu_virConnectDomainQemuMonitorEventRegister, METH_VARARGS, NULL}, |
340 | 455 | {(char *) "virConnectDomainQemuMonitorEventDeregister", libvirt_qemu_virConnectDomainQemuMonitorEventDeregister, METH_VARARGS, NULL}, |
341 | 456 | #endif /* LIBVIR_CHECK_VERSION(1, 2, 3) */ |
457 | #if LIBVIR_CHECK_VERSION(8, 2, 0) | |
458 | {(char *) "virDomainQemuMonitorCommandWithFiles", libvirt_qemu_virDomainQemuMonitorCommandWithFiles, METH_VARARGS, NULL}, | |
459 | #endif /* LIBVIR_CHECK_VERSION(8, 2, 0) */ | |
342 | 460 | {NULL, NULL, 0, NULL} |
343 | 461 | }; |
344 | 462 |
0 | # Manually written part of python bindings for libvirt-qemu | |
1 | from typing import Any, Callable, Dict | |
0 | from typing import Any, Callable, Dict, List, IO | |
2 | 1 | |
3 | 2 | |
4 | 3 | def _dispatchQemuMonitorEventCallback(conn: libvirt.virConnect, dom: libvirt.virDomain, event: str, seconds: int, micros: int, details: str, cbData: Dict[str, Any]) -> int: |
37 | 36 | raise libvirt.libvirtError('virConnectDomainQemuMonitorEventRegister() failed') |
38 | 37 | conn.qemuMonitorEventCallbackID[ret] = opaque # type: ignore |
39 | 38 | return ret |
39 | ||
40 | def qemuMonitorCommandWithFiles(domain: libvirt.virDomain, cmd: str, files: List[int] = [], flags: int = 0) -> (str, List[IO]): | |
41 | """This API is QEMU specific, so it will only work with hypervisor | |
42 | connections to the QEMU driver with local connections using the unix | |
43 | socket. | |
44 | ||
45 | Send an arbitrary monitor command @cmd with file descriptors @files to | |
46 | domain through the QEMU monitor and optionally return a list of files | |
47 | in the returned tuple. There are several requirements to safely | |
48 | and successfully use this API: | |
49 | ||
50 | - A @cmd that queries state without making any modifications is safe | |
51 | - A @cmd that alters state that is also tracked by libvirt is unsafe, | |
52 | and may cause libvirtd to crash | |
53 | - A @cmd that alters state not tracked by the current version of | |
54 | libvirt is possible as a means to test new qemu features before | |
55 | they have support in libvirt, but no guarantees are made to safety | |
56 | ||
57 | If VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP is set, the command is considered to | |
58 | be a human monitor command and libvirt will automatically convert it into | |
59 | QMP if needed. In that case the @result will also be converted back from | |
60 | QMP. | |
61 | ||
62 | Returns a tuple consisting of the string output from @cmd and a list of | |
63 | files respectively.""" | |
64 | ret = libvirtmod_qemu.virDomainQemuMonitorCommandWithFiles(domain._o, cmd, files, flags) | |
65 | if ret is None: | |
66 | raise libvirt.libvirtError('virDomainQemuMonitorCommandWithFiles() failed') | |
67 | return ret |
407 | 407 | type = VIR_TYPED_PARAM_BOOLEAN; |
408 | 408 | } else if (PyLong_Check(value)) { |
409 | 409 | unsigned long long ull = PyLong_AsUnsignedLongLong(value); |
410 | if (ull == (unsigned long long) -1 && PyErr_Occurred()) | |
410 | if (ull == (unsigned long long) -1 && PyErr_Occurred()) { | |
411 | 411 | type = VIR_TYPED_PARAM_LLONG; |
412 | else | |
412 | PyErr_Clear(); | |
413 | } else { | |
413 | 414 | type = VIR_TYPED_PARAM_ULLONG; |
415 | } | |
414 | 416 | } else if (PyFloat_Check(value)) { |
415 | 417 | type = VIR_TYPED_PARAM_DOUBLE; |
416 | 418 | } |
20 | 20 | |
21 | 21 | Register the implementation of default loop: |
22 | 22 | |
23 | >>> import libvirtaio | |
24 | >>> libvirtaio.virEventRegisterAsyncIOImpl() | |
23 | import asyncio | |
24 | import libvirtaio | |
25 | ||
26 | async def myapp(): | |
27 | libvirtaio.virEventRegisterAsyncIOImpl() | |
28 | ||
29 | conn = libvirt.open("test:///default") | |
30 | ||
31 | For compatibility with Python < 3.7: | |
32 | ||
33 | loop = asyncio.new_event_loop() | |
34 | asyncio.set_event_loop(loop) | |
35 | ||
36 | loop.run_until_complete(myapp()) | |
37 | ||
38 | asyncio.set_event_loop(None) | |
39 | loop.close() | |
40 | ||
41 | If Python >= 3.7 can be required then | |
42 | ||
43 | asyncio.run(myapp()) | |
25 | 44 | |
26 | 45 | .. seealso:: |
27 | 46 | https://libvirt.org/html/libvirt-libvirt-event.html |
44 | 63 | 'virEventAsyncIOImpl', |
45 | 64 | 'virEventRegisterAsyncIOImpl', |
46 | 65 | ] |
47 | ||
48 | # Python < 3.4.4 doesn't have 'ensure_future', so we have to fall | |
49 | # back to 'async'; however, since 'async' is a reserved keyword | |
50 | # in Python >= 3.7, we can't perform a straightforward import and | |
51 | # we have to resort to getattr() instead | |
52 | ensure_future = getattr(asyncio, "ensure_future", None) | |
53 | if not ensure_future: | |
54 | ensure_future = getattr(asyncio, "async") | |
55 | 66 | |
56 | 67 | |
57 | 68 | class Callback(object): |
218 | 229 | return '<{} iden={} timeout={}>'.format( |
219 | 230 | self.__class__.__name__, self.iden, self.timeout) |
220 | 231 | |
221 | @asyncio.coroutine | |
222 | def _timer(self) -> Generator[Any, None, None]: | |
232 | async def _timer(self) -> Generator[Any, None, None]: | |
223 | 233 | '''An actual timer running on the event loop. |
224 | 234 | |
225 | 235 | This is a coroutine. |
229 | 239 | if self.timeout > 0: |
230 | 240 | timeout = self.timeout * 1e-3 |
231 | 241 | self.impl.log.debug('sleeping %r', timeout) |
232 | yield from asyncio.sleep(timeout) | |
242 | await asyncio.sleep(timeout) | |
233 | 243 | else: |
234 | 244 | # scheduling timeout for next loop iteration |
235 | yield | |
245 | await asyncio.sleep(0) | |
236 | 246 | |
237 | 247 | except asyncio.CancelledError: |
238 | 248 | self.impl.log.debug('timer %d cancelled', self.iden) |
247 | 257 | |
248 | 258 | if self.timeout >= 0 and self._task is None: |
249 | 259 | self.impl.log.debug('timer %r start', self.iden) |
250 | self._task = ensure_future(self._timer(), | |
251 | loop=self.impl.loop) | |
260 | self._task = asyncio.ensure_future(self._timer(), | |
261 | loop=self.impl.loop) | |
252 | 262 | |
253 | 263 | elif self.timeout < 0 and self._task is not None: |
254 | 264 | self.impl.log.debug('timer %r stop', self.iden) |
279 | 289 | self.descriptors = DescriptorDict(self) |
280 | 290 | self.log = logging.getLogger(self.__class__.__name__) |
281 | 291 | |
292 | self._pending = 0 | |
293 | # Transient asyncio.Event instance dynamically created | |
294 | # and destroyed by drain() | |
282 | 295 | # NOTE invariant: _finished.is_set() iff _pending == 0 |
283 | self._pending = 0 | |
284 | self._finished = asyncio.Event(loop=loop) | |
285 | self._finished.set() | |
296 | self._finished = None | |
286 | 297 | |
287 | 298 | def __repr__(self) -> str: |
288 | 299 | return '<{} callbacks={} descriptors={}>'.format( |
291 | 302 | def _pending_inc(self) -> None: |
292 | 303 | '''Increase the count of pending affairs. Do not use directly.''' |
293 | 304 | self._pending += 1 |
294 | self._finished.clear() | |
305 | if self._finished is not None: | |
306 | self._finished.clear() | |
295 | 307 | |
296 | 308 | def _pending_dec(self) -> None: |
297 | 309 | '''Decrease the count of pending affairs. Do not use directly.''' |
298 | 310 | assert self._pending > 0 |
299 | 311 | self._pending -= 1 |
300 | if self._pending == 0: | |
312 | if self._pending == 0 and self._finished is not None: | |
301 | 313 | self._finished.set() |
302 | 314 | |
303 | 315 | def register(self) -> "virEventAsyncIOImpl": |
311 | 323 | |
312 | 324 | def schedule_ff_callback(self, iden: int, opaque: _T) -> None: |
313 | 325 | '''Schedule a ff callback from one of the handles or timers''' |
314 | ensure_future(self._ff_callback(iden, opaque), loop=self.loop) | |
315 | ||
316 | @asyncio.coroutine | |
317 | def _ff_callback(self, iden: int, opaque: _T) -> None: | |
326 | asyncio.ensure_future(self._ff_callback(iden, opaque), loop=self.loop) | |
327 | ||
328 | async def _ff_callback(self, iden: int, opaque: _T) -> None: | |
318 | 329 | '''Directly free the opaque object |
319 | 330 | |
320 | 331 | This is a coroutine. |
323 | 334 | libvirt.virEventInvokeFreeCallback(opaque) |
324 | 335 | self._pending_dec() |
325 | 336 | |
326 | @asyncio.coroutine | |
327 | def drain(self) -> Generator[Any, None, None]: | |
337 | async def drain(self) -> None: | |
328 | 338 | '''Wait for the implementation to become idle. |
329 | 339 | |
330 | 340 | This is a coroutine. |
331 | 341 | ''' |
332 | 342 | self.log.debug('drain()') |
333 | 343 | if self._pending: |
334 | yield from self._finished.wait() | |
344 | assert self._finished is None | |
345 | self._finished = asyncio.Event() | |
346 | await self._finished.wait() | |
347 | self._finished = None | |
348 | assert self._pending == 0 | |
335 | 349 | self.log.debug('drain ended') |
336 | 350 | |
337 | 351 | def is_idle(self) -> bool: |
0 | #!/usr/bin/env python3 | |
1 | ||
2 | import sys | |
3 | import lxml | |
4 | import lxml.etree | |
5 | from typing import Dict, List, Set, Tuple # noqa F401 | |
6 | ||
7 | if len(sys.argv) >= 2: | |
8 | # Munge import path to insert build location for libvirt mod | |
9 | sys.path.insert(0, sys.argv[1]) | |
10 | import libvirt | |
11 | ||
12 | ||
13 | def get_libvirt_api_xml_path(): | |
14 | import subprocess | |
15 | args = ["pkg-config", "--variable", "libvirt_api", "libvirt"] | |
16 | proc = subprocess.Popen(args, stdout=subprocess.PIPE) | |
17 | stdout, _ = proc.communicate() | |
18 | if proc.returncode: | |
19 | sys.exit(proc.returncode) | |
20 | return stdout.splitlines()[0] | |
21 | ||
22 | ||
23 | # Path to the libvirt API XML file | |
24 | if len(sys.argv) >= 3: | |
25 | xml = sys.argv[2] | |
26 | else: | |
27 | xml = get_libvirt_api_xml_path() | |
28 | ||
29 | with open(xml, "r") as fp: | |
30 | tree = lxml.etree.parse(fp) | |
31 | ||
32 | verbose = False | |
33 | fail = False | |
34 | ||
35 | enumvals = {} # type: Dict[str, Dict[str, int]] | |
36 | second_pass = [] # type: List[str] | |
37 | wantenums = [] # type: List[str] | |
38 | wantfunctions = [] # type: List[str] | |
39 | ||
40 | # Phase 1: Identify all functions and enums in public API | |
41 | wantfunctions = tree.xpath('/api/files/file/exports[@type="function"]/@symbol') | |
42 | ||
43 | for n in tree.xpath('/api/symbols/enum'): | |
44 | typ = n.attrib['type'] | |
45 | name = n.attrib['name'] | |
46 | val = n.attrib['value'] | |
47 | ||
48 | if typ not in enumvals: | |
49 | enumvals[typ] = {} | |
50 | ||
51 | # If the value cannot be converted to int, it is reference to | |
52 | # another enum and needs to be sorted out later on | |
53 | try: | |
54 | val = int(val) | |
55 | except ValueError: | |
56 | second_pass.append(n) | |
57 | continue | |
58 | ||
59 | enumvals[typ][name] = int(val) | |
60 | ||
61 | for n in second_pass: | |
62 | typ = n.attrib['type'] | |
63 | name = n.attrib['name'] | |
64 | val = n.attrib['value'] | |
65 | ||
66 | for v in enumvals.values(): | |
67 | if val in v: | |
68 | val = int(v[val]) | |
69 | break | |
70 | ||
71 | # Version 4.0.0 was broken as missing VIR_TYPED_PARAM enums | |
72 | # constants. This is harmless from POV of validating API | |
73 | # coverage so ignore this error. | |
74 | if (not isinstance(val, int) and | |
75 | not val.startswith("VIR_TYPED_PARAM_")): | |
76 | fail = True | |
77 | print("Cannot get a value of enum %s (originally %s)" % (val, name)) | |
78 | enumvals[typ][name] = val | |
79 | ||
80 | for n in tree.xpath('/api/files/file/exports[@type="enum"]/@symbol'): | |
81 | for enumval in enumvals.values(): | |
82 | if n in enumval: | |
83 | enumv = enumval | |
84 | break | |
85 | # Eliminate sentinels | |
86 | if n.endswith('_LAST') and enumv[n] == max(enumv.values()): | |
87 | continue | |
88 | wantenums.append(n) | |
89 | ||
90 | # Phase 2: Identify all classes and methods in the 'libvirt' python module | |
91 | gotenums = [] # type: List[str] | |
92 | gottypes = [] # type: List[str] | |
93 | gotfunctions = {"libvirt": []} # type: Dict[str, List[str]] | |
94 | ||
95 | for name in dir(libvirt): | |
96 | if name.startswith('_'): | |
97 | continue | |
98 | thing = getattr(libvirt, name) | |
99 | # Special-case libvirtError to deal with python 2.4 difference | |
100 | # in Exception class type reporting. | |
101 | if isinstance(thing, int): | |
102 | gotenums.append(name) | |
103 | elif getattr(thing, "__module__", "") == "typing": | |
104 | continue | |
105 | elif type(thing) == type or name == "libvirtError": | |
106 | gottypes.append(name) | |
107 | gotfunctions[name] = [] | |
108 | elif callable(thing): | |
109 | gotfunctions["libvirt"].append(name) | |
110 | ||
111 | for enum in wantenums: | |
112 | if enum not in gotenums: | |
113 | fail = True | |
114 | for typ, enumval in enumvals.items(): | |
115 | if enum in enumval: | |
116 | print("FAIL Missing exported enum %s of type %s" % (enum, typ)) | |
117 | ||
118 | for klassname in gottypes: | |
119 | klassobj = getattr(libvirt, klassname) | |
120 | for name in dir(klassobj): | |
121 | if name.startswith('_'): | |
122 | continue | |
123 | if name == 'c_pointer': | |
124 | continue | |
125 | thing = getattr(klassobj, name) | |
126 | if callable(thing): | |
127 | gotfunctions[klassname].append(name) | |
128 | ||
129 | ||
130 | # Phase 3: First cut at mapping of C APIs to python classes + methods | |
131 | basicklassmap = {} # type: Dict[str, Tuple[str, str, str]] | |
132 | ||
133 | for cname in wantfunctions: | |
134 | name = cname | |
135 | # Some virConnect APIs have stupid names | |
136 | if name[0:7] == "virNode" and name[0:13] != "virNodeDevice": | |
137 | name = "virConnect" + name[7:] | |
138 | if name[0:7] == "virConn" and name[0:10] != "virConnect": | |
139 | name = "virConnect" + name[7:] | |
140 | ||
141 | # The typed param APIs are only for internal use | |
142 | if name[0:14] == "virTypedParams": | |
143 | continue | |
144 | ||
145 | if name[0:23] == "virNetworkDHCPLeaseFree": | |
146 | continue | |
147 | ||
148 | if name[0:28] == "virDomainStatsRecordListFree": | |
149 | continue | |
150 | ||
151 | if name[0:19] == "virDomainFSInfoFree": | |
152 | continue | |
153 | ||
154 | if name[0:25] == "virDomainIOThreadInfoFree": | |
155 | continue | |
156 | ||
157 | if name[0:22] == "virDomainInterfaceFree": | |
158 | continue | |
159 | ||
160 | if name[0:21] == "virDomainListGetStats": | |
161 | name = "virConnectDomainListGetStats" | |
162 | ||
163 | # These aren't functions, they're callback signatures | |
164 | if name in ["virConnectAuthCallbackPtr", "virConnectCloseFunc", | |
165 | "virStreamSinkFunc", "virStreamSourceFunc", "virStreamEventCallback", | |
166 | "virEventHandleCallback", "virEventTimeoutCallback", "virFreeCallback", | |
167 | "virStreamSinkHoleFunc", "virStreamSourceHoleFunc", "virStreamSourceSkipFunc"]: | |
168 | continue | |
169 | if name[0:21] == "virConnectDomainEvent" and name[-8:] == "Callback": | |
170 | continue | |
171 | if name[0:22] == "virConnectNetworkEvent" and name[-8:] == "Callback": | |
172 | continue | |
173 | if (name.startswith("virConnectStoragePoolEvent") and | |
174 | name.endswith("Callback")): | |
175 | continue | |
176 | if (name.startswith("virConnectNodeDeviceEvent") and | |
177 | name.endswith("Callback")): | |
178 | continue | |
179 | if (name.startswith("virConnectSecretEvent") and | |
180 | name.endswith("Callback")): | |
181 | continue | |
182 | ||
183 | # virEvent APIs go into main 'libvirt' namespace not any class | |
184 | if name[0:8] == "virEvent": | |
185 | if name[-4:] == "Func": | |
186 | continue | |
187 | basicklassmap[name] = ("libvirt", name, cname) | |
188 | else: | |
189 | found = False | |
190 | # To start with map APIs to classes based on the | |
191 | # naming prefix. Mistakes will be fixed in next | |
192 | # loop | |
193 | for klassname in gottypes: | |
194 | klen = len(klassname) | |
195 | if name[0:klen] == klassname: | |
196 | found = True | |
197 | if name not in basicklassmap: | |
198 | basicklassmap[name] = (klassname, name[klen:], cname) | |
199 | elif len(basicklassmap[name]) < klen: | |
200 | basicklassmap[name] = (klassname, name[klen:], cname) | |
201 | ||
202 | # Anything which can't map to a class goes into the | |
203 | # global namespaces | |
204 | if not found: | |
205 | basicklassmap[name] = ("libvirt", name[3:], cname) | |
206 | ||
207 | ||
208 | # Phase 4: Deal with oh so many special cases in C -> python mapping | |
209 | finalklassmap = {} # type: Dict[str, Tuple[str, str, str]] | |
210 | ||
211 | for name, (klass, func, cname) in sorted(basicklassmap.items()): | |
212 | # The object lifecycle APIs are irrelevant since they're | |
213 | # used inside the object constructors/destructors. | |
214 | if func in ["Ref", "Free", "New", "GetConnect", "GetDomain", "GetNetwork"]: | |
215 | if klass == "virStream" and func == "New": | |
216 | klass = "virConnect" | |
217 | func = "NewStream" | |
218 | else: | |
219 | continue | |
220 | ||
221 | # All the error handling methods need special handling | |
222 | if klass == "libvirt": | |
223 | if func in ["CopyLastError", "DefaultErrorFunc", | |
224 | "ErrorFunc", "FreeError", | |
225 | "SaveLastError", "ResetError"]: | |
226 | continue | |
227 | elif func in ["GetLastError", "GetLastErrorMessage", | |
228 | "GetLastErrorCode", "GetLastErrorDomain", | |
229 | "ResetLastError", "Initialize"]: | |
230 | func = "vir" + func | |
231 | elif func == "SetErrorFunc": | |
232 | func = "RegisterErrorHandler" | |
233 | elif klass == "virConnect": | |
234 | if func in ["CopyLastError", "SetErrorFunc"]: | |
235 | continue | |
236 | elif func in ["GetLastError", "ResetLastError"]: | |
237 | func = "virConn" + func | |
238 | ||
239 | # Remove 'Get' prefix from most APIs, except those in virConnect | |
240 | # and virDomainSnapshot namespaces which stupidly used a different | |
241 | # convention which we now can't fix without breaking API | |
242 | if func[0:3] == "Get" and klass not in ["virConnect", "virDomainCheckpoint", "virDomainSnapshot", "libvirt"]: | |
243 | if func not in ["GetCPUStats", "GetTime"]: | |
244 | func = func[3:] | |
245 | ||
246 | # The object creation and lookup APIs all have to get re-mapped | |
247 | # into the parent class | |
248 | if func in ["CreateXML", "CreateLinux", "CreateXMLWithFiles", | |
249 | "DefineXML", "CreateXMLFrom", "LookupByUUID", | |
250 | "LookupByUUIDString", "LookupByVolume" "LookupByName", | |
251 | "LookupByID", "LookupByName", "LookupByKey", "LookupByPath", | |
252 | "LookupByMACString", "LookupByUsage", "LookupByVolume", | |
253 | "LookupByTargetPath", "LookupSCSIHostByWWN", "LookupByPortDev", | |
254 | "Restore", "RestoreFlags", | |
255 | "SaveImageDefineXML", "SaveImageGetXMLDesc", "DefineXMLFlags", | |
256 | "CreateXMLFlags"]: | |
257 | if klass != "virDomain": | |
258 | func = klass[3:] + func | |
259 | ||
260 | if klass in ["virDomainCheckpoint", "virDomainSnapshot"]: | |
261 | klass = "virDomain" | |
262 | func = func[6:] | |
263 | elif klass == "virStorageVol" and func in ["StorageVolCreateXMLFrom", "StorageVolCreateXML"]: | |
264 | klass = "virStoragePool" | |
265 | func = func[10:] | |
266 | elif klass == "virNetworkPort": | |
267 | klass = "virNetwork" | |
268 | func = func[7:] | |
269 | elif func == "StoragePoolLookupByVolume": | |
270 | klass = "virStorageVol" | |
271 | elif func == "StorageVolLookupByName": | |
272 | klass = "virStoragePool" | |
273 | else: | |
274 | klass = "virConnect" | |
275 | ||
276 | # The open methods get remapped to primary namespace | |
277 | if klass == "virConnect" and func in ["Open", "OpenAuth", "OpenReadOnly"]: | |
278 | klass = "libvirt" | |
279 | ||
280 | # These are inexplicably renamed in the python API | |
281 | if func == "ListDomains": | |
282 | func = "ListDomainsID" | |
283 | elif func == "ListAllNodeDevices": | |
284 | func = "ListAllDevices" | |
285 | elif func == "ListNodeDevices": | |
286 | func = "ListDevices" | |
287 | ||
288 | # The virInterfaceChangeXXXX APIs go into virConnect. Stupidly | |
289 | # they have lost their 'interface' prefix in names, but we can't | |
290 | # fix this name | |
291 | if func[0:6] == "Change": | |
292 | klass = "virConnect" | |
293 | ||
294 | # Need to special case the checkpoint and snapshot APIs | |
295 | if klass == "virDomainSnapshot" and func in ["Current", "ListNames", "Num"]: | |
296 | klass = "virDomain" | |
297 | func = "snapshot" + func | |
298 | ||
299 | # Names should start with lowercase letter... | |
300 | func = func[0:1].lower() + func[1:] | |
301 | if func[0:8] == "nWFilter": | |
302 | func = "nwfilter" + func[8:] | |
303 | if func[0:8] == "fSFreeze" or func[0:6] == "fSThaw" or func[0:6] == "fSInfo": | |
304 | func = "fs" + func[2:] | |
305 | if func[0:12] == "iOThreadInfo": | |
306 | func = "ioThreadInfo" | |
307 | ||
308 | if klass == "virNetwork": | |
309 | func = func.replace("dHCP", "DHCP") | |
310 | ||
311 | # ...except when they don't. More stupid naming | |
312 | # decisions we can't fix | |
313 | if func == "iD": | |
314 | func = "ID" | |
315 | if func == "uUID": | |
316 | func = "UUID" | |
317 | if func == "uUIDString": | |
318 | func = "UUIDString" | |
319 | if func == "oSType": | |
320 | func = "OSType" | |
321 | if func == "xMLDesc": | |
322 | func = "XMLDesc" | |
323 | if func == "mACString": | |
324 | func = "MACString" | |
325 | ||
326 | finalklassmap[name] = (klass, func, cname) | |
327 | ||
328 | ||
329 | # Phase 5: Validate sure that every C API is mapped to a python API | |
330 | usedfunctions = set() # type: Set[str] | |
331 | for name, (klass, func, cname) in sorted(finalklassmap.items()): | |
332 | if func in gotfunctions[klass]: | |
333 | usedfunctions.add("%s.%s" % (klass, func)) | |
334 | if verbose: | |
335 | print("PASS %s -> %s.%s" % (name, klass, func)) | |
336 | else: | |
337 | print("FAIL %s -> %s.%s (C API not mapped to python)" % (name, klass, func)) | |
338 | fail = True | |
339 | ||
340 | ||
341 | # Phase 6: Validate that every python API has a corresponding C API | |
342 | for klass in gotfunctions: | |
343 | if klass == "libvirtError": | |
344 | continue | |
345 | for func in sorted(gotfunctions[klass]): | |
346 | # These are pure python methods with no C APi | |
347 | if func in ["connect", "getConnect", "domain", "getDomain", | |
348 | "virEventInvokeFreeCallback", "network", | |
349 | "sparseRecvAll", "sparseSendAll"]: | |
350 | continue | |
351 | ||
352 | key = "%s.%s" % (klass, func) | |
353 | if key not in usedfunctions: | |
354 | print("FAIL %s.%s (Python API not mapped to C)" % (klass, func)) | |
355 | fail = True | |
356 | else: | |
357 | if verbose: | |
358 | print("PASS %s.%s" % (klass, func)) | |
359 | ||
360 | # Phase 7: Validate that all the low level C APIs have binding | |
361 | for name, (klass, func, cname) in sorted(finalklassmap.items()): | |
362 | pyname = cname | |
363 | if pyname == "virSetErrorFunc": | |
364 | pyname = "virRegisterErrorHandler" | |
365 | elif pyname == "virConnectListDomains": | |
366 | pyname = "virConnectListDomainsID" | |
367 | ||
368 | # These exist in C and exist in python, but we've got | |
369 | # a pure-python impl so don't check them | |
370 | if name in ["virStreamRecvAll", "virStreamSendAll", | |
371 | "virStreamSparseRecvAll", "virStreamSparseSendAll"]: | |
372 | continue | |
373 | ||
374 | try: | |
375 | thing = getattr(libvirt.libvirtmod, pyname) | |
376 | except AttributeError: | |
377 | print("FAIL libvirt.libvirtmod.%s (C binding does not exist)" % pyname) | |
378 | fail = True | |
379 | ||
380 | if fail: | |
381 | sys.exit(1) | |
382 | else: | |
383 | sys.exit(0) |
0 | 0 | #!/usr/bin/env python3 |
1 | 1 | |
2 | from distutils.core import setup, Extension, Command | |
3 | from distutils.command.build import build | |
4 | from distutils.command.clean import clean | |
5 | from distutils.command.sdist import sdist | |
6 | from distutils.dir_util import remove_tree | |
7 | from distutils.util import get_platform | |
8 | from distutils.spawn import spawn | |
9 | from distutils.errors import DistutilsExecError | |
10 | import distutils | |
11 | ||
2 | from setuptools import setup, Extension, Command | |
3 | from setuptools.command.build_ext import build_ext | |
4 | from setuptools.command.build_py import build_py | |
5 | from setuptools.command.sdist import sdist | |
6 | ||
7 | import glob | |
12 | 8 | import sys |
13 | 9 | import os |
14 | 10 | import os.path |
15 | 11 | import re |
16 | 12 | import shutil |
13 | import subprocess | |
17 | 14 | import time |
18 | 15 | |
19 | 16 | if sys.version_info < (3, 5): |
28 | 25 | if not os.path.exists("build"): |
29 | 26 | os.mkdir("build") |
30 | 27 | |
31 | _pkgcfg = -1 | |
32 | def get_pkgcfg(do_fail=True): | |
33 | global _pkgcfg | |
34 | if _pkgcfg == -1: | |
35 | _pkgcfg = os.getenv('PKG_CONFIG') | |
36 | if _pkgcfg is None: | |
37 | _pkgcfg = distutils.spawn.find_executable("pkg-config") | |
38 | if _pkgcfg is None and do_fail: | |
39 | raise Exception("pkg-config binary is required to compile libvirt-python") | |
40 | return _pkgcfg | |
28 | def check_pkgcfg(): | |
29 | try: | |
30 | proc = subprocess.run(["pkg-config", "--version"], | |
31 | stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) | |
32 | if proc.returncode != 0: | |
33 | print("pkg-config binary does not appear to be functional") | |
34 | sys.exit(1) | |
35 | except FileNotFoundError: | |
36 | print("pkg-config binary is required to compile libvirt-python") | |
37 | sys.exit(1) | |
38 | ||
39 | check_pkgcfg() | |
41 | 40 | |
42 | 41 | def check_minimum_libvirt_version(): |
43 | spawn([get_pkgcfg(), | |
44 | "--print-errors", | |
45 | "--atleast-version=%s" % MIN_LIBVIRT, | |
46 | "libvirt"]) | |
42 | subprocess.check_call(["pkg-config", | |
43 | "--print-errors", | |
44 | "--atleast-version=%s" % MIN_LIBVIRT, | |
45 | "libvirt"]) | |
47 | 46 | |
48 | 47 | def have_libvirt_lxc(): |
49 | try: | |
50 | spawn([get_pkgcfg(), | |
51 | "--atleast-version=%s" % MIN_LIBVIRT_LXC, | |
52 | "libvirt"]) | |
48 | proc = subprocess.run(["pkg-config", | |
49 | "--atleast-version=%s" % MIN_LIBVIRT_LXC, | |
50 | "libvirt"]) | |
51 | if proc.returncode == 0: | |
53 | 52 | return True |
54 | except DistutilsExecError: | |
55 | return False | |
53 | return False | |
56 | 54 | |
57 | 55 | def get_pkgconfig_data(args, mod, required=True): |
58 | 56 | """Run pkg-config to and return content associated with it""" |
59 | f = os.popen("%s %s %s" % (get_pkgcfg(), " ".join(args), mod)) | |
57 | f = os.popen("%s %s %s" % ("pkg-config", " ".join(args), mod)) | |
60 | 58 | |
61 | 59 | line = f.readline() |
62 | 60 | if line is not None: |
89 | 87 | Determine which modules we are actually building, and all their |
90 | 88 | required config |
91 | 89 | """ |
92 | if get_pkgcfg(do_fail=False) is None: | |
93 | return [], [] | |
94 | ||
95 | 90 | c_modules = [] |
96 | 91 | py_modules = [] |
97 | 92 | ldflags = get_pkgconfig_data(["--libs-only-L"], "libvirt", False).split() |
109 | 104 | |
110 | 105 | moduleqemu = Extension('libvirtmod_qemu', |
111 | 106 | sources = ['libvirt-qemu-override.c', 'build/libvirt-qemu.c', 'typewrappers.c', 'libvirt-utils.c'], |
112 | libraries = [ "virt-qemu" ], | |
107 | libraries = [ "virt-qemu", "virt" ], | |
113 | 108 | include_dirs = [ "." ]) |
114 | 109 | moduleqemu.extra_compile_args.extend(cflags) |
115 | 110 | moduleqemu.extra_link_args.extend(ldflags) |
120 | 115 | if have_libvirt_lxc(): |
121 | 116 | modulelxc = Extension('libvirtmod_lxc', |
122 | 117 | sources = ['libvirt-lxc-override.c', 'build/libvirt-lxc.c', 'typewrappers.c', 'libvirt-utils.c'], |
123 | libraries = [ "virt-lxc" ], | |
118 | libraries = [ "virt-lxc", "virt" ], | |
124 | 119 | include_dirs = [ "." ]) |
125 | 120 | modulelxc.extra_compile_args.extend(cflags) |
126 | 121 | modulelxc.extra_link_args.extend(ldflags) |
137 | 132 | # Custom commands # |
138 | 133 | ################### |
139 | 134 | |
140 | class my_build(build): | |
135 | class my_build_ext(build_ext): | |
141 | 136 | |
142 | 137 | def run(self): |
143 | 138 | check_minimum_libvirt_version() |
144 | 139 | apis = get_api_xml_files() |
145 | 140 | |
146 | self.spawn([sys.executable, "generator.py", "libvirt", apis[0]]) | |
147 | self.spawn([sys.executable, "generator.py", "libvirt-qemu", apis[1]]) | |
141 | subprocess.check_call([sys.executable, "generator.py", "libvirt", apis[0], "c"]) | |
142 | subprocess.check_call([sys.executable, "generator.py", "libvirt-qemu", apis[1], "c"]) | |
148 | 143 | if have_libvirt_lxc(): |
149 | self.spawn([sys.executable, "generator.py", "libvirt-lxc", apis[2]]) | |
144 | subprocess.check_call([sys.executable, "generator.py", "libvirt-lxc", apis[2], "c"]) | |
145 | ||
146 | build_ext.run(self) | |
147 | ||
148 | class my_build_py(build_py): | |
149 | ||
150 | def run(self): | |
151 | check_minimum_libvirt_version() | |
152 | apis = get_api_xml_files() | |
153 | ||
154 | subprocess.check_call([sys.executable, "generator.py", "libvirt", apis[0], "py"]) | |
155 | subprocess.check_call([sys.executable, "generator.py", "libvirt-qemu", apis[1], "py"]) | |
156 | if have_libvirt_lxc(): | |
157 | subprocess.check_call([sys.executable, "generator.py", "libvirt-lxc", apis[2], "py"]) | |
150 | 158 | shutil.copy('libvirtaio.py', 'build') |
151 | 159 | |
152 | build.run(self) | |
160 | build_py.run(self) | |
153 | 161 | |
154 | 162 | class my_sdist(sdist): |
155 | 163 | user_options = sdist.user_options |
232 | 240 | else: |
233 | 241 | sdist.run(self) |
234 | 242 | |
235 | class my_rpm(Command): | |
236 | user_options = [] | |
237 | ||
238 | description = "Build src and noarch rpms." | |
239 | ||
240 | def initialize_options(self): | |
241 | pass | |
242 | ||
243 | def finalize_options(self): | |
244 | pass | |
245 | ||
246 | def run(self): | |
247 | """ | |
248 | Run sdist, then 'rpmbuild' the tar.gz | |
249 | """ | |
250 | ||
251 | self.run_command('sdist') | |
252 | self.spawn(["/usr/bin/rpmbuild", "-ta", "--clean", | |
253 | "dist/libvirt-python-%s.tar.gz" % self.distribution.get_version()]) | |
254 | ||
255 | 243 | class my_test(Command): |
256 | 244 | user_options = [ |
257 | 245 | ('build-base=', 'b', |
259 | 247 | ('build-platlib=', None, |
260 | 248 | "build directory for platform-specific distributions"), |
261 | 249 | ('plat-name=', 'p', |
262 | "platform name to build for, if supported " | |
263 | "(default: %s)" % get_platform()), | |
250 | "platform name to build for, if supported "), | |
264 | 251 | ] |
265 | 252 | |
266 | 253 | description = "Run test suite." |
254 | ||
255 | def find_build_dir(self): | |
256 | if self.plat_name is not None: | |
257 | plat_specifier = ".%s-%d.%d" % (self.plat_name, | |
258 | sys.version_info[0], | |
259 | sys.version_info[1]) | |
260 | if hasattr(sys, 'gettotalrefcount'): | |
261 | plat_specifier += '-pydebug' | |
262 | ||
263 | return os.path.join(self.build_base, | |
264 | 'lib' + plat_specifier) | |
265 | else: | |
266 | dirs = glob.glob(os.path.join(self.build_base, | |
267 | "lib.*")) | |
268 | if len(dirs) == 0: | |
269 | print("No build directory found, run 'setup.py build'") | |
270 | sys.exit(1) | |
271 | if len(dirs) > 1: | |
272 | print("Multiple build dirs found, use --plat-name option") | |
273 | sys.exit(1) | |
274 | return dirs[0] | |
267 | 275 | |
268 | 276 | def initialize_options(self): |
269 | 277 | self.build_base = 'build' |
271 | 279 | self.plat_name = None |
272 | 280 | |
273 | 281 | def finalize_options(self): |
274 | if self.plat_name is None: | |
275 | self.plat_name = get_platform() | |
276 | ||
277 | plat_specifier = ".%s-%d.%d" % (self.plat_name, | |
278 | sys.version_info[0], | |
279 | sys.version_info[1]) | |
280 | ||
281 | if hasattr(sys, 'gettotalrefcount'): | |
282 | plat_specifier += '-pydebug' | |
283 | ||
284 | 282 | if self.build_platlib is None: |
285 | self.build_platlib = os.path.join(self.build_base, | |
286 | 'lib' + plat_specifier) | |
283 | self.build_platlib = self.find_build_dir() | |
287 | 284 | |
288 | 285 | def find_pytest_path(self): |
289 | 286 | binaries = [ |
295 | 292 | ] |
296 | 293 | |
297 | 294 | for binary in binaries: |
298 | path = distutils.spawn.find_executable(binary) | |
295 | path = shutil.which(binary) | |
299 | 296 | if path is not None: |
300 | 297 | return path |
301 | 298 | |
305 | 302 | """ |
306 | 303 | Run test suite |
307 | 304 | """ |
308 | ||
309 | apis = get_api_xml_files() | |
310 | 305 | |
311 | 306 | if "PYTHONPATH" in os.environ: |
312 | 307 | os.environ["PYTHONPATH"] = self.build_platlib + ":" + os.environ["PYTHONPATH"] |
313 | 308 | else: |
314 | 309 | os.environ["PYTHONPATH"] = self.build_platlib |
315 | 310 | |
316 | if "LIBVIRT_API_COVERAGE" in os.environ: | |
317 | self.spawn([sys.executable, "sanitytest.py", self.build_platlib, apis[0]]) | |
318 | 311 | pytest = self.find_pytest_path() |
319 | self.spawn([sys.executable, pytest]) | |
320 | ||
321 | ||
322 | class my_clean(clean): | |
323 | def run(self): | |
324 | clean.run(self) | |
325 | ||
312 | subprocess.check_call([pytest]) | |
313 | ||
314 | class my_clean(Command): | |
315 | user_options = [ | |
316 | ('all', None, 'unused, compatibility with distutils') | |
317 | ] | |
318 | ||
319 | def initialize_options(self): | |
320 | self.all = False | |
321 | ||
322 | def finalize_options(self): | |
323 | pass | |
324 | ||
325 | def run(self): | |
326 | 326 | if os.path.exists("build"): |
327 | remove_tree("build") | |
327 | shutil.rmtree("build", ignore_errors=True) | |
328 | 328 | |
329 | 329 | |
330 | 330 | ################## |
334 | 334 | _c_modules, _py_modules = get_module_lists() |
335 | 335 | |
336 | 336 | setup(name = 'libvirt-python', |
337 | version = '8.0.0', | |
337 | version = '9.0.0', | |
338 | 338 | url = 'http://www.libvirt.org', |
339 | 339 | maintainer = 'Libvirt Maintainers', |
340 | 340 | maintainer_email = 'libvir-list@redhat.com', |
351 | 351 | '': 'build' |
352 | 352 | }, |
353 | 353 | cmdclass = { |
354 | 'build': my_build, | |
354 | 'build_ext': my_build_ext, | |
355 | 'build_py': my_build_py, | |
355 | 356 | 'clean': my_clean, |
356 | 357 | 'sdist': my_sdist, |
357 | 'rpm': my_rpm, | |
358 | 358 | 'test': my_test |
359 | 359 | }, |
360 | 360 | classifiers = [ |
367 | 367 | "Programming Language :: Python :: 3.6", |
368 | 368 | "Programming Language :: Python :: 3.7", |
369 | 369 | "Programming Language :: Python :: 3.8", |
370 | "Programming Language :: Python :: 3.9", | |
371 | "Programming Language :: Python :: 3.10", | |
370 | 372 | ] |
371 | 373 | ) |
0 | ||
1 | import libvirt | |
2 | import libvirtmod | |
3 | ||
4 | _add_handle_impl = None | |
5 | _update_handle_impl = None | |
6 | _remove_handle_impl = None | |
7 | ||
8 | _add_timeout_impl = None | |
9 | _update_timeout_impl = None | |
10 | _remove_timeout_impl = None | |
11 | ||
12 | _registered = False | |
13 | ||
14 | def _add_handle(fd: int, event: int, cb: libvirt._EventCB, opaque: libvirt._T) -> int: | |
15 | global _add_handle_impl | |
16 | assert _add_handle_impl != None | |
17 | return _add_handle_impl(fd, event, cb, opaque) | |
18 | ||
19 | def _update_handle(watch: int, event: int) -> None: | |
20 | global _update_handle_impl | |
21 | assert _update_handle_impl != None | |
22 | _update_handle_impl(watch, event) | |
23 | ||
24 | def _remove_handle(watch: int) -> int: | |
25 | global _remove_handle_impl | |
26 | assert _remove_handle_impl != None | |
27 | return _remove_handle_impl(watch) | |
28 | ||
29 | def _add_timeout(timeout: int, cb: libvirt._TimerCB, opaque: libvirt._T) -> int: | |
30 | global _add_timeout_impl | |
31 | assert _add_timeout_impl != None | |
32 | return _add_timeout_impl(timeout, cb, opaque) | |
33 | ||
34 | def _update_timeout(timer: int, timeout: int) -> None: | |
35 | global _update_timeout_impl | |
36 | assert _update_timeout_impl != None | |
37 | _update_timeout_impl(timer, timeout) | |
38 | ||
39 | def _remove_timeout(timer: int) -> int: | |
40 | global _remove_timeout_impl | |
41 | assert _remove_timeout_impl != None | |
42 | return _remove_timeout_impl(timer) | |
43 | ||
44 | # libvirt.virEventRegisterImpl() is a one time call per process | |
45 | # This method is intended to be used with mock patching, so that | |
46 | # tests can get the appearance of being able to call | |
47 | # virEventRegisterImpl many times. | |
48 | # | |
49 | # Note, this relies on the tests closing all connection objects | |
50 | # and not leaving any handles/timers pending when they stop | |
51 | # running their event loop impl. | |
52 | ||
53 | def virEventRegisterImplMock(add_handle_impl, | |
54 | update_handle_impl, | |
55 | remove_handle_impl, | |
56 | add_timeout_impl, | |
57 | update_timeout_impl, | |
58 | remove_timeout_impl): | |
59 | global _add_handle_impl | |
60 | global _update_handle_impl | |
61 | global _remove_handle_impl | |
62 | global _add_timeout_impl | |
63 | global _update_timeout_impl | |
64 | global _remove_timeout_impl | |
65 | ||
66 | _add_handle_impl = add_handle_impl | |
67 | _update_handle_impl = update_handle_impl | |
68 | _remove_handle_impl = remove_handle_impl | |
69 | _add_timeout_impl = add_timeout_impl | |
70 | _update_timeout_impl = update_timeout_impl | |
71 | _remove_timeout_impl = remove_timeout_impl | |
72 | ||
73 | global _registered | |
74 | if not _registered: | |
75 | libvirtmod.virEventRegisterImpl(_add_handle, | |
76 | _update_handle, | |
77 | _remove_timeout, | |
78 | _add_timeout, | |
79 | _update_timeout, | |
80 | _remove_timeout) | |
81 | _registered = True |
0 | import asyncio | |
1 | import libvirt | |
2 | import libvirtaio | |
3 | import sys | |
4 | import unittest | |
5 | from unittest import mock | |
6 | ||
7 | import eventmock | |
8 | ||
9 | ||
10 | class TestLibvirtAio(unittest.TestCase): | |
11 | async def _run(self, register): | |
12 | def lifecycleCallback(conn, dom, event, detail, domainChangedEvent): | |
13 | if (event == libvirt.VIR_DOMAIN_EVENT_STOPPED or | |
14 | event == libvirt.VIR_DOMAIN_EVENT_STARTED): | |
15 | domainChangedEvent.set() | |
16 | ||
17 | if register: | |
18 | libvirtEvents = libvirtaio.virEventRegisterAsyncIOImpl() | |
19 | else: | |
20 | libvirtEvents = libvirtaio.getCurrentImpl() | |
21 | ||
22 | conn = libvirt.open("test:///default") | |
23 | dom = conn.lookupByName("test") | |
24 | ||
25 | eventRegistered = False | |
26 | domainStopped = False | |
27 | try: | |
28 | # Ensure the VM is running. | |
29 | self.assertEqual([libvirt.VIR_DOMAIN_RUNNING, libvirt.VIR_DOMAIN_RUNNING_UNKNOWN], dom.state()) | |
30 | self.assertTrue(libvirtEvents.is_idle()) | |
31 | ||
32 | # Register VM start/stopped event handler. | |
33 | domainChangedEvent = asyncio.Event() | |
34 | conn.domainEventRegisterAny(dom, libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE, lifecycleCallback, domainChangedEvent) | |
35 | eventRegistered = True | |
36 | ||
37 | self.assertFalse(libvirtEvents.is_idle()) | |
38 | ||
39 | # Stop the VM. | |
40 | dom.destroy() | |
41 | domainStopped = True | |
42 | ||
43 | # Ensure domain stopped event is received. | |
44 | await asyncio.wait_for(domainChangedEvent.wait(), 2) | |
45 | self.assertEqual([libvirt.VIR_DOMAIN_SHUTOFF, libvirt.VIR_DOMAIN_SHUTOFF_DESTROYED], dom.state()) | |
46 | ||
47 | # Start the VM. | |
48 | domainChangedEvent.clear() | |
49 | domainStopped = False | |
50 | dom.create() | |
51 | ||
52 | # Ensure domain started event is received. | |
53 | await asyncio.wait_for(domainChangedEvent.wait(), 2) | |
54 | self.assertEqual([libvirt.VIR_DOMAIN_RUNNING, libvirt.VIR_DOMAIN_RUNNING_BOOTED], dom.state()) | |
55 | self.assertFalse(libvirtEvents.is_idle()) | |
56 | ||
57 | # Deregister the VM start/stopped event handler. | |
58 | eventRegistered = False | |
59 | conn.domainEventDeregisterAny(libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE) | |
60 | ||
61 | # Wait for event queue to clear. | |
62 | await libvirtEvents.drain() | |
63 | ||
64 | # Make sure event queue is cleared. | |
65 | self.assertTrue(libvirtEvents.is_idle()) | |
66 | ||
67 | finally: | |
68 | if eventRegistered: | |
69 | conn.domainEventDeregisterAny(libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE) | |
70 | ||
71 | if domainStopped: | |
72 | dom.create() | |
73 | ||
74 | @mock.patch('libvirt.virEventRegisterImpl', | |
75 | side_effect=eventmock.virEventRegisterImplMock) | |
76 | def testEventsWithManualLoopSetup(self, mock_event_register): | |
77 | # Register libvirt events after starting the asyncio loop. | |
78 | # | |
79 | # Manually create and set the event loop against this | |
80 | # thread. | |
81 | loop = asyncio.new_event_loop() | |
82 | asyncio.set_event_loop(loop) | |
83 | ||
84 | loop.run_until_complete(self._run(register=True)) | |
85 | ||
86 | loop.close() | |
87 | asyncio.set_event_loop(None) | |
88 | mock_event_register.assert_called_once() | |
89 | ||
90 | @mock.patch('libvirt.virEventRegisterImpl', | |
91 | side_effect=eventmock.virEventRegisterImplMock) | |
92 | @unittest.skipIf(sys.version_info < (3,7), "test requires Python 3.7+") | |
93 | def testEventsWithAsyncioRun(self, mock_event_register): | |
94 | # Register libvirt events after starting the asyncio loop. | |
95 | # | |
96 | # Use asyncio helper to create and set the event loop | |
97 | # against this thread. | |
98 | asyncio.run(self._run(register=True)) | |
99 | mock_event_register.assert_called_once() | |
100 | ||
101 | @mock.patch('libvirt.virEventRegisterImpl', | |
102 | side_effect=eventmock.virEventRegisterImplMock) | |
103 | def testEventsPreInitExplicit(self, mock_event_register): | |
104 | # Register libvirt events before starting the asyncio loop. | |
105 | # | |
106 | # Tell virEventRegisterAsyncIOImpl() explicitly what loop | |
107 | # to use before we set a loop for this thread. | |
108 | loop = asyncio.new_event_loop() | |
109 | libvirtaio.virEventRegisterAsyncIOImpl(loop) | |
110 | asyncio.set_event_loop(loop) | |
111 | ||
112 | loop.run_until_complete(self._run(register=False)) | |
113 | ||
114 | loop.close() | |
115 | asyncio.set_event_loop(None) | |
116 | mock_event_register.assert_called_once() | |
117 | ||
118 | @mock.patch('libvirt.virEventRegisterImpl', | |
119 | side_effect=eventmock.virEventRegisterImplMock) | |
120 | @unittest.skipIf(sys.version_info >= (3,10), "test incompatible with 3.10") | |
121 | def testEventsPreInitImplicit(self, mock_event_register): | |
122 | # Register libvirt events before starting the asyncio loop. | |
123 | # | |
124 | # Allow virEventRegisterAsyncIOImpl() to implicitly find the | |
125 | # loop we set for this thread. | |
126 | loop = asyncio.new_event_loop() | |
127 | asyncio.set_event_loop(loop) | |
128 | libvirtaio.virEventRegisterAsyncIOImpl() | |
129 | ||
130 | loop.run_until_complete(self._run(register=False)) | |
131 | ||
132 | loop.close() | |
133 | asyncio.set_event_loop(None) | |
134 | mock_event_register.assert_called_once() | |
135 | ||
136 | @mock.patch('libvirt.virEventRegisterImpl', | |
137 | side_effect=eventmock.virEventRegisterImplMock) | |
138 | @unittest.skipIf(sys.version_info >= (3,10), "test incompatible with 3.10") | |
139 | def testEventsImplicitLoopInit(self, mock_event_register): | |
140 | # Register libvirt events before starting the asyncio loop. | |
141 | # | |
142 | # Let virEventRegisterAsyncIOImpl() auto-create a default | |
143 | # event loop, which we then register against this thread. | |
144 | # | |
145 | # Historically this often worked if called from the main thead, | |
146 | # but since Python 3.10 this triggers a deprecation warning, | |
147 | # which will turn into a RuntimeError in a later release. | |
148 | libvirtaio.virEventRegisterAsyncIOImpl() | |
149 | loop = asyncio.get_event_loop() | |
150 | ||
151 | loop.run_until_complete(self._run(register=False)) | |
152 | ||
153 | loop.close() | |
154 | asyncio.set_event_loop(None) | |
155 | mock_event_register.assert_called_once() |
0 | #!/usr/bin/env python3 | |
1 | ||
2 | import sys | |
3 | from typing import Dict, List, Set, Tuple # noqa F401 | |
4 | import libvirt | |
5 | import unittest | |
6 | import os | |
7 | ||
8 | ||
9 | def get_libvirt_api_xml_path(): | |
10 | import subprocess | |
11 | args = ["pkg-config", "--variable", "libvirt_api", "libvirt"] | |
12 | proc = subprocess.Popen(args, stdout=subprocess.PIPE) | |
13 | stdout, _ = proc.communicate() | |
14 | if proc.returncode: | |
15 | sys.exit(proc.returncode) | |
16 | return stdout.splitlines()[0] | |
17 | ||
18 | # Identify all functions and enums in public API | |
19 | def identify_functions_enums(tree): | |
20 | enumvals = {} # type: Dict[str, Dict[str, int]] | |
21 | second_pass = [] # type: List[str] | |
22 | wantenums = [] # type: List[str] | |
23 | wantfunctions = [] # type: List[str] | |
24 | ||
25 | wantfunctions = tree.xpath('/api/files/file/exports[@type="function"]/@symbol') | |
26 | ||
27 | for n in tree.xpath('/api/symbols/enum'): | |
28 | typ = n.attrib['type'] | |
29 | name = n.attrib['name'] | |
30 | val = n.attrib['value'] | |
31 | ||
32 | if typ not in enumvals: | |
33 | enumvals[typ] = {} | |
34 | ||
35 | # If the value cannot be converted to int, it is reference to | |
36 | # another enum and needs to be sorted out later on | |
37 | try: | |
38 | val = int(val) | |
39 | except ValueError: | |
40 | second_pass.append(n) | |
41 | continue | |
42 | ||
43 | enumvals[typ][name] = int(val) | |
44 | ||
45 | for n in second_pass: | |
46 | typ = n.attrib['type'] | |
47 | name = n.attrib['name'] | |
48 | val = n.attrib['value'] | |
49 | ||
50 | for v in enumvals.values(): | |
51 | if val in v: | |
52 | val = int(v[val]) | |
53 | break | |
54 | ||
55 | # Version 4.0.0 was broken as missing VIR_TYPED_PARAM enums | |
56 | # constants. This is harmless from POV of validating API | |
57 | # coverage so ignore this error. | |
58 | if (not isinstance(val, int) and | |
59 | not val.startswith("VIR_TYPED_PARAM_")): | |
60 | fail = True | |
61 | print("Cannot get a value of enum %s (originally %s)" % (val, name)) | |
62 | enumvals[typ][name] = val | |
63 | ||
64 | for n in tree.xpath('/api/files/file/exports[@type="enum"]/@symbol'): | |
65 | for enumval in enumvals.values(): | |
66 | if n in enumval: | |
67 | enumv = enumval | |
68 | break | |
69 | # Eliminate sentinels | |
70 | if n.endswith('_LAST') and enumv[n] == max(enumv.values()): | |
71 | continue | |
72 | wantenums.append(n) | |
73 | ||
74 | return wantfunctions, wantenums, enumvals | |
75 | ||
76 | ||
77 | # Identify all classes and methods in the 'libvirt' python module | |
78 | def identify_class_methods(wantenums, enumvals): | |
79 | gotenums = [] # type: List[str] | |
80 | gottypes = [] # type: List[str] | |
81 | gotfunctions = {"libvirt": []} # type: Dict[str, List[str]] | |
82 | ||
83 | for name in dir(libvirt): | |
84 | if name.startswith('_'): | |
85 | continue | |
86 | thing = getattr(libvirt, name) | |
87 | # Special-case libvirtError to deal with python 2.4 difference | |
88 | # in Exception class type reporting. | |
89 | if isinstance(thing, int): | |
90 | gotenums.append(name) | |
91 | elif getattr(thing, "__module__", "") == "typing": | |
92 | continue | |
93 | elif type(thing) == type or name == "libvirtError": | |
94 | gottypes.append(name) | |
95 | gotfunctions[name] = [] | |
96 | elif callable(thing): | |
97 | gotfunctions["libvirt"].append(name) | |
98 | ||
99 | for enum in wantenums: | |
100 | if enum not in gotenums: | |
101 | fail = True | |
102 | for typ, enumval in enumvals.items(): | |
103 | if enum in enumval: | |
104 | raise Exception("Missing exported enum %s of type %s" % (enum, typ)) | |
105 | ||
106 | for klassname in gottypes: | |
107 | klassobj = getattr(libvirt, klassname) | |
108 | for name in dir(klassobj): | |
109 | if name.startswith('_'): | |
110 | continue | |
111 | if name == 'c_pointer': | |
112 | continue | |
113 | thing = getattr(klassobj, name) | |
114 | if callable(thing): | |
115 | gotfunctions[klassname].append(name) | |
116 | ||
117 | return gotfunctions, gottypes | |
118 | ||
119 | ||
120 | # First cut at mapping of C APIs to python classes + methods | |
121 | def basic_class_method_mapping(wantfunctions, gottypes): | |
122 | basicklassmap = {} # type: Dict[str, Tuple[str, str, str]] | |
123 | ||
124 | for cname in wantfunctions: | |
125 | name = cname | |
126 | # Some virConnect APIs have stupid names | |
127 | if name[0:7] == "virNode" and name[0:13] != "virNodeDevice": | |
128 | name = "virConnect" + name[7:] | |
129 | if name[0:7] == "virConn" and name[0:10] != "virConnect": | |
130 | name = "virConnect" + name[7:] | |
131 | ||
132 | # The typed param APIs are only for internal use | |
133 | if name[0:14] == "virTypedParams": | |
134 | continue | |
135 | ||
136 | if name[0:23] == "virNetworkDHCPLeaseFree": | |
137 | continue | |
138 | ||
139 | if name[0:28] == "virDomainStatsRecordListFree": | |
140 | continue | |
141 | ||
142 | if name[0:19] == "virDomainFSInfoFree": | |
143 | continue | |
144 | ||
145 | if name[0:25] == "virDomainIOThreadInfoFree": | |
146 | continue | |
147 | ||
148 | if name[0:22] == "virDomainInterfaceFree": | |
149 | continue | |
150 | ||
151 | if name[0:21] == "virDomainListGetStats": | |
152 | name = "virConnectDomainListGetStats" | |
153 | ||
154 | # These aren't functions, they're callback signatures | |
155 | if name in ["virConnectAuthCallbackPtr", "virConnectCloseFunc", | |
156 | "virStreamSinkFunc", "virStreamSourceFunc", "virStreamEventCallback", | |
157 | "virEventHandleCallback", "virEventTimeoutCallback", "virFreeCallback", | |
158 | "virStreamSinkHoleFunc", "virStreamSourceHoleFunc", "virStreamSourceSkipFunc"]: | |
159 | continue | |
160 | if name[0:21] == "virConnectDomainEvent" and name[-8:] == "Callback": | |
161 | continue | |
162 | if name[0:22] == "virConnectNetworkEvent" and name[-8:] == "Callback": | |
163 | continue | |
164 | if (name.startswith("virConnectStoragePoolEvent") and | |
165 | name.endswith("Callback")): | |
166 | continue | |
167 | if (name.startswith("virConnectNodeDeviceEvent") and | |
168 | name.endswith("Callback")): | |
169 | continue | |
170 | if (name.startswith("virConnectSecretEvent") and | |
171 | name.endswith("Callback")): | |
172 | continue | |
173 | ||
174 | # virEvent APIs go into main 'libvirt' namespace not any class | |
175 | if name[0:8] == "virEvent": | |
176 | if name[-4:] == "Func": | |
177 | continue | |
178 | basicklassmap[name] = ("libvirt", name, cname) | |
179 | else: | |
180 | found = False | |
181 | # To start with map APIs to classes based on the | |
182 | # naming prefix. Mistakes will be fixed in next | |
183 | # loop | |
184 | for klassname in gottypes: | |
185 | klen = len(klassname) | |
186 | if name[0:klen] == klassname: | |
187 | found = True | |
188 | if name not in basicklassmap: | |
189 | basicklassmap[name] = (klassname, name[klen:], cname) | |
190 | elif len(basicklassmap[name]) < klen: | |
191 | basicklassmap[name] = (klassname, name[klen:], cname) | |
192 | ||
193 | # Anything which can't map to a class goes into the | |
194 | # global namespaces | |
195 | if not found: | |
196 | basicklassmap[name] = ("libvirt", name[3:], cname) | |
197 | ||
198 | return basicklassmap | |
199 | ||
200 | ||
201 | # Deal with oh so many special cases in C -> python mapping | |
202 | def fixup_class_method_mapping(basicklassmap): | |
203 | finalklassmap = {} # type: Dict[str, Tuple[str, str, str]] | |
204 | ||
205 | for name, (klass, func, cname) in sorted(basicklassmap.items()): | |
206 | # The object lifecycle APIs are irrelevant since they're | |
207 | # used inside the object constructors/destructors. | |
208 | if func in ["Ref", "Free", "New", "GetConnect", "GetDomain", "GetNetwork"]: | |
209 | if klass == "virStream" and func == "New": | |
210 | klass = "virConnect" | |
211 | func = "NewStream" | |
212 | else: | |
213 | continue | |
214 | ||
215 | # All the error handling methods need special handling | |
216 | if klass == "libvirt": | |
217 | if func in ["CopyLastError", "DefaultErrorFunc", | |
218 | "ErrorFunc", "FreeError", | |
219 | "SaveLastError", "ResetError"]: | |
220 | continue | |
221 | elif func in ["GetLastError", "GetLastErrorMessage", | |
222 | "GetLastErrorCode", "GetLastErrorDomain", | |
223 | "ResetLastError", "Initialize"]: | |
224 | func = "vir" + func | |
225 | elif func == "SetErrorFunc": | |
226 | func = "RegisterErrorHandler" | |
227 | elif klass == "virConnect": | |
228 | if func in ["CopyLastError", "SetErrorFunc"]: | |
229 | continue | |
230 | elif func in ["GetLastError", "ResetLastError"]: | |
231 | func = "virConn" + func | |
232 | ||
233 | # Remove 'Get' prefix from most APIs, except those in virConnect | |
234 | # and virDomainSnapshot namespaces which stupidly used a different | |
235 | # convention which we now can't fix without breaking API | |
236 | if func[0:3] == "Get" and klass not in ["virConnect", "virDomainCheckpoint", "virDomainSnapshot", "libvirt"]: | |
237 | if func not in ["GetCPUStats", "GetTime"]: | |
238 | func = func[3:] | |
239 | ||
240 | # The object creation and lookup APIs all have to get re-mapped | |
241 | # into the parent class | |
242 | if func in ["CreateXML", "CreateLinux", "CreateXMLWithFiles", | |
243 | "DefineXML", "CreateXMLFrom", "LookupByUUID", | |
244 | "LookupByUUIDString", "LookupByVolume" "LookupByName", | |
245 | "LookupByID", "LookupByName", "LookupByKey", "LookupByPath", | |
246 | "LookupByMACString", "LookupByUsage", "LookupByVolume", | |
247 | "LookupByTargetPath", "LookupSCSIHostByWWN", "LookupByPortDev", | |
248 | "Restore", "RestoreFlags", | |
249 | "SaveImageDefineXML", "SaveImageGetXMLDesc", "DefineXMLFlags", | |
250 | "CreateXMLFlags"]: | |
251 | if klass != "virDomain": | |
252 | func = klass[3:] + func | |
253 | ||
254 | if klass in ["virDomainCheckpoint", "virDomainSnapshot"]: | |
255 | klass = "virDomain" | |
256 | func = func[6:] | |
257 | elif klass == "virStorageVol" and func in ["StorageVolCreateXMLFrom", "StorageVolCreateXML"]: | |
258 | klass = "virStoragePool" | |
259 | func = func[10:] | |
260 | elif klass == "virNetworkPort": | |
261 | klass = "virNetwork" | |
262 | func = func[7:] | |
263 | elif func == "StoragePoolLookupByVolume": | |
264 | klass = "virStorageVol" | |
265 | elif func == "StorageVolLookupByName": | |
266 | klass = "virStoragePool" | |
267 | else: | |
268 | klass = "virConnect" | |
269 | ||
270 | # The open methods get remapped to primary namespace | |
271 | if klass == "virConnect" and func in ["Open", "OpenAuth", "OpenReadOnly"]: | |
272 | klass = "libvirt" | |
273 | ||
274 | # These are inexplicably renamed in the python API | |
275 | if func == "ListDomains": | |
276 | func = "ListDomainsID" | |
277 | elif func == "ListAllNodeDevices": | |
278 | func = "ListAllDevices" | |
279 | elif func == "ListNodeDevices": | |
280 | func = "ListDevices" | |
281 | ||
282 | # The virInterfaceChangeXXXX APIs go into virConnect. Stupidly | |
283 | # they have lost their 'interface' prefix in names, but we can't | |
284 | # fix this name | |
285 | if func[0:6] == "Change": | |
286 | klass = "virConnect" | |
287 | ||
288 | # Need to special case the checkpoint and snapshot APIs | |
289 | if klass == "virDomainSnapshot" and func in ["Current", "ListNames", "Num"]: | |
290 | klass = "virDomain" | |
291 | func = "snapshot" + func | |
292 | ||
293 | # Names should start with lowercase letter... | |
294 | func = func[0:1].lower() + func[1:] | |
295 | if func[0:8] == "nWFilter": | |
296 | func = "nwfilter" + func[8:] | |
297 | if func[0:8] == "fSFreeze" or func[0:6] == "fSThaw" or func[0:6] == "fSInfo": | |
298 | func = "fs" + func[2:] | |
299 | if func[0:12] == "iOThreadInfo": | |
300 | func = "ioThreadInfo" | |
301 | ||
302 | if klass == "virNetwork": | |
303 | func = func.replace("dHCP", "DHCP") | |
304 | ||
305 | # ...except when they don't. More stupid naming | |
306 | # decisions we can't fix | |
307 | if func == "iD": | |
308 | func = "ID" | |
309 | if func == "uUID": | |
310 | func = "UUID" | |
311 | if func == "uUIDString": | |
312 | func = "UUIDString" | |
313 | if func == "oSType": | |
314 | func = "OSType" | |
315 | if func == "xMLDesc": | |
316 | func = "XMLDesc" | |
317 | if func == "mACString": | |
318 | func = "MACString" | |
319 | ||
320 | finalklassmap[name] = (klass, func, cname) | |
321 | ||
322 | return finalklassmap | |
323 | ||
324 | ||
325 | # Validate that every C API is mapped to a python API | |
326 | def validate_c_to_python_api_mappings(finalklassmap, gotfunctions): | |
327 | usedfunctions = set() # type: Set[str] | |
328 | for name, (klass, func, cname) in sorted(finalklassmap.items()): | |
329 | if func in gotfunctions[klass]: | |
330 | usedfunctions.add("%s.%s" % (klass, func)) | |
331 | else: | |
332 | raise Exception("%s -> %s.%s (C API not mapped to python)" % (name, klass, func)) | |
333 | return usedfunctions | |
334 | ||
335 | ||
336 | # Validate that every python API has a corresponding C API | |
337 | def validate_python_to_c_api_mappings(gotfunctions, usedfunctions): | |
338 | for klass in gotfunctions: | |
339 | if klass == "libvirtError": | |
340 | continue | |
341 | for func in sorted(gotfunctions[klass]): | |
342 | # These are pure python methods with no C APi | |
343 | if func in ["connect", "getConnect", "domain", "getDomain", | |
344 | "virEventInvokeFreeCallback", "network", | |
345 | "sparseRecvAll", "sparseSendAll"]: | |
346 | continue | |
347 | ||
348 | key = "%s.%s" % (klass, func) | |
349 | if key not in usedfunctions: | |
350 | raise Exception("%s.%s (Python API not mapped to C)" % (klass, func)) | |
351 | ||
352 | ||
353 | # Validate that all the low level C APIs have binding | |
354 | def validate_c_api_bindings_present(finalklassmap): | |
355 | for name, (klass, func, cname) in sorted(finalklassmap.items()): | |
356 | pyname = cname | |
357 | if pyname == "virSetErrorFunc": | |
358 | pyname = "virRegisterErrorHandler" | |
359 | elif pyname == "virConnectListDomains": | |
360 | pyname = "virConnectListDomainsID" | |
361 | ||
362 | # These exist in C and exist in python, but we've got | |
363 | # a pure-python impl so don't check them | |
364 | if name in ["virStreamRecvAll", "virStreamSendAll", | |
365 | "virStreamSparseRecvAll", "virStreamSparseSendAll"]: | |
366 | continue | |
367 | ||
368 | try: | |
369 | thing = getattr(libvirt.libvirtmod, pyname) | |
370 | except AttributeError: | |
371 | raise Exception("libvirt.libvirtmod.%s (C binding does not exist)" % pyname) | |
372 | ||
373 | # Historically python lxml is incompatible with any other | |
374 | # use of libxml2 in the same process. Merely importing | |
375 | # 'lxml.etree' will result in libvirt's use of libxml2 | |
376 | # triggering a SEGV: | |
377 | # | |
378 | # https://bugs.launchpad.net/lxml/+bug/1748019 | |
379 | # | |
380 | # per the last comment though, it was somewhat improved by | |
381 | # | |
382 | # https://github.com/lxml/lxml/commit/fa1d856cad369d0ac64323ddec14b02281491706 | |
383 | # | |
384 | # so if we have version >= 4.5.2, we are safe to import | |
385 | # lxml.etree for the purposes of unit tests at least | |
386 | def broken_lxml(): | |
387 | import lxml | |
388 | ||
389 | if not hasattr(lxml, "__version__"): | |
390 | return True | |
391 | ||
392 | digits = [int(d) for d in lxml.__version__.split(".")] | |
393 | ||
394 | # We have 3 digits in versions today, but be paranoid | |
395 | # for possible future changes. | |
396 | if len(digits) != 3: | |
397 | return False | |
398 | ||
399 | version = (digits[0] * 1000 * 1000) + (digits[1] * 1000) + digits[2] | |
400 | if version < 4005002: | |
401 | return True | |
402 | ||
403 | return False | |
404 | ||
405 | api_test_flag = unittest.skipUnless( | |
406 | os.environ.get('LIBVIRT_API_COVERAGE', False), | |
407 | "API coverage test is only for upstream maintainers", | |
408 | ) | |
409 | ||
410 | lxml_broken_flag = unittest.skipIf( | |
411 | broken_lxml(), | |
412 | "lxml version clashes with libxml usage from libvirt" | |
413 | ) | |
414 | ||
415 | @api_test_flag | |
416 | @lxml_broken_flag | |
417 | class LibvirtAPICoverage(unittest.TestCase): | |
418 | def test_libvirt_api(self): | |
419 | xml = get_libvirt_api_xml_path() | |
420 | ||
421 | import lxml.etree | |
422 | with open(xml, "r") as fp: | |
423 | tree = lxml.etree.parse(fp) | |
424 | ||
425 | wantfunctions, wantenums, enumvals = identify_functions_enums(tree) | |
426 | gotfunctions, gottypes = identify_class_methods(wantenums, enumvals) | |
427 | basicklassmap = basic_class_method_mapping(wantfunctions, gottypes) | |
428 | finalklassmap = fixup_class_method_mapping(basicklassmap) | |
429 | usedfunctions = validate_c_to_python_api_mappings(finalklassmap, gotfunctions) | |
430 | validate_python_to_c_api_mappings(gotfunctions, usedfunctions) | |
431 | validate_c_api_bindings_present(finalklassmap) |
0 | import unittest | |
1 | import libvirt | |
2 | ||
3 | ||
4 | class TestLibvirtDomainCheckpoint(unittest.TestCase): | |
5 | def setUp(self): | |
6 | self.conn = libvirt.open("test:///default") | |
7 | self.dom = self.conn.lookupByName("test") | |
8 | ||
9 | def tearDown(self): | |
10 | self.dom = None | |
11 | self.conn = None | |
12 | ||
13 | @unittest.skipUnless(hasattr(libvirt.virDomain, "checkpointCreateXML"), | |
14 | "checkpoints not supported in this libvirt") | |
15 | def testCheckpointCreate(self): | |
16 | cp = self.dom.checkpointCreateXML("<domaincheckpoint/>") | |
17 | cp.delete() |
0 | import unittest | |
1 | import libvirt | |
2 | ||
3 | ||
4 | class TestLibvirtDomainSnapshot(unittest.TestCase): | |
5 | def setUp(self): | |
6 | self.conn = libvirt.open("test:///default") | |
7 | self.dom = self.conn.lookupByName("test") | |
8 | ||
9 | def tearDown(self): | |
10 | self.dom = None | |
11 | self.conn = None | |
12 | ||
13 | def testSnapCreate(self): | |
14 | snap = self.dom.snapshotCreateXML("<domainsnapshot/>") | |
15 | snap.delete() |
0 | import unittest | |
1 | import libvirt | |
2 | ||
3 | ||
4 | class TestLibvirtInterface(unittest.TestCase): | |
5 | def setUp(self): | |
6 | self.conn = libvirt.open("test:///default") | |
7 | self.iface = self.conn.interfaceLookupByName("eth1") | |
8 | ||
9 | def tearDown(self): | |
10 | self.iface = None | |
11 | self.conn = None | |
12 | ||
13 | def testAttr(self): | |
14 | self.assertEqual(self.iface.name(), "eth1") |
0 | import unittest | |
1 | import libvirt | |
2 | ||
3 | ||
4 | class TestLibvirtNetwork(unittest.TestCase): | |
5 | def setUp(self): | |
6 | self.conn = libvirt.open("test:///default") | |
7 | self.net = self.conn.networkLookupByName("default") | |
8 | ||
9 | def tearDown(self): | |
10 | self.net = None | |
11 | self.conn = None | |
12 | ||
13 | def testAttr(self): | |
14 | self.assertEqual(self.net.name(), "default") |
0 | import unittest | |
1 | import libvirt | |
2 | ||
3 | ||
4 | class TestLibvirtNodeDev(unittest.TestCase): | |
5 | def setUp(self): | |
6 | self.conn = libvirt.open("test:///default") | |
7 | self.nodedev = self.conn.nodeDeviceLookupByName("computer") | |
8 | ||
9 | def tearDown(self): | |
10 | self.nodedev = None | |
11 | self.conn = None | |
12 | ||
13 | def testAttr(self): | |
14 | self.assertEqual(self.nodedev.name(), "computer") |
0 | import unittest | |
1 | import libvirt | |
2 | ||
3 | ||
4 | class TestLibvirtStorage(unittest.TestCase): | |
5 | def setUp(self): | |
6 | self.conn = libvirt.open("test:///default") | |
7 | self.pool = self.conn.storagePoolLookupByName("default-pool") | |
8 | ||
9 | def tearDown(self): | |
10 | self.pool = None | |
11 | self.conn = None | |
12 | ||
13 | def testAttr(self): | |
14 | self.assertEqual(self.pool.name(), "default-pool") | |
15 | ||
16 | def testVol(self): | |
17 | volxml = '''<volume type="file"> | |
18 | <name>raw.img</name> | |
19 | <allocation unit="M">10</allocation> | |
20 | <capacity unit="M">1000</capacity> | |
21 | </volume>''' | |
22 | ||
23 | vol = self.pool.createXML(volxml) |
29 | 29 | } |
30 | 30 | |
31 | 31 | PyObject * |
32 | libvirt_uintWrap(uint val) | |
32 | libvirt_uintWrap(unsigned int val) | |
33 | 33 | { |
34 | 34 | return PyLong_FromLong((long) val); |
35 | 35 | } |
188 | 188 | } PyvirVoidPtr_Object; |
189 | 189 | |
190 | 190 | PyObject * libvirt_intWrap(int val); |
191 | PyObject * libvirt_uintWrap(uint val); | |
191 | PyObject * libvirt_uintWrap(unsigned int val); | |
192 | 192 | PyObject * libvirt_longWrap(long val); |
193 | 193 | PyObject * libvirt_ulongWrap(unsigned long val); |
194 | 194 | PyObject * libvirt_longlongWrap(long long val); |