Codebase list libvirt-python / 5cf8728
New upstream version 9.0.0 Guido Günther 1 year, 3 months ago
74 changed file(s) with 4496 addition(s) and 985 deletion(s). Raw diff Collapse all Expand all
0 --recurse
1 --exclude=*.orig
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>
1111 Adam Litke <agl@us.ibm.com>
1212 Alex Jia <ajia@redhat.com>
1313 Andrea Bolognani <abologna@redhat.com>
14 Bastian Germann <bage@linutronix.de>
1415 Beraldo Leal <bleal@redhat.com>
1516 Boris Fiuczynski <fiuczy@linux.vnet.ibm.com>
1617 Brian Rak <brak@gameservers.com>
18 Chris Gunn <chrisgun@microsoft.com>
1719 Chris Lalancette <clalance@redhat.com>
1820 Claudio Bley <cbley@av-test.de>
1921 Cole Robinson <crobinso@redhat.com>
2931 Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
3032 Eric Blake <eblake@redhat.com>
3133 Erik Skultety <eskultet@redhat.com>
34 Erik Skultety <eskultety@ridgehead.home.lan>
3235 Federico Simoncelli <fsimonce@redhat.com>
3336 Giuseppe Scrivano <gscrivan@redhat.com>
3437 Guan Qiang <hzguanqiang@corp.netease.com>
7275 Peng Hao <peng.hao2@zte.com.cn>
7376 Peter Krempa <pkrempa@redhat.com>
7477 Philipp Hahn <hahn@univention.de>
78 Pino Toscano <ptoscano@redhat.com>
7579 Prabodh Agarwal <prabodh1194@users.noreply.github.com>
7680 Pradipta Kr. Banerjee <pradipta.banerjee@gmail.com>
7781 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
0793 2022-01-05 Daniel P. Berrangé <berrange@redhat.com>
1794
2795 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
00 # file GENERATED by distutils, do NOT edit
11 AUTHORS
2 CONTRIBUTING.rst
23 COPYING
34 COPYING.LESSER
45 ChangeLog
6 HACKING
57 MANIFEST
68 MANIFEST.in
79 README
2527 libvirt-utils.c
2628 libvirt-utils.h
2729 libvirtaio.py
30 requirements-test.txt
2831 sanitytest.py
2932 setup.py
3033 tox.ini
3134 typewrappers.c
3235 typewrappers.h
36 examples/README
3337 examples/consolecallback.py
38 examples/dhcpleases.py
3439 examples/dominfo.py
3540 examples/domipaddrs.py
3641 examples/domrestore.py
4550 examples/guest-vcpus/guest-vcpu.py
4651 tests/test_conn.py
4752 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
00 include AUTHORS
11 include COPYING
22 include COPYING.LESSER
3 include CONTRIBUTING.rst
4 include HACKING
35 include ChangeLog
6 include examples/README
47 include examples/consolecallback.py
8 include examples/dhcpleases.py
59 include examples/domipaddrs.py
610 include examples/dominfo.py
711 include examples/domrestore.py
3741 include MANIFEST
3842 include MANIFEST.in
3943 include README
44 include requirements-test.txt
4045 include sanitytest.py
4146 include setup.py
4247 include tests/test_conn.py
4348 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
4455 include tox.ini
4556 include typewrappers.c
4657 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
11 Name: libvirt-python
2 Version: 8.0.0
2 Version: 9.0.0
33 Summary: The libvirt virtualization API python binding
44 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
77 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
138 Classifier: Development Status :: 5 - Production/Stable
149 Classifier: Intended Audience :: Developers
1510 Classifier: License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)
1914 Classifier: Programming Language :: Python :: 3.6
2015 Classifier: Programming Language :: Python :: 3.7
2116 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 ))
437437 def virEventLoopPollStart() -> None:
438438 global eventLoopThread
439439 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)
442443 eventLoopThread.start()
443444
444445
448449 import asyncio
449450 loop = asyncio.new_event_loop()
450451 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)
453456 eventLoopThread.start()
454457
455458
456459 def virEventLoopNativeStart() -> None:
457460 global eventLoopThread
458461 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)
461465 eventLoopThread.start()
462466
463467
1515 EnumType = Dict[str, EnumValue]
1616
1717 functions = {} # type: Dict[str, FunctionType]
18 lxc_functions = {} # type: Dict[str, FunctionType]
19 qemu_functions = {} # type: Dict[str, FunctionType]
2018 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 } }
2319 event_ids = [] # type: List[str]
2420 params = [] # type: List[Tuple[str, str]] # [ (paramName, paramValue)... ]
2521
10197 self.function_return_field = attrs.get('field', '')
10298 elif tag == 'enum':
10399 # 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:
105105 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'])
110106 elif tag == "macro":
111107 if "string" in attrs:
112108 params.append((attrs['name'], attrs['string']))
118114 # functions come from source files, hence 'virerror.c'
119115 if self.function:
120116 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):
123128 function(self.function, self.function_descr,
124129 self.function_return, self.function_args,
125130 self.function_file, self.function_module,
126131 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)
152132 self.in_function = False
153133 elif tag == 'arg':
154134 if self.in_function:
176156 if name == "virConnectListDomains":
177157 name = "virConnectListDomainsID"
178158 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)
191159
192160
193161 def enum(type: str, name: str, value: EnumValue) -> None:
212180 value = 1
213181 elif value == 'VIR_DOMAIN_AFFECT_CONFIG':
214182 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':
228184 value = -2
229185 elif value == 'VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_DEFAULT':
230186 value = -1
231187 elif value == 'VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_NOWAIT':
232188 value = 0
233 if onlyOverrides and name not in qemu_enums[type]:
189
190 if onlyOverrides and name not in enums[type]:
234191 return
235 qemu_enums[type][name] = value
192 enums[type][name] = value
236193
237194
238195 #######################################################################
241198 # be exposed as-is on the Python interface
242199 #
243200 #######################################################################
244
245 functions_skipped = {
246 "virConnectListDomains",
247 }
248 lxc_functions_skipped = set() # type: Set[str]
249 qemu_functions_skipped = set() # type: Set[str]
250201
251202 skipped_types = {
252203 # 'int *': "usually a return type",
341292 'const virDomainSnapshot *': ('O', "virDomainSnapshot", "virDomainSnapshotPtr", "virDomainSnapshotPtr"),
342293 } # type: Dict[str, Tuple[str, str, str, str]]
343294
344
345 unknown_types = defaultdict(list) # type: Dict[str, List[str]]
346295
347296 #######################################################################
348297 #
481430 'virDomainAuthorizedSSHKeysSet',
482431 'virDomainGetMessages',
483432 'virNodeDeviceGetAutostart',
484 }
485
486 lxc_skip_impl = {
433 'virDomainSaveParams',
434 'virDomainRestoreParams',
435
487436 'virDomainLxcOpenNamespace',
488 }
489
490 qemu_skip_impl = {
437
491438 'virDomainQemuMonitorCommand',
492439 'virDomainQemuAgentCommand',
493440 }
536483 'virConnectListAllSecrets', # overridden in virConnect.py
537484 'virConnectGetAllDomainStats', # overridden in virConnect.py
538485 'virDomainListGetStats', # overridden in virConnect.py
486 'virDomainFDAssociate', # overridden in virDomain.py
539487
540488 'virStreamRecvAll', # Pure python libvirt-override-virStream.py
541489 'virStreamSendAll', # Pure python libvirt-override-virStream.py
615563 'virDomainFSInfoFree', # only useful in C, python code uses list
616564 'virDomainIOThreadInfoFree', # only useful in C, python code uses list
617565 'virDomainInterfaceFree', # only useful in C, python code uses list
618 }
619
620 lxc_skip_function = {
566
621567 "virDomainLxcEnterNamespace",
622568 "virDomainLxcEnterSecurityLabel",
623 }
624 qemu_skip_function = {
569
625570 # "virDomainQemuAttach",
626571 'virConnectDomainQemuMonitorEventRegister', # overridden in -qemu.py
627572 'virConnectDomainQemuMonitorEventDeregister', # overridden in -qemu.py
573 'virDomainQemuMonitorCommandWithFiles', # overridden in -qemu.py
628574 }
629575
630576 # Generate C code, but skip python impl
633579 # be exposed in bindings
634580 }
635581
636 lxc_function_skip_python_impl = set() # type: Set[str]
637 qemu_function_skip_python_impl = set() # type: Set[str]
638
639582 function_skip_index_one = {
640583 "virDomainRevertToSnapshot",
641584 }
642585
643586
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:
645684 """
646 :returns: -1 on failure, 0 on skip, 1 on success.
685 :returns: True if generated, False if skipped
647686 """
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
669691
670692 c_call = ""
671693 format = ""
699721 c_call += ", "
700722 c_call += "%s" % (a_name)
701723 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))
706725 if format:
707726 format += ":%s" % (name)
708727
732751 ret_convert += " free(c_retval);\n"
733752 ret_convert += " return py_retval;\n"
734753 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))
739755
740756 if cond:
741757 include.write("#if %s\n" % cond)
743759 output.write("#if %s\n" % cond)
744760
745761 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))
758765
759766 if file == "python":
760767 # Those have been manually generated
762769 include.write("#endif\n")
763770 export.write("#endif\n")
764771 output.write("#endif\n")
765 return 1
772 return True
766773 if file == "python_accessor" and r_type != "void" and not r_field:
767774 # Those have been manually generated
768775 if cond:
769776 include.write("#endif\n")
770777 export.write("#endif\n")
771778 output.write("#endif\n")
772 return 1
779 return True
773780
774781 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))
781783 output.write(" PyObject *args")
782784 if format == "":
783785 output.write(" ATTRIBUTE_UNUSED")
805807 export.write("#endif /* %s */\n" % cond)
806808 output.write("#endif /* %s */\n" % cond)
807809
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
818811
819812
820813 def print_c_pointer(classname: str, output: IO[str], export: IO[str], include: IO[str]) -> None:
839832 (classname, classname))
840833
841834
842 def buildStubs(module: str, api_xml: str) -> int:
835 def load_apis(module: str, api_xml: str):
843836 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
858837
859838 try:
860839 onlyOverrides = False
864843 print(api_xml, ":", msg)
865844 sys.exit(1)
866845
867 n = len(funcs)
846 n = len(functions)
868847 if not quiet:
869848 print("Found %d functions in %s" % ((n), api_xml))
870849
881860 if not quiet:
882861 # XXX: This is not right, same function already in @functions
883862 # 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
885869 nb_wrap = 0
886 failed = 0
887 skipped = 0
888 funcs_failed = [] # type: List[str]
889870
890871 header_file = "build/%s.h" % module
891872 export_file = "build/%s-export.c" % module
904885 wrapper.write("#include \"typewrappers.h\"\n")
905886 wrapper.write("#include \"build/%s.h\"\n\n" % (module,))
906887
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):
919890 nb_wrap += 1
920891
921892 if module == "libvirt":
933904
934905 if not quiet:
935906 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
950907
951908
952909 #######################################################################
12811238
12821239
12831240 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]:
12911242 return
1292 val = funcs[name][0]
1243 val = functions[name][0]
12931244 val = val.replace("NULL", "None")
12941245 sep = '\n%s' % (indent,)
12951246 output.write('%s"""%s """\n' % (indent, sep.join(val.splitlines())))
12961247
12971248
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)
13021262
13031263 for tinfo in classes_type.values():
13041264 function_classes[tinfo[2]] = []
13291289 ctypes_processed.add(type)
13301290
13311291 for name, (desc, ret, args, file, mod, cond) in functions.items():
1292 if skip_py_impl(name):
1293 continue
1294
13321295 for type in ctypes:
13331296 classe = classes_type[type][2]
13341297
13481311 info = (0, func, name, ret, args, file, mod)
13491312 function_classes['None'].append(info)
13501313
1351 classes_file = "build/%s.py" % module
1314 classes_file = "build/%s.py" % package
13521315 extra_file = "%s-override.py" % module
13531316 extra = None
13541317
13671330 classes.write("#\n")
13681331 classes.write("# WARNING WARNING WARNING WARNING\n")
13691332 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
13701346 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)
13711350 classes.writelines(extra.readlines())
13721351 classes.write("#\n")
13731352 classes.write("# WARNING WARNING WARNING WARNING\n")
13741353 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)
13761355 classes.write("#\n")
13771356 classes.write("# WARNING WARNING WARNING WARNING\n")
13781357 if extra:
14121391 classes.write(" ret = ")
14131392 else:
14141393 classes.write(" ")
1415 classes.write("libvirtmod.%s(" % name)
1394 classes.write("%s.%s(" % (pymod, name))
14161395 for n, (a_name, a_type, a_info) in enumerate(args):
14171396 if n != 0:
14181397 classes.write(", ")
14651444
14661445 classes.write("\n")
14671446
1468 for classname in classes_list:
1447 modclasses = []
1448 if module == "libvirt":
1449 modclasses = classes_list
1450 for classname in modclasses:
14691451 PARENTS = {
14701452 "virConnect": "self._conn",
14711453 "virDomain": "self._dom",
15061488 if classname in classes_destructors:
15071489 classes.write(" def __del__(self):\n")
15081490 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]))
15111493 classes.write(" self._o = None\n\n")
15121494 destruct = classes_destructors[classname]
15131495
15261508
15271509 classes.write(" def c_pointer(self):\n")
15281510 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))
15311513
15321514 flist = function_classes[classname]
15331515 oldfile = ""
15721554 classes.write(" ret = ")
15731555 else:
15741556 classes.write(" ")
1575 classes.write("libvirtmod.%s(" % name)
1557 classes.write("%s.%s(" % (pymod, name))
15761558 for n, (a_name, a_type, a_info) in enumerate(args):
15771559 if n != 0:
15781560 classes.write(", ")
16441626
16451627 classes.write("\n")
16461628 # 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")
16491632 classes.write(" #\n")
16501633 classes.write(" # %s methods from %s.py (hand coded)\n" % (classname, classname))
16511634 classes.write(" #\n")
16581641
16591642 def shouldSkip(lines: List[str]) -> bool:
16601643 for line in lines:
1661 offset = line.find("libvirtmod.")
1644 offset = line.find(pymod + ".")
16621645 if offset != -1:
16631646 func = line[offset + 11:]
16641647 offset = func.find("(")
16651648 func = func[0:offset]
1666 if func not in functions_skipped:
1649 if not skip_c_impl(func) and func != "virConnectListDomains":
16671650 return True
16681651 return False
16691652
16901673 classes.writelines(cached)
16911674 classes.write("\n")
16921675 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")
16951731
16961732 #
16971733 # Generate enum constants
17271763 classes.write("%s = %s\n" % (name, value))
17281764 classes.write("\n")
17291765
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))
17331770
17341771 classes.close()
17351772
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)
19461781
19471782 quiet = False
19481783 if not os.path.exists("build"):
19491784 os.mkdir("build")
19501785
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])
19631794
19641795 sys.exit(0)
851851 <arg name='params' type='virTypedParameterPtr' info='pointer to launch security state objects'/>
852852 <arg name='flags' type='unsigned int' info='currently used, set to 0.'/>
853853 </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&apos;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&apos;ed set of virDomainSaveRestoreFlags'/>
867 </function>
854868 </symbols>
855869 </api>
7979 if ret == -1:
8080 raise libvirtError('virDomainSetTime() failed')
8181 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
16941694 { VIR_DOMAIN_IOTHREAD_POLL_MAX_NS, VIR_TYPED_PARAM_ULLONG },
16951695 { VIR_DOMAIN_IOTHREAD_POLL_GROW, VIR_TYPED_PARAM_UINT },
16961696 { 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) */
16971701 };
16981702
16991703 static PyObject *
79217925 buf[ret > -1 ? ret : 0] = '\0';
79227926 DEBUG("StreamRecv ret=%d strlen=%d\n", ret, (int) strlen(buf));
79237927
7924 if (ret == -2)
7928 if (ret == -2) {
7929 VIR_FREE(buf);
79257930 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 }
79287936 rv = libvirt_charPtrSizeWrap((char *) buf, (Py_ssize_t) ret);
79297937 VIR_FREE(buf);
79307938 return rv;
1069410702 return libvirt_intWrap(c_retval);
1069510703 }
1069610704 #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, &params, &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, &params, &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
1069710843
1069810844 /************************************************************************
1069910845 * *
1097211118 #if LIBVIR_CHECK_VERSION(8, 0, 0)
1097311119 {(char *) "virDomainSetLaunchSecurityState", libvirt_virDomainSetLaunchSecurityState, METH_VARARGS, NULL},
1097411120 #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) */
1097511128 {NULL, NULL, 0, NULL}
1097611129 };
1097711130
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
130
141 from types import TracebackType
152 from typing import Any, Callable, Dict, List, Optional, overload, Tuple, Type, TypeVar, Union
1313
1414 Summary: The libvirt virtualization API python3 binding
1515 Name: libvirt-python
16 Version: 8.0.0
16 Version: 9.0.0
1717 Release: 1%{?dist}
1818 Source0: https://libvirt.org/sources/python/%{name}-%{version}.tar.gz
1919 Url: https://libvirt.org
2222 BuildRequires: python3-devel
2323 BuildRequires: python3-pytest
2424 BuildRequires: python3-lxml
25 BuildRequires: python3-setuptools
2526 BuildRequires: gcc
2627
2728 # 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
1919 #include "typewrappers.h"
2020 #include "libvirt-utils.h"
2121 #include "build/libvirt-qemu.h"
22 #ifndef __CYGWIN__
23 # include <fcntl.h>
24 #endif
2225
2326 #ifndef __CYGWIN__
2427 extern PyObject *PyInit_libvirtmod_qemu(void);
323326 return py_retval;
324327 }
325328 #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) */
326441
327442 /************************************************************************
328443 * *
339454 {(char *) "virConnectDomainQemuMonitorEventRegister", libvirt_qemu_virConnectDomainQemuMonitorEventRegister, METH_VARARGS, NULL},
340455 {(char *) "virConnectDomainQemuMonitorEventDeregister", libvirt_qemu_virConnectDomainQemuMonitorEventDeregister, METH_VARARGS, NULL},
341456 #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) */
342460 {NULL, NULL, 0, NULL}
343461 };
344462
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
21
32
43 def _dispatchQemuMonitorEventCallback(conn: libvirt.virConnect, dom: libvirt.virDomain, event: str, seconds: int, micros: int, details: str, cbData: Dict[str, Any]) -> int:
3736 raise libvirt.libvirtError('virConnectDomainQemuMonitorEventRegister() failed')
3837 conn.qemuMonitorEventCallbackID[ret] = opaque # type: ignore
3938 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
407407 type = VIR_TYPED_PARAM_BOOLEAN;
408408 } else if (PyLong_Check(value)) {
409409 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()) {
411411 type = VIR_TYPED_PARAM_LLONG;
412 else
412 PyErr_Clear();
413 } else {
413414 type = VIR_TYPED_PARAM_ULLONG;
415 }
414416 } else if (PyFloat_Check(value)) {
415417 type = VIR_TYPED_PARAM_DOUBLE;
416418 }
2020
2121 Register the implementation of default loop:
2222
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())
2544
2645 .. seealso::
2746 https://libvirt.org/html/libvirt-libvirt-event.html
4463 'virEventAsyncIOImpl',
4564 'virEventRegisterAsyncIOImpl',
4665 ]
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")
5566
5667
5768 class Callback(object):
218229 return '<{} iden={} timeout={}>'.format(
219230 self.__class__.__name__, self.iden, self.timeout)
220231
221 @asyncio.coroutine
222 def _timer(self) -> Generator[Any, None, None]:
232 async def _timer(self) -> Generator[Any, None, None]:
223233 '''An actual timer running on the event loop.
224234
225235 This is a coroutine.
229239 if self.timeout > 0:
230240 timeout = self.timeout * 1e-3
231241 self.impl.log.debug('sleeping %r', timeout)
232 yield from asyncio.sleep(timeout)
242 await asyncio.sleep(timeout)
233243 else:
234244 # scheduling timeout for next loop iteration
235 yield
245 await asyncio.sleep(0)
236246
237247 except asyncio.CancelledError:
238248 self.impl.log.debug('timer %d cancelled', self.iden)
247257
248258 if self.timeout >= 0 and self._task is None:
249259 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)
252262
253263 elif self.timeout < 0 and self._task is not None:
254264 self.impl.log.debug('timer %r stop', self.iden)
279289 self.descriptors = DescriptorDict(self)
280290 self.log = logging.getLogger(self.__class__.__name__)
281291
292 self._pending = 0
293 # Transient asyncio.Event instance dynamically created
294 # and destroyed by drain()
282295 # 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
286297
287298 def __repr__(self) -> str:
288299 return '<{} callbacks={} descriptors={}>'.format(
291302 def _pending_inc(self) -> None:
292303 '''Increase the count of pending affairs. Do not use directly.'''
293304 self._pending += 1
294 self._finished.clear()
305 if self._finished is not None:
306 self._finished.clear()
295307
296308 def _pending_dec(self) -> None:
297309 '''Decrease the count of pending affairs. Do not use directly.'''
298310 assert self._pending > 0
299311 self._pending -= 1
300 if self._pending == 0:
312 if self._pending == 0 and self._finished is not None:
301313 self._finished.set()
302314
303315 def register(self) -> "virEventAsyncIOImpl":
311323
312324 def schedule_ff_callback(self, iden: int, opaque: _T) -> None:
313325 '''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:
318329 '''Directly free the opaque object
319330
320331 This is a coroutine.
323334 libvirt.virEventInvokeFreeCallback(opaque)
324335 self._pending_dec()
325336
326 @asyncio.coroutine
327 def drain(self) -> Generator[Any, None, None]:
337 async def drain(self) -> None:
328338 '''Wait for the implementation to become idle.
329339
330340 This is a coroutine.
331341 '''
332342 self.log.debug('drain()')
333343 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
335349 self.log.debug('drain ended')
336350
337351 def is_idle(self) -> bool:
+0
-384
sanitytest.py less more
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 [egg_info]
1 tag_build =
2 tag_date = 0
3
00 #!/usr/bin/env python3
11
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
128 import sys
139 import os
1410 import os.path
1511 import re
1612 import shutil
13 import subprocess
1714 import time
1815
1916 if sys.version_info < (3, 5):
2825 if not os.path.exists("build"):
2926 os.mkdir("build")
3027
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()
4140
4241 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"])
4746
4847 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:
5352 return True
54 except DistutilsExecError:
55 return False
53 return False
5654
5755 def get_pkgconfig_data(args, mod, required=True):
5856 """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))
6058
6159 line = f.readline()
6260 if line is not None:
8987 Determine which modules we are actually building, and all their
9088 required config
9189 """
92 if get_pkgcfg(do_fail=False) is None:
93 return [], []
94
9590 c_modules = []
9691 py_modules = []
9792 ldflags = get_pkgconfig_data(["--libs-only-L"], "libvirt", False).split()
109104
110105 moduleqemu = Extension('libvirtmod_qemu',
111106 sources = ['libvirt-qemu-override.c', 'build/libvirt-qemu.c', 'typewrappers.c', 'libvirt-utils.c'],
112 libraries = [ "virt-qemu" ],
107 libraries = [ "virt-qemu", "virt" ],
113108 include_dirs = [ "." ])
114109 moduleqemu.extra_compile_args.extend(cflags)
115110 moduleqemu.extra_link_args.extend(ldflags)
120115 if have_libvirt_lxc():
121116 modulelxc = Extension('libvirtmod_lxc',
122117 sources = ['libvirt-lxc-override.c', 'build/libvirt-lxc.c', 'typewrappers.c', 'libvirt-utils.c'],
123 libraries = [ "virt-lxc" ],
118 libraries = [ "virt-lxc", "virt" ],
124119 include_dirs = [ "." ])
125120 modulelxc.extra_compile_args.extend(cflags)
126121 modulelxc.extra_link_args.extend(ldflags)
137132 # Custom commands #
138133 ###################
139134
140 class my_build(build):
135 class my_build_ext(build_ext):
141136
142137 def run(self):
143138 check_minimum_libvirt_version()
144139 apis = get_api_xml_files()
145140
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"])
148143 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"])
150158 shutil.copy('libvirtaio.py', 'build')
151159
152 build.run(self)
160 build_py.run(self)
153161
154162 class my_sdist(sdist):
155163 user_options = sdist.user_options
232240 else:
233241 sdist.run(self)
234242
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
255243 class my_test(Command):
256244 user_options = [
257245 ('build-base=', 'b',
259247 ('build-platlib=', None,
260248 "build directory for platform-specific distributions"),
261249 ('plat-name=', 'p',
262 "platform name to build for, if supported "
263 "(default: %s)" % get_platform()),
250 "platform name to build for, if supported "),
264251 ]
265252
266253 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]
267275
268276 def initialize_options(self):
269277 self.build_base = 'build'
271279 self.plat_name = None
272280
273281 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
284282 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()
287284
288285 def find_pytest_path(self):
289286 binaries = [
295292 ]
296293
297294 for binary in binaries:
298 path = distutils.spawn.find_executable(binary)
295 path = shutil.which(binary)
299296 if path is not None:
300297 return path
301298
305302 """
306303 Run test suite
307304 """
308
309 apis = get_api_xml_files()
310305
311306 if "PYTHONPATH" in os.environ:
312307 os.environ["PYTHONPATH"] = self.build_platlib + ":" + os.environ["PYTHONPATH"]
313308 else:
314309 os.environ["PYTHONPATH"] = self.build_platlib
315310
316 if "LIBVIRT_API_COVERAGE" in os.environ:
317 self.spawn([sys.executable, "sanitytest.py", self.build_platlib, apis[0]])
318311 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):
326326 if os.path.exists("build"):
327 remove_tree("build")
327 shutil.rmtree("build", ignore_errors=True)
328328
329329
330330 ##################
334334 _c_modules, _py_modules = get_module_lists()
335335
336336 setup(name = 'libvirt-python',
337 version = '8.0.0',
337 version = '9.0.0',
338338 url = 'http://www.libvirt.org',
339339 maintainer = 'Libvirt Maintainers',
340340 maintainer_email = 'libvir-list@redhat.com',
351351 '': 'build'
352352 },
353353 cmdclass = {
354 'build': my_build,
354 'build_ext': my_build_ext,
355 'build_py': my_build_py,
355356 'clean': my_clean,
356357 'sdist': my_sdist,
357 'rpm': my_rpm,
358358 'test': my_test
359359 },
360360 classifiers = [
367367 "Programming Language :: Python :: 3.6",
368368 "Programming Language :: Python :: 3.7",
369369 "Programming Language :: Python :: 3.8",
370 "Programming Language :: Python :: 3.9",
371 "Programming Language :: Python :: 3.10",
370372 ]
371373 )
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)
2929 }
3030
3131 PyObject *
32 libvirt_uintWrap(uint val)
32 libvirt_uintWrap(unsigned int val)
3333 {
3434 return PyLong_FromLong((long) val);
3535 }
188188 } PyvirVoidPtr_Object;
189189
190190 PyObject * libvirt_intWrap(int val);
191 PyObject * libvirt_uintWrap(uint val);
191 PyObject * libvirt_uintWrap(unsigned int val);
192192 PyObject * libvirt_longWrap(long val);
193193 PyObject * libvirt_ulongWrap(unsigned long val);
194194 PyObject * libvirt_longlongWrap(long long val);