From 13326974610b3bb38672b87f37c7de2934c69204 Mon Sep 17 00:00:00 2001 From: ge Date: Thu, 23 Nov 2023 02:35:32 +0300 Subject: [PATCH] various improvements --- packaging/build/compute-0.1.0.dev1.tar.gz | Bin 20824 -> 0 bytes .../compute-0.1.0.dev1.dist-info/METADATA | 81 -- .../build/compute-0.1.0.dev1.dist-info/RECORD | 23 - .../build/compute-0.1.0.dev1.dist-info/WHEEL | 4 - .../entry_points.txt | 3 - .../cpython3_3.11/build/compute/__init__.py | 22 - .../cpython3_3.11/build/compute/__main__.py | 21 - .../build/compute/cli/__init__.py | 0 .../build/compute/cli/control.py | 501 ---------- .../cpython3_3.11/build/compute/common.py | 30 - .../cpython3_3.11/build/compute/exceptions.py | 80 -- .../build/compute/instance/__init__.py | 18 - .../build/compute/instance/guest_agent.py | 208 ---- .../build/compute/instance/instance.py | 675 ------------- .../build/compute/instance/schemas.py | 165 ---- .../cpython3_3.11/build/compute/session.py | 286 ------ .../build/compute/storage/__init__.py | 17 - .../build/compute/storage/pool.py | 124 --- .../build/compute/storage/volume.py | 138 --- .../build/compute/utils/__init__.py | 0 .../build/compute/utils/config_loader.py | 56 -- .../cpython3_3.11/build/compute/utils/ids.py | 33 - .../build/compute/utils/units.py | 54 -- .../compute-0.1.0.dev1-py3-none-any.whl | Bin 30693 -> 0 bytes .../.pybuild/cpython3_3.11/scripts/compute | 8 - packaging/build/compute-0.1.0.dev1/PKG-INFO | 81 -- packaging/build/compute-0.1.0.dev1/README.md | 65 -- .../compute-0.1.0.dev1/compute/__init__.py | 22 - .../compute-0.1.0.dev1/compute/__main__.py | 21 - .../compute/cli/__init__.py | 0 .../compute-0.1.0.dev1/compute/cli/control.py | 501 ---------- .../compute-0.1.0.dev1/compute/common.py | 30 - .../compute-0.1.0.dev1/compute/exceptions.py | 80 -- .../compute/instance/__init__.py | 18 - .../compute/instance/guest_agent.py | 208 ---- .../compute/instance/instance.py | 675 ------------- .../compute/instance/schemas.py | 165 ---- .../compute-0.1.0.dev1/compute/session.py | 286 ------ .../compute/storage/__init__.py | 17 - .../compute/storage/pool.py | 124 --- .../compute/storage/volume.py | 138 --- .../compute/utils/__init__.py | 0 .../compute/utils/config_loader.py | 56 -- .../compute-0.1.0.dev1/compute/utils/ids.py | 33 - .../compute-0.1.0.dev1/compute/utils/units.py | 54 -- .../dh_installchangelogs.dch.trimmed | 5 - .../compute-doc/installed-by-dh_installdocs | 0 .../compute/dh_installchangelogs.dch.trimmed | 5 - .../compute/installed-by-dh_installdocs | 1 - .../build/compute-0.1.0.dev1/debian/changelog | 5 - .../debian/compute-doc.debhelper.log | 1 - .../debian/compute-doc.substvars | 4 - .../debian/compute-doc/DEBIAN/control | 11 - .../debian/compute-doc/DEBIAN/md5sums | 40 - .../share/doc/compute-doc/changelog.Debian.gz | Bin 176 -> 0 bytes .../usr/share/doc/compute-doc/copyright | 32 - .../compute-doc/html/_sources/index.rst.txt | 16 - .../html/_sources/pyapi/exceptions.rst.txt | 5 - .../html/_sources/pyapi/index.rst.txt | 49 - .../pyapi/instance/guest_agent.rst.txt | 6 - .../_sources/pyapi/instance/index.rst.txt | 10 - .../_sources/pyapi/instance/instance.rst.txt | 6 - .../_sources/pyapi/instance/schemas.rst.txt | 5 - .../html/_sources/pyapi/session.rst.txt | 6 - .../html/_sources/pyapi/storage/index.rst.txt | 9 - .../html/_sources/pyapi/storage/pool.rst.txt | 6 - .../_sources/pyapi/storage/volume.rst.txt | 6 - .../html/_sources/pyapi/utils.rst.txt | 14 - .../_sphinx_javascript_frameworks_compat.js | 1 - .../compute-doc/html/_static/alabaster.css | 701 -------------- .../doc/compute-doc/html/_static/basic.css | 900 ------------------ .../doc/compute-doc/html/_static/custom.css | 1 - .../doc/compute-doc/html/_static/doctools.js | 1 - .../html/_static/documentation_options.js | 14 - .../doc/compute-doc/html/_static/file.png | Bin 286 -> 0 bytes .../_static/forkme_right_darkblue_121621.png | Bin 7791 -> 0 bytes .../doc/compute-doc/html/_static/jquery.js | 1 - .../compute-doc/html/_static/language_data.js | 1 - .../doc/compute-doc/html/_static/minus.png | Bin 90 -> 0 bytes .../doc/compute-doc/html/_static/plus.png | Bin 90 -> 0 bytes .../doc/compute-doc/html/_static/pygments.css | 83 -- .../compute-doc/html/_static/searchtools.js | 1 - .../html/_static/sphinx_highlight.js | 1 - .../compute-doc/html/_static/underscore.js | 1 - .../share/doc/compute-doc/html/genindex.html | 614 ------------ .../usr/share/doc/compute-doc/html/index.html | 122 --- .../share/doc/compute-doc/html/objects.inv | Bin 1463 -> 0 bytes .../doc/compute-doc/html/py-modindex.html | 165 ---- .../compute-doc/html/pyapi/exceptions.html | 183 ---- .../doc/compute-doc/html/pyapi/index.html | 342 ------- .../html/pyapi/instance/guest_agent.html | 266 ------ .../html/pyapi/instance/index.html | 120 --- .../html/pyapi/instance/instance.html | 490 ---------- .../html/pyapi/instance/schemas.html | 187 ---- .../doc/compute-doc/html/pyapi/session.html | 331 ------- .../compute-doc/html/pyapi/storage/index.html | 119 --- .../compute-doc/html/pyapi/storage/pool.html | 201 ---- .../html/pyapi/storage/volume.html | 210 ---- .../doc/compute-doc/html/pyapi/utils.html | 144 --- .../share/doc/compute-doc/html/search.html | 124 --- .../share/doc/compute-doc/html/searchindex.js | 1 - .../debian/compute.bash-completion | 93 -- .../debian/compute.debhelper.log | 1 - .../debian/compute.postinst.debhelper | 10 - .../debian/compute.prerm.debhelper | 10 - .../debian/compute.substvars | 3 - .../debian/compute/DEBIAN/control | 12 - .../debian/compute/DEBIAN/md5sums | 27 - .../debian/compute/DEBIAN/postinst | 12 - .../debian/compute/DEBIAN/prerm | 12 - .../debian/compute/usr/bin/compute | 8 - .../compute-0.1.0.dev1.dist-info/METADATA | 81 -- .../compute-0.1.0.dev1.dist-info/RECORD | 23 - .../compute-0.1.0.dev1.dist-info/WHEEL | 4 - .../entry_points.txt | 3 - .../python3/dist-packages/compute/__init__.py | 22 - .../python3/dist-packages/compute/__main__.py | 21 - .../dist-packages/compute/cli/__init__.py | 0 .../dist-packages/compute/cli/control.py | 501 ---------- .../python3/dist-packages/compute/common.py | 30 - .../dist-packages/compute/exceptions.py | 80 -- .../compute/instance/__init__.py | 18 - .../compute/instance/guest_agent.py | 208 ---- .../compute/instance/instance.py | 675 ------------- .../dist-packages/compute/instance/schemas.py | 165 ---- .../python3/dist-packages/compute/session.py | 286 ------ .../dist-packages/compute/storage/__init__.py | 17 - .../dist-packages/compute/storage/pool.py | 124 --- .../dist-packages/compute/storage/volume.py | 138 --- .../dist-packages/compute/utils/__init__.py | 0 .../compute/utils/config_loader.py | 56 -- .../dist-packages/compute/utils/ids.py | 33 - .../dist-packages/compute/utils/units.py | 54 -- .../share/bash-completion/completions/compute | 93 -- .../compute/usr/share/doc/compute/README.md | 65 -- .../usr/share/doc/compute/changelog.Debian.gz | Bin 176 -> 0 bytes .../compute/usr/share/doc/compute/copyright | 32 - .../build/compute-0.1.0.dev1/debian/control | 48 - .../build/compute-0.1.0.dev1/debian/copyright | 32 - .../debian/debhelper-build-stamp | 2 - .../build/compute-0.1.0.dev1/debian/docs | 1 - .../build/compute-0.1.0.dev1/debian/files | 3 - .../build/compute-0.1.0.dev1/debian/rules | 20 - .../compute-0.1.0.dev1/debian/source/format | 1 - .../compute-0.1.0.dev1/debian/source/options | 1 - .../debian/upstream/metadata.ex | 10 - .../build/compute-0.1.0.dev1/pyproject.toml | 61 -- .../build/compute-doc_0.1.0.dev1-1_all.deb | Bin 40424 -> 0 bytes .../build/compute_0.1.0.dev1-1.debian.tar.xz | Bin 2660 -> 0 bytes packaging/build/compute_0.1.0.dev1-1.dsc | 21 - packaging/build/compute_0.1.0.dev1-1_all.deb | Bin 21644 -> 0 bytes .../compute_0.1.0.dev1-1_amd64.buildinfo | 270 ------ .../build/compute_0.1.0.dev1-1_amd64.changes | 38 - .../build/compute_0.1.0.dev1.orig.tar.gz | Bin 20824 -> 0 bytes packaging/build/docs/Makefile | 20 - packaging/build/docs/make.bat | 35 - .../docs/source/_templates/versioning.html | 8 - packaging/build/docs/source/conf.py | 33 - packaging/build/docs/source/index.rst | 16 - .../build/docs/source/pyapi/exceptions.rst | 5 - packaging/build/docs/source/pyapi/index.rst | 49 - .../source/pyapi/instance/guest_agent.rst | 6 - .../docs/source/pyapi/instance/index.rst | 10 - .../docs/source/pyapi/instance/instance.rst | 6 - .../docs/source/pyapi/instance/schemas.rst | 5 - packaging/build/docs/source/pyapi/session.rst | 6 - .../build/docs/source/pyapi/storage/index.rst | 9 - .../build/docs/source/pyapi/storage/pool.rst | 6 - .../docs/source/pyapi/storage/volume.rst | 6 - packaging/build/docs/source/pyapi/utils.rst | 14 - 170 files changed, 14347 deletions(-) delete mode 100644 packaging/build/compute-0.1.0.dev1.tar.gz delete mode 100644 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute-0.1.0.dev1.dist-info/METADATA delete mode 100644 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute-0.1.0.dev1.dist-info/RECORD delete mode 100644 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute-0.1.0.dev1.dist-info/WHEEL delete mode 100644 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute-0.1.0.dev1.dist-info/entry_points.txt delete mode 100644 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/__init__.py delete mode 100644 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/__main__.py delete mode 100644 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/cli/__init__.py delete mode 100644 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/cli/control.py delete mode 100644 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/common.py delete mode 100644 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/exceptions.py delete mode 100644 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/instance/__init__.py delete mode 100644 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/instance/guest_agent.py delete mode 100644 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/instance/instance.py delete mode 100644 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/instance/schemas.py delete mode 100644 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/session.py delete mode 100644 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/storage/__init__.py delete mode 100644 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/storage/pool.py delete mode 100644 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/storage/volume.py delete mode 100644 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/utils/__init__.py delete mode 100644 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/utils/config_loader.py delete mode 100644 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/utils/ids.py delete mode 100644 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/utils/units.py delete mode 100644 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/compute-0.1.0.dev1-py3-none-any.whl delete mode 100755 packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/scripts/compute delete mode 100644 packaging/build/compute-0.1.0.dev1/PKG-INFO delete mode 100644 packaging/build/compute-0.1.0.dev1/README.md delete mode 100644 packaging/build/compute-0.1.0.dev1/compute/__init__.py delete mode 100644 packaging/build/compute-0.1.0.dev1/compute/__main__.py delete mode 100644 packaging/build/compute-0.1.0.dev1/compute/cli/__init__.py delete mode 100644 packaging/build/compute-0.1.0.dev1/compute/cli/control.py delete mode 100644 packaging/build/compute-0.1.0.dev1/compute/common.py delete mode 100644 packaging/build/compute-0.1.0.dev1/compute/exceptions.py delete mode 100644 packaging/build/compute-0.1.0.dev1/compute/instance/__init__.py delete mode 100644 packaging/build/compute-0.1.0.dev1/compute/instance/guest_agent.py delete mode 100644 packaging/build/compute-0.1.0.dev1/compute/instance/instance.py delete mode 100644 packaging/build/compute-0.1.0.dev1/compute/instance/schemas.py delete mode 100644 packaging/build/compute-0.1.0.dev1/compute/session.py delete mode 100644 packaging/build/compute-0.1.0.dev1/compute/storage/__init__.py delete mode 100644 packaging/build/compute-0.1.0.dev1/compute/storage/pool.py delete mode 100644 packaging/build/compute-0.1.0.dev1/compute/storage/volume.py delete mode 100644 packaging/build/compute-0.1.0.dev1/compute/utils/__init__.py delete mode 100644 packaging/build/compute-0.1.0.dev1/compute/utils/config_loader.py delete mode 100644 packaging/build/compute-0.1.0.dev1/compute/utils/ids.py delete mode 100644 packaging/build/compute-0.1.0.dev1/compute/utils/units.py delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/.debhelper/generated/compute-doc/dh_installchangelogs.dch.trimmed delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/.debhelper/generated/compute-doc/installed-by-dh_installdocs delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/.debhelper/generated/compute/dh_installchangelogs.dch.trimmed delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/.debhelper/generated/compute/installed-by-dh_installdocs delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/changelog delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc.debhelper.log delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc.substvars delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/DEBIAN/control delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/DEBIAN/md5sums delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/changelog.Debian.gz delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/copyright delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/index.rst.txt delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/exceptions.rst.txt delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/index.rst.txt delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/instance/guest_agent.rst.txt delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/instance/index.rst.txt delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/instance/instance.rst.txt delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/instance/schemas.rst.txt delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/session.rst.txt delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/storage/index.rst.txt delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/storage/pool.rst.txt delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/storage/volume.rst.txt delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/utils.rst.txt delete mode 120000 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/_sphinx_javascript_frameworks_compat.js delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/alabaster.css delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/basic.css delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/custom.css delete mode 120000 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/doctools.js delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/documentation_options.js delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/file.png delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/forkme_right_darkblue_121621.png delete mode 120000 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/jquery.js delete mode 120000 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/language_data.js delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/minus.png delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/plus.png delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/pygments.css delete mode 120000 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/searchtools.js delete mode 120000 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/sphinx_highlight.js delete mode 120000 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/underscore.js delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/genindex.html delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/index.html delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/objects.inv delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/py-modindex.html delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/exceptions.html delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/index.html delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/instance/guest_agent.html delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/instance/index.html delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/instance/instance.html delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/instance/schemas.html delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/session.html delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/storage/index.html delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/storage/pool.html delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/storage/volume.html delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/utils.html delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/search.html delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/searchindex.js delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute.bash-completion delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute.debhelper.log delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute.postinst.debhelper delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute.prerm.debhelper delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute.substvars delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/DEBIAN/control delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/DEBIAN/md5sums delete mode 100755 packaging/build/compute-0.1.0.dev1/debian/compute/DEBIAN/postinst delete mode 100755 packaging/build/compute-0.1.0.dev1/debian/compute/DEBIAN/prerm delete mode 100755 packaging/build/compute-0.1.0.dev1/debian/compute/usr/bin/compute delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute-0.1.0.dev1.dist-info/METADATA delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute-0.1.0.dev1.dist-info/RECORD delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute-0.1.0.dev1.dist-info/WHEEL delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute-0.1.0.dev1.dist-info/entry_points.txt delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/__init__.py delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/__main__.py delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/cli/__init__.py delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/cli/control.py delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/common.py delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/exceptions.py delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/instance/__init__.py delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/instance/guest_agent.py delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/instance/instance.py delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/instance/schemas.py delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/session.py delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/storage/__init__.py delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/storage/pool.py delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/storage/volume.py delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/utils/__init__.py delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/utils/config_loader.py delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/utils/ids.py delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/utils/units.py delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/share/bash-completion/completions/compute delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/share/doc/compute/README.md delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/share/doc/compute/changelog.Debian.gz delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/compute/usr/share/doc/compute/copyright delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/control delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/copyright delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/debhelper-build-stamp delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/docs delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/files delete mode 100755 packaging/build/compute-0.1.0.dev1/debian/rules delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/source/format delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/source/options delete mode 100644 packaging/build/compute-0.1.0.dev1/debian/upstream/metadata.ex delete mode 100644 packaging/build/compute-0.1.0.dev1/pyproject.toml delete mode 100644 packaging/build/compute-doc_0.1.0.dev1-1_all.deb delete mode 100644 packaging/build/compute_0.1.0.dev1-1.debian.tar.xz delete mode 100644 packaging/build/compute_0.1.0.dev1-1.dsc delete mode 100644 packaging/build/compute_0.1.0.dev1-1_all.deb delete mode 100644 packaging/build/compute_0.1.0.dev1-1_amd64.buildinfo delete mode 100644 packaging/build/compute_0.1.0.dev1-1_amd64.changes delete mode 100644 packaging/build/compute_0.1.0.dev1.orig.tar.gz delete mode 100644 packaging/build/docs/Makefile delete mode 100644 packaging/build/docs/make.bat delete mode 100644 packaging/build/docs/source/_templates/versioning.html delete mode 100644 packaging/build/docs/source/conf.py delete mode 100644 packaging/build/docs/source/index.rst delete mode 100644 packaging/build/docs/source/pyapi/exceptions.rst delete mode 100644 packaging/build/docs/source/pyapi/index.rst delete mode 100644 packaging/build/docs/source/pyapi/instance/guest_agent.rst delete mode 100644 packaging/build/docs/source/pyapi/instance/index.rst delete mode 100644 packaging/build/docs/source/pyapi/instance/instance.rst delete mode 100644 packaging/build/docs/source/pyapi/instance/schemas.rst delete mode 100644 packaging/build/docs/source/pyapi/session.rst delete mode 100644 packaging/build/docs/source/pyapi/storage/index.rst delete mode 100644 packaging/build/docs/source/pyapi/storage/pool.rst delete mode 100644 packaging/build/docs/source/pyapi/storage/volume.rst delete mode 100644 packaging/build/docs/source/pyapi/utils.rst diff --git a/packaging/build/compute-0.1.0.dev1.tar.gz b/packaging/build/compute-0.1.0.dev1.tar.gz deleted file mode 100644 index fcb6882313d06126099819d8417de54da00684f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20824 zcmV)7K*zryiwFn+00002|6^}$aCLNLEif)IE-)@+Wp*(xbYXG;?Y(Pz+c=UaJfHO| zxaoHuN9W{I|_wDp-`9LW$^N^$Kk{KC>%!VAAXZhi$7I=TdlSA;yb3dTdVEWKX?y+_#Hm8 zEDuxY{trLqXZ4jg&f{^^ZEv+&o3GbbH`_t$)#lb#d#m<`<>&wT&mb93XL+>J3SixX zVRYAidD7e7J?I7F;rHDCo9pXU`+s$FYx587^^Mi7jn?|w<_7Hl)zyuSKX|R>{{PKC zKY2Th0kxX=;>8mH$z%{^-Z-3uH_(I}Z>BNz3bhQ+UjcLiVXxt)_F9FD_jt+wKw zKU{b_X%y-s!DJ7TcTbKE#P`7{nGILsNt}DvN$O40*^Nj#h{g$k!%Tdi>ZuH{Lp*52dk0i01pWUSc(`X8RmI7xP^2xc^GNQ(9Am+$TZBd{5DNy zH@DjOZ)RZ{PVzV+FeS4TAs4~FfG62(I!#gu*njUGeDL1Q00Q3j4Q895_cYMUmNIXa zK@ks7!we7r1_`~&VeB0JeU(-w(+3DG|HsFp zeJklO%At`@&f7L~*;2+; zIQTT1%H;ij?C|a`c5AJ6{FvXuJlBGD`%gH#H2T*pPNN}gU}|PG^3JD8l&6mu_1iq3 zW}TNWr&MQ!lY=C^dD&><&YeVFeoJjklPt~?L0Hn+q*JS1US8I?25)3&cxB~2&Tj!l z@6=Z$JXo^!llNv8kA^VVt2hK8!At<8#h`#heFEgTj?*k}LbuUG>xYQe71m!FMpxY6 zr8pBWX-x7L617X&dgk57&@@)ena*(rpyEqv4X`JT1~{?6JC=0@FubcsP6`m>E)KoR z;q=qZr3WPJGMwfsH&K2m#wLC$AOtVPP<{^NSihbA2TT5c$^UEo|9WdRXs^G1)mq3IZ$R-S|Np!2|7Um*U&kY2S*Br{ zd¶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 diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute-0.1.0.dev1.dist-info/METADATA b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute-0.1.0.dev1.dist-info/METADATA deleted file mode 100644 index f4c22ad..0000000 --- a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute-0.1.0.dev1.dist-info/METADATA +++ /dev/null @@ -1,81 +0,0 @@ -Metadata-Version: 2.1 -Name: compute -Version: 0.1.0.dev1 -Summary: Compute instances management library and tools -Author: ge -Author-email: ge@nixhacks.net -Requires-Python: >=3.11,<4.0 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.11 -Requires-Dist: libvirt-python (==9.0.0) -Requires-Dist: lxml (>=4.9.2,<5.0.0) -Requires-Dist: pydantic (==1.10.4) -Requires-Dist: pyyaml (>=6.0.1,<7.0.0) -Description-Content-Type: text/markdown - -# Compute - -Compute instances management library and tools. - -## Docs - -Run `make serve-docs`. See [Development](#development) below. - -## Roadmap - -- [x] Create instances -- [ ] CDROM -- [ ] cloud-init for provisioning instances -- [x] Instance power management -- [x] Instance pause and resume -- [x] vCPU hotplug -- [x] Memory hotplug -- [x] Hot disk resize [not tested] -- [ ] CPU topology customization -- [x] CPU customization (emulation mode, model, vendor, features) -- [ ] BIOS/UEFI settings -- [x] Device attaching -- [x] Device detaching -- [ ] GPU passthrough -- [ ] CPU guarantied resource percent support -- [x] QEMU Guest Agent management -- [ ] Instance resources usage stats -- [ ] SSH-keys management -- [x] Setting user passwords in guest -- [x] QCOW2 disks support -- [ ] ZVOL support -- [ ] Network disks support -- [ ] Images service integration (Images service is not implemented yet) -- [ ] Manage storage pools -- [ ] Idempotency -- [ ] CLI [in progress] -- [ ] HTTP API -- [ ] Instance migrations -- [ ] Instance snapshots -- [ ] Instance backups -- [ ] LXC - -## Development - -Python 3.11+ is required. - -Install [poetry](https://python-poetry.org/), clone this repository and run: - -``` -poetry install --with dev --with docs -``` - -# Build Debian package - -Install Docker first, then run: - -``` -make build-deb -``` - -`compute` and `compute-doc` packages will built. See packaging/build directory. Packages can be installed via `dpkg` or `apt-get`: - -``` -apt-get install ./compute*.deb -``` - diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute-0.1.0.dev1.dist-info/RECORD b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute-0.1.0.dev1.dist-info/RECORD deleted file mode 100644 index 5f97163..0000000 --- a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute-0.1.0.dev1.dist-info/RECORD +++ /dev/null @@ -1,23 +0,0 @@ -../scripts/compute,sha256=b-Gj6H6ssfbGalpouUMSX5pmsjqDnN9xMdTwnU-UfZY,216 -compute/__init__.py,sha256=x4zp_CoVPKgDT6AqhometspAyinGxJUXO48duJ5aHUM,873 -compute/__main__.py,sha256=zJyKJul6pCbguFPtVLZBoAuZl9RXibn4CCMn46jIgUQ,745 -compute/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -compute/cli/control.py,sha256=83wnR21pHOPyyk1i1n_YBIDz6dCFB6hmuIFguIk68rs,14634 -compute/common.py,sha256=G1qwC1EybG5LEJtyoux9ymiqB2ZOsgKXlCpbuhHv55Y,948 -compute/exceptions.py,sha256=Ga59L55qSAPeyDfjANPuMh4yVSRWHDYi9xqq5o4_7-0,2452 -compute/instance/__init__.py,sha256=kHN8jVamyrBZYZgi62tPtJ7rS73gUPhfswLalmPA5Zs,772 -compute/instance/guest_agent.py,sha256=fq89kQbcV5X5eFCsMmujRuwTOSghWO4ZhAjvxyUu84M,7018 -compute/instance/instance.py,sha256=WP6oTJfdAf6QlefwVLqdC8J6XoKHum6nZhwwHOEtjNk,23297 -compute/instance/schemas.py,sha256=B51ytPlxhnx0MrkR2WYhd49RaRT7Is7NsIM9OrMUpvI,4288 -compute/session.py,sha256=znYOIzoiCbSG62k-ViaXti_lOnw88wD8Syp3nCXAJ28,10050 -compute/storage/__init__.py,sha256=zNaVjZ2925DxrVUFWwVRsGU6bSYbF46sb4L6NsaiKbw,736 -compute/storage/pool.py,sha256=9z99bBDbb4ATGpfMkEWpxAO4fEQHNVOxxf0iUln9cN0,4197 -compute/storage/volume.py,sha256=_TbK9Y4d3NAeknPUiuhldAT3ZaN1sZgjy4QzC-Sw4Io,4110 -compute/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -compute/utils/config_loader.py,sha256=ul1J3sZg0D9R0HbOz5Pg9JmL4nFaMahAzQEdGaWFABU,1989 -compute/utils/ids.py,sha256=fg6Xsg4OMM-BIaU3DPu0L91ICwx-L3qNoELEwQZz2s0,1007 -compute/utils/units.py,sha256=UkwD0zQ-rlpSpkbfezCcvJx4D8iZlI9M-oXXvdVEvy0,1549 -compute-0.1.0.dev1.dist-info/METADATA,sha256=tbX8xp92Jwqf44sOwPB-HqKHLezab5dU9DrQDYFitDQ,1944 -compute-0.1.0.dev1.dist-info/WHEEL,sha256=vVCvjcmxuUltf8cYhJ0sJMRDLr1XsPuxEId8YDzbyCY,88 -compute-0.1.0.dev1.dist-info/entry_points.txt,sha256=xHhg-Fo9Z5gJnIahbG8pVIGNDqlH5Eordn8hnXUwscw,51 -compute-0.1.0.dev1.dist-info/RECORD,, diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute-0.1.0.dev1.dist-info/WHEEL b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute-0.1.0.dev1.dist-info/WHEEL deleted file mode 100644 index 4ba7671..0000000 --- a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute-0.1.0.dev1.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: poetry-core 1.4.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute-0.1.0.dev1.dist-info/entry_points.txt b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute-0.1.0.dev1.dist-info/entry_points.txt deleted file mode 100644 index 4130f9f..0000000 --- a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute-0.1.0.dev1.dist-info/entry_points.txt +++ /dev/null @@ -1,3 +0,0 @@ -[console_scripts] -compute=compute.cli.control:cli - diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/__init__.py b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/__init__.py deleted file mode 100644 index ffe06d7..0000000 --- a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Compute instances management library.""" - -__version__ = '0.1.0-dev1' - -from .instance import Instance, InstanceConfig, InstanceSchema -from .session import Session -from .storage import StoragePool, Volume, VolumeConfig diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/__main__.py b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/__main__.py deleted file mode 100644 index 4995fbd..0000000 --- a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/__main__.py +++ /dev/null @@ -1,21 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Command line interface for compute module.""" - -from compute.cli import main - - -main.cli() diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/cli/__init__.py b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/cli/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/cli/control.py b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/cli/control.py deleted file mode 100644 index f5a5b91..0000000 --- a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/cli/control.py +++ /dev/null @@ -1,501 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Command line interface.""" - -import argparse -import io -import logging -import os -import shlex -import sys -from collections import UserDict -from typing import Any -from uuid import uuid4 - -import libvirt -import yaml -from pydantic import ValidationError - -from compute import __version__ -from compute.exceptions import ComputeError, GuestAgentTimeoutExceededError -from compute.instance import GuestAgent -from compute.session import Session -from compute.utils import ids - - -log = logging.getLogger(__name__) -log_levels = [lv.lower() for lv in logging.getLevelNamesMapping()] - -libvirt.registerErrorHandler( - lambda userdata, err: None, # noqa: ARG005 - ctx=None, -) - - -class Table: - """Minimalistic text table constructor.""" - - def __init__(self, whitespace: str | None = None): - """Initialise Table.""" - self.whitespace = whitespace or '\t' - self.header = [] - self.rows = [] - self.table = '' - - def add_row(self, row: list) -> None: - """Add table row.""" - self.rows.append([str(col) for col in row]) - - def add_rows(self, rows: list[list]) -> None: - """Add multiple rows.""" - for row in rows: - self.add_row(row) - - def __str__(self) -> str: - """Build table and return.""" - widths = [max(map(len, col)) for col in zip(*self.rows, strict=True)] - self.rows.insert(0, [str(h).upper() for h in self.header]) - for row in self.rows: - self.table += self.whitespace.join( - ( - val.ljust(width) - for val, width in zip(row, widths, strict=True) - ) - ) - self.table += '\n' - return self.table.strip() - - -def _list_instances(session: Session) -> None: - table = Table() - table.header = ['NAME', 'STATE'] - for instance in session.list_instances(): - table.add_row( - [ - instance.name, - instance.get_status(), - ] - ) - print(table) - sys.exit() - - -def _exec_guest_agent_command( - session: Session, args: argparse.Namespace -) -> None: - instance = session.get_instance(args.instance) - ga = GuestAgent(instance.domain, timeout=args.timeout) - arguments = args.arguments.copy() - if len(arguments) > 1 and not args.no_join_args: - arguments = [shlex.join(arguments)] - if not args.no_join_args: - arguments.insert(0, '-c') - stdin = None - if not sys.stdin.isatty(): - stdin = sys.stdin.read() - try: - output = ga.guest_exec( - path=args.executable, - args=arguments, - env=args.env, - stdin=stdin, - capture_output=True, - decode_output=True, - poll=True, - ) - except GuestAgentTimeoutExceededError as e: - sys.exit( - f'{e}. NOTE: command may still running in guest, ' - f'PID={ga.last_pid}' - ) - if output.stderr: - print(output.stderr.strip(), file=sys.stderr) - if output.stdout: - print(output.stdout.strip(), file=sys.stdout) - sys.exit(output.exitcode) - - -class _NotPresent: - """ - Type for representing non-existent dictionary keys. - - See :class:`_FillableDict`. - """ - - -class _FillableDict(UserDict): - """Use :method:`fill` to add key if not present.""" - - def __init__(self, data: dict): - self.data = data - - def fill(self, key: str, value: Any) -> None: # noqa: ANN401 - if self.data.get(key, _NotPresent) is _NotPresent: - self.data[key] = value - - -def _merge_dicts(a: dict, b: dict, path: list[str] | None = None) -> dict: - """Merge `b` into `a`. Return modified `a`.""" - if path is None: - path = [] - for key in b: - if key in a: - if isinstance(a[key], dict) and isinstance(b[key], dict): - _merge_dicts(a[key], b[key], [path + str(key)]) - elif a[key] == b[key]: - pass # same leaf value - else: - a[key] = b[key] # replace existing key's values - else: - a[key] = b[key] - return a - - -def _create_instance(session: Session, file: io.TextIOWrapper) -> None: - try: - data = _FillableDict(yaml.load(file.read(), Loader=yaml.SafeLoader)) - log.debug('Read from file: %s', data) - except yaml.YAMLError as e: - sys.exit(f'error: cannot parse YAML: {e}') - - capabilities = session.get_capabilities() - node_info = session.get_node_info() - - data.fill('name', uuid4().hex) - data.fill('title', None) - data.fill('description', None) - data.fill('arch', capabilities.arch) - data.fill('machine', capabilities.machine) - data.fill('emulator', capabilities.emulator) - data.fill('max_vcpus', node_info.cpus) - data.fill('max_memory', node_info.memory) - data.fill('cpu', {}) - cpu = { - 'emulation_mode': 'host-passthrough', - 'model': None, - 'vendor': None, - 'topology': None, - 'features': None, - } - data['cpu'] = _merge_dicts(data['cpu'], cpu) - data.fill( - 'network_interfaces', - [{'source': 'default', 'mac': ids.random_mac()}], - ) - data.fill('boot', {'order': ['cdrom', 'hd']}) - - try: - log.debug('Input data: %s', data) - session.create_instance(**data) - except ValidationError as e: - for error in e.errors(): - fields = '.'.join([str(lc) for lc in error['loc']]) - print( - f"validation error: {fields}: {error['msg']}", - file=sys.stderr, - ) - sys.exit() - - -def _shutdown_instance(session: Session, args: argparse.Namespace) -> None: - instance = session.get_instance(args.instance) - if args.soft: - method = 'SOFT' - elif args.hard: - method = 'HARD' - elif args.unsafe: - method = 'UNSAFE' - else: - method = 'NORMAL' - instance.shutdown(method) - - -def main(session: Session, args: argparse.Namespace) -> None: - """Perform actions.""" - match args.command: - case 'init': - _create_instance(session, args.file) - case 'exec': - _exec_guest_agent_command(session, args) - case 'ls': - _list_instances(session) - case 'start': - instance = session.get_instance(args.instance) - instance.start() - case 'shutdown': - _shutdown_instance(session, args) - case 'reboot': - instance = session.get_instance(args.instance) - instance.reboot() - case 'reset': - instance = session.get_instance(args.instance) - instance.reset() - case 'powrst': - instance = session.get_instance(args.instance) - instance.power_reset() - case 'pause': - instance = session.get_instance(args.instance) - instance.pause() - case 'resume': - instance = session.get_instance(args.instance) - instance.resume() - case 'status': - instance = session.get_instance(args.instance) - print(instance.status) - case 'setvcpus': - instance = session.get_instance(args.instance) - instance.set_vcpus(args.nvcpus, live=True) - case 'setmem': - instance = session.get_instance(args.instance) - instance.set_memory(args.memory, live=True) - case 'setpass': - instance = session.get_instance(args.instance) - instance.set_user_password( - args.username, - args.password, - encrypted=args.encrypted, - ) - - -def cli() -> None: # noqa: PLR0915 - """Return command line arguments parser.""" - root = argparse.ArgumentParser( - prog='compute', - description='manage compute instances', - formatter_class=argparse.RawTextHelpFormatter, - ) - root.add_argument( - '-v', - '--verbose', - action='store_true', - default=False, - help='enable verbose mode', - ) - root.add_argument( - '-c', - '--connect', - metavar='URI', - help='libvirt connection URI', - ) - root.add_argument( - '-l', - '--log-level', - type=str.lower, - metavar='LEVEL', - choices=log_levels, - help='log level', - ) - root.add_argument( - '-V', - '--version', - action='version', - version=__version__, - ) - subparsers = root.add_subparsers(dest='command', metavar='COMMAND') - - # init command - init = subparsers.add_parser( - 'init', help='initialise instance using YAML config file' - ) - init.add_argument( - 'file', - type=argparse.FileType('r', encoding='UTF-8'), - nargs='?', - default='instance.yaml', - help='instance config [default: instance.yaml]', - ) - - # exec subcommand - execute = subparsers.add_parser( - 'exec', - help='execute command in guest via guest agent', - description=( - 'NOTE: any argument after instance name will be passed into ' - 'guest as shell command.' - ), - ) - execute.add_argument('instance') - execute.add_argument('arguments', nargs=argparse.REMAINDER) - execute.add_argument( - '-t', - '--timeout', - type=int, - default=60, - help=( - 'waiting time in seconds for a command to be executed ' - 'in guest [default: 60]' - ), - ) - execute.add_argument( - '-x', - '--executable', - default='/bin/sh', - help='path to executable in guest [default: /bin/sh]', - ) - execute.add_argument( - '-e', - '--env', - type=str, - nargs='?', - action='append', - help='environment variables to pass to executable in guest', - ) - execute.add_argument( - '-n', - '--no-join-args', - action='store_true', - default=False, - help=( - "do not join arguments list and add '-c' option, suitable " - 'for non-shell executables and other specific cases.' - ), - ) - - # ls subcommand - listall = subparsers.add_parser('ls', help='list instances') - listall.add_argument( - '-a', - '--all', - action='store_true', - default=False, - help='list all instances including inactive', - ) - - # start subcommand - start = subparsers.add_parser('start', help='start instance') - start.add_argument('instance') - - # shutdown subcommand - shutdown = subparsers.add_parser('shutdown', help='shutdown instance') - shutdown.add_argument('instance') - shutdown_opts = shutdown.add_mutually_exclusive_group() - shutdown_opts.add_argument( - '-s', - '--soft', - action='store_true', - help='normal guest OS shutdown, guest agent is used', - ) - shutdown_opts.add_argument( - '-n', - '--normal', - action='store_true', - help='shutdown with hypervisor selected method [default]', - ) - shutdown_opts.add_argument( - '-H', - '--hard', - action='store_true', - help=( - "gracefully destroy instance, it's like long " - 'pressing the power button' - ), - ) - shutdown_opts.add_argument( - '-u', - '--unsafe', - action='store_true', - help=( - 'destroy instance, this is similar to a power outage ' - 'and may result in data loss or corruption' - ), - ) - - # reboot subcommand - reboot = subparsers.add_parser('reboot', help='reboot instance') - reboot.add_argument('instance') - - # reset subcommand - reset = subparsers.add_parser('reset', help='reset instance') - reset.add_argument('instance') - - # powrst subcommand - powrst = subparsers.add_parser('powrst', help='power reset instance') - powrst.add_argument('instance') - - # pause subcommand - pause = subparsers.add_parser('pause', help='pause instance') - pause.add_argument('instance') - - # resume subcommand - resume = subparsers.add_parser('resume', help='resume paused instance') - resume.add_argument('instance') - - # status subcommand - status = subparsers.add_parser('status', help='display instance status') - status.add_argument('instance') - - # setvcpus subcommand - setvcpus = subparsers.add_parser('setvcpus', help='set vCPU number') - setvcpus.add_argument('instance') - setvcpus.add_argument('nvcpus', type=int) - - # setmem subcommand - setmem = subparsers.add_parser('setmem', help='set memory size') - setmem.add_argument('instance') - setmem.add_argument('memory', type=int, help='memory in MiB') - - # setpass subcommand - setpass = subparsers.add_parser( - 'setpass', - help='set user password in guest', - ) - setpass.add_argument('instance') - setpass.add_argument('username') - setpass.add_argument('password') - setpass.add_argument( - '-e', - '--encrypted', - action='store_true', - default=False, - help='set it if password is already encrypted', - ) - - args = root.parse_args() - if args.command is None: - root.print_help() - sys.exit() - - log_level = args.log_level or os.getenv('CMP_LOG') - - if isinstance(log_level, str) and log_level.lower() in log_levels: - logging.basicConfig( - level=logging.getLevelNamesMapping()[log_level.upper()] - ) - - log.debug('CLI started with args: %s', args) - - connect_uri = ( - args.connect - or os.getenv('CMP_LIBVIRT_URI') - or os.getenv('LIBVIRT_DEFAULT_URI') - or 'qemu:///system' - ) - - try: - with Session(connect_uri) as session: - main(session, args) - except ComputeError as e: - sys.exit(f'error: {e}') - except KeyboardInterrupt: - sys.exit() - except SystemExit as e: - sys.exit(e) - except Exception as e: # noqa: BLE001 - sys.exit(f'unexpected error {type(e)}: {e}') - - -if __name__ == '__main__': - cli() diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/common.py b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/common.py deleted file mode 100644 index 34a339a..0000000 --- a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/common.py +++ /dev/null @@ -1,30 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Common symbols.""" - -from abc import ABC, abstractmethod - - -class EntityConfig(ABC): - """An abstract entity XML config builder class.""" - - @abstractmethod - def to_xml(self) -> str: - """Return device XML config.""" - raise NotImplementedError - - -DeviceConfig = EntityConfig diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/exceptions.py b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/exceptions.py deleted file mode 100644 index 1eef8de..0000000 --- a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/exceptions.py +++ /dev/null @@ -1,80 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Exceptions.""" - - -class ComputeError(Exception): - """Basic exception class.""" - - -class ConfigLoaderError(ComputeError): - """Something went wrong when loading configuration.""" - - -class SessionError(ComputeError): - """Something went wrong while connecting to libvirtd.""" - - -class GuestAgentError(ComputeError): - """Something went wring when QEMU Guest Agent call.""" - - -class GuestAgentUnavailableError(GuestAgentError): - """Guest agent is not connected or is unavailable.""" - - -class GuestAgentTimeoutExceededError(GuestAgentError): - """QEMU timeout exceeded.""" - - def __init__(self, msg: int): - """Initialise GuestAgentTimeoutExceededError.""" - super().__init__(f'QEMU timeout ({msg} sec) exceeded') - - -class GuestAgentCommandNotSupportedError(GuestAgentError): - """Guest agent command is not supported or blacklisted on guest.""" - - -class StoragePoolError(ComputeError): - """Something went wrong when operating with storage pool.""" - - -class StoragePoolNotFoundError(StoragePoolError): - """Storage pool not found.""" - - def __init__(self, msg: str): - """Initialise StoragePoolNotFoundError.""" - super().__init__(f"storage pool named '{msg}' not found") - - -class VolumeNotFoundError(StoragePoolError): - """Storage volume not found.""" - - def __init__(self, msg: str): - """Initialise VolumeNotFoundError.""" - super().__init__(f"storage volume '{msg}' not found") - - -class InstanceError(ComputeError): - """Something went wrong while interacting with the domain.""" - - -class InstanceNotFoundError(InstanceError): - """Virtual machine or container not found on compute node.""" - - def __init__(self, msg: str): - """Initialise InstanceNotFoundError.""" - super().__init__(f"compute instance '{msg}' not found") diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/instance/__init__.py b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/instance/__init__.py deleted file mode 100644 index 6e2b150..0000000 --- a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/instance/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -from .guest_agent import GuestAgent -from .instance import Instance, InstanceConfig -from .schemas import InstanceSchema diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/instance/guest_agent.py b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/instance/guest_agent.py deleted file mode 100644 index 4381591..0000000 --- a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/instance/guest_agent.py +++ /dev/null @@ -1,208 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Interacting with the QEMU Guest Agent.""" - -import json -import logging -from base64 import b64decode, standard_b64encode -from time import sleep, time -from typing import NamedTuple - -import libvirt -import libvirt_qemu - -from compute.exceptions import ( - GuestAgentCommandNotSupportedError, - GuestAgentError, - GuestAgentTimeoutExceededError, - GuestAgentUnavailableError, -) - - -log = logging.getLogger(__name__) - - -class GuestExecOutput(NamedTuple): - """QEMU guest-exec command output.""" - - exited: bool | None = None - exitcode: int | None = None - stdout: str | None = None - stderr: str | None = None - - -class GuestAgent: - """Class for interacting with QEMU guest agent.""" - - def __init__(self, domain: libvirt.virDomain, timeout: int = 60): - """ - Initialise GuestAgent. - - :param domain: Libvirt domain object - :param timeout: QEMU timeout - """ - self.domain = domain - self.timeout = timeout - self.flags = libvirt_qemu.VIR_DOMAIN_QEMU_MONITOR_COMMAND_DEFAULT - self.last_pid = None - - def execute(self, command: dict) -> dict: - """ - Execute QEMU guest agent command. - - See: https://qemu-project.gitlab.io/qemu/interop/qemu-ga-ref.html - - :param command: QEMU guest agent command as dict - :return: Command output - :rtype: dict - """ - log.debug(command) - try: - output = libvirt_qemu.qemuAgentCommand( - self.domain, json.dumps(command), self.timeout, self.flags - ) - return json.loads(output) - except libvirt.libvirtError as e: - if e.get_error_code() == libvirt.VIR_ERR_AGENT_UNRESPONSIVE: - raise GuestAgentUnavailableError(e) from e - raise GuestAgentError(e) from e - - def is_available(self) -> bool: - """ - Execute guest-ping. - - :return: True or False if guest agent is unreachable. - :rtype: bool - """ - try: - if self.execute({'execute': 'guest-ping', 'arguments': {}}): - return True - except GuestAgentError: - return False - - def get_supported_commands(self) -> set[str]: - """Return set of supported guest agent commands.""" - output = self.execute({'execute': 'guest-info', 'arguments': {}}) - return { - cmd['name'] - for cmd in output['return']['supported_commands'] - if cmd['enabled'] is True - } - - def raise_for_commands(self, commands: list[str]) -> None: - """ - Raise exception if QEMU GA command is not available. - - :param commands: List of required commands - :raise: GuestAgentCommandNotSupportedError - """ - supported = self.get_supported_commands() - for command in commands: - if command not in supported: - raise GuestAgentCommandNotSupportedError(command) - - def guest_exec( # noqa: PLR0913 - self, - path: str, - args: list[str] | None = None, - env: list[str] | None = None, - stdin: str | None = None, - *, - capture_output: bool = False, - decode_output: bool = False, - poll: bool = False, - ) -> GuestExecOutput: - """ - Execute qemu-exec command and return output. - - :param path: Path ot executable on guest. - :param arg: List of arguments to pass to executable. - :param env: List of environment variables to pass to executable. - For example: ``['LANG=C', 'TERM=xterm']`` - :param stdin: Data to pass to executable STDIN. - :param capture_output: Capture command output. - :param decode_output: Use base64_decode() to decode command output. - Affects only if `capture_output` is True. - :param poll: Poll command output. Uses `self.timeout` and - POLL_INTERVAL constant. - :return: Command output - :rtype: GuestExecOutput - """ - self.raise_for_commands(['guest-exec', 'guest-exec-status']) - command = { - 'execute': 'guest-exec', - 'arguments': { - 'path': path, - **({'arg': args} if args else {}), - **({'env': env} if env else {}), - **( - { - 'input-data': standard_b64encode( - stdin.encode('utf-8') - ).decode('utf-8') - } - if stdin - else {} - ), - 'capture-output': capture_output, - }, - } - output = self.execute(command) - self.last_pid = pid = output['return']['pid'] - command_status = self.guest_exec_status(pid, poll=poll)['return'] - exited = command_status['exited'] - exitcode = command_status['exitcode'] - stdout = command_status.get('out-data', None) - stderr = command_status.get('err-data', None) - if decode_output: - stdout = b64decode(stdout or '').decode('utf-8') - stderr = b64decode(stderr or '').decode('utf-8') - return GuestExecOutput(exited, exitcode, stdout, stderr) - - def guest_exec_status( - self, pid: int, *, poll: bool = False, poll_interval: float = 0.3 - ) -> dict: - """ - Execute guest-exec-status and return output. - - :param pid: PID in guest. - :param poll: If True poll command status. - :param poll_interval: Time between attempts to obtain command status. - :return: Command output - :rtype: dict - """ - self.raise_for_commands(['guest-exec-status']) - command = { - 'execute': 'guest-exec-status', - 'arguments': {'pid': pid}, - } - if not poll: - return self.execute(command) - start_time = time() - while True: - command_status = self.execute(command) - if command_status['return']['exited']: - break - sleep(poll_interval) - now = time() - if now - start_time > self.timeout: - raise GuestAgentTimeoutExceededError(self.timeout) - log.debug( - 'Polling command pid=%s finished, time taken: %s seconds', - pid, - int(time() - start_time), - ) - return command_status diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/instance/instance.py b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/instance/instance.py deleted file mode 100644 index 5b806e6..0000000 --- a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/instance/instance.py +++ /dev/null @@ -1,675 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Manage compute instances.""" - -__all__ = ['Instance', 'InstanceConfig', 'InstanceInfo'] - -import logging -from typing import NamedTuple - -import libvirt -from lxml import etree -from lxml.builder import E - -from compute.common import DeviceConfig, EntityConfig -from compute.exceptions import ( - GuestAgentCommandNotSupportedError, - InstanceError, -) -from compute.storage import DiskConfig -from compute.utils import units - -from .guest_agent import GuestAgent -from .schemas import ( - CPUEmulationMode, - CPUSchema, - InstanceSchema, - NetworkInterfaceSchema, -) - - -log = logging.getLogger(__name__) - - -class InstanceConfig(EntityConfig): - """Compute instance XML config builder.""" - - def __init__(self, schema: InstanceSchema): - """ - Initialise InstanceConfig. - - :param schema: InstanceSchema object - """ - self.name = schema.name - self.title = schema.title - self.description = schema.description - self.memory = schema.memory - self.max_memory = schema.max_memory - self.vcpus = schema.vcpus - self.max_vcpus = schema.max_vcpus - self.cpu = schema.cpu - self.machine = schema.machine - self.emulator = schema.emulator - self.arch = schema.arch - self.boot = schema.boot - self.network_interfaces = schema.network_interfaces - - def _gen_cpu_xml(self, cpu: CPUSchema) -> etree.Element: - options = { - 'mode': cpu.emulation_mode, - 'match': 'exact', - 'check': 'partial', - } - if cpu.emulation_mode == CPUEmulationMode.HOST_PASSTHROUGH: - options['check'] = 'none' - options['migratable'] = 'on' - xml = E.cpu(**options) - if cpu.model: - xml.append(E.model(cpu.model, fallback='forbid')) - if cpu.vendor: - xml.append(E.vendor(cpu.vendor)) - if cpu.topology: - xml.append( - E.topology( - sockets=str(cpu.topology.sockets), - dies=str(cpu.topology.dies), - cores=str(cpu.topology.cores), - threads=str(cpu.topology.threads), - ) - ) - if cpu.features: - for feature in cpu.features.require: - xml.append(E.feature(policy='require', name=feature)) - for feature in cpu.features.disable: - xml.append(E.feature(policy='disable', name=feature)) - return xml - - def _gen_vcpus_xml(self, vcpus: int, max_vcpus: int) -> etree.Element: - xml = E.vcpus() - xml.append(E.vcpu(id='0', enabled='yes', hotpluggable='no', order='1')) - for i in range(max_vcpus - 1): - enabled = 'yes' if (i + 2) <= vcpus else 'no' - xml.append( - E.vcpu( - id=str(i + 1), - enabled=enabled, - hotpluggable='yes', - order=str(i + 2), - ) - ) - return xml - - def _gen_network_interface_xml( - self, interface: NetworkInterfaceSchema - ) -> etree.Element: - return E.interface( - E.source(network=interface.source), - E.mac(address=interface.mac), - type='network', - ) - - def to_xml(self) -> str: - """Return XML config for libvirt.""" - xml = E.domain(type='kvm') - xml.append(E.name(self.name)) - if self.title: - xml.append(E.title(self.title)) - if self.description: - xml.append(E.description(self.description)) - xml.append(E.metadata()) - xml.append(E.memory(str(self.max_memory * 1024), unit='KiB')) - xml.append(E.currentMemory(str(self.memory * 1024), unit='KiB')) - xml.append( - E.vcpu( - str(self.max_vcpus), - placement='static', - current=str(self.vcpus), - ) - ) - xml.append(self._gen_cpu_xml(self.cpu)) - os = E.os(E.type('hvm', machine=self.machine, arch=self.arch)) - for dev in self.boot.order: - os.append(E.boot(dev=dev)) - xml.append(os) - xml.append(E.features(E.acpi(), E.apic())) - xml.append(E.on_poweroff('destroy')) - xml.append(E.on_reboot('restart')) - xml.append(E.on_crash('restart')) - xml.append( - E.pm( - E('suspend-to-mem', enabled='no'), - E('suspend-to-disk', enabled='no'), - ) - ) - devices = E.devices() - devices.append(E.emulator(str(self.emulator))) - for interface in self.network_interfaces: - devices.append(self._gen_network_interface_xml(interface)) - devices.append(E.graphics(type='vnc', port='-1', autoport='yes')) - devices.append(E.input(type='tablet', bus='usb')) - devices.append( - E.channel( - E.source(mode='bind'), - E.target(type='virtio', name='org.qemu.guest_agent.0'), - E.address( - type='virtio-serial', controller='0', bus='0', port='1' - ), - type='unix', - ) - ) - devices.append( - E.console(E.target(type='serial', port='0'), type='pty') - ) - devices.append( - E.video( - E.model(type='vga', vram='16384', heads='1', primary='yes') - ) - ) - xml.append(devices) - return etree.tostring(xml, encoding='unicode', pretty_print=True) - - -class InstanceInfo(NamedTuple): - """ - Store compute instance info. - - Reference: - https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainInfo - """ - - state: str - max_memory: int - memory: int - nproc: int - cputime: int - - -class Instance: - """Manage compute instances.""" - - def __init__(self, domain: libvirt.virDomain): - """ - Initialise Instance. - - :ivar libvirt.virDomain domain: domain object - :ivar libvirt.virConnect connection: connection object - :ivar str name: domain name - :ivar GuestAgent guest_agent: :class:`GuestAgent` object - - :param domain: libvirt domain object - """ - self.domain = domain - self.connection = domain.connect() - self.name = domain.name() - self.guest_agent = GuestAgent(domain) - - def _expand_instance_state(self, state: int) -> str: - states = { - libvirt.VIR_DOMAIN_NOSTATE: 'nostate', - libvirt.VIR_DOMAIN_RUNNING: 'running', - libvirt.VIR_DOMAIN_BLOCKED: 'blocked', - libvirt.VIR_DOMAIN_PAUSED: 'paused', - libvirt.VIR_DOMAIN_SHUTDOWN: 'shutdown', - libvirt.VIR_DOMAIN_SHUTOFF: 'shutoff', - libvirt.VIR_DOMAIN_CRASHED: 'crashed', - libvirt.VIR_DOMAIN_PMSUSPENDED: 'pmsuspended', - } - return states[state] - - def get_info(self) -> InstanceInfo: - """Return instance info.""" - info = self.domain.info() - return InstanceInfo( - state=self._expand_instance_state(info[0]), - max_memory=info[1], - memory=info[2], - nproc=info[3], - cputime=info[4], - ) - - def get_status(self) -> str: - """ - Return instance state: 'running', 'shutoff', etc. - - Reference: - https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainState - """ - try: - state, _ = self.domain.state() - except libvirt.libvirtError as e: - raise InstanceError( - 'Cannot fetch status of ' f'instance={self.name}: {e}' - ) from e - return self._expand_instance_state(state) - - def is_running(self) -> bool: - """Return True if instance is running, else return False.""" - if self.domain.isActive() != 1: - # 0 - is inactive, -1 - is error - return False - return True - - def is_autostart(self) -> bool: - """Return True if instance autostart is enabled, else return False.""" - try: - return bool(self.domain.autostart()) - except libvirt.libvirtError as e: - raise InstanceError( - f'Cannot get autostart status for ' - f'instance={self.name}: {e}' - ) from e - - def get_max_memory(self) -> int: - """Maximum memory value for domain in KiB.""" - return self.domain.maxMemory() - - def get_max_vcpus(self) -> int: - """Maximum vCPUs number for domain.""" - return self.domain.maxVcpus() - - def start(self) -> None: - """Start defined instance.""" - log.info('Starting instnce=%s', self.name) - if self.is_running(): - log.warning( - 'Already started, nothing to do instance=%s', self.name - ) - return - try: - self.domain.create() - except libvirt.libvirtError as e: - raise InstanceError( - f'Cannot start instance={self.name}: {e}' - ) from e - - def shutdown(self, method: str | None = None) -> None: - """ - Shutdown instance. - - Shutdown methods: - - SOFT - Use guest agent to shutdown. If guest agent is unavailable - NORMAL method will be used. - - NORMAL - Use method choosen by hypervisor to shutdown. Usually send ACPI - signal to guest OS. OS may ignore ACPI e.g. if guest is hanged. - - HARD - Shutdown instance without any guest OS shutdown. This is simular - to unplugging machine from power. Internally send SIGTERM to - instance process and destroy it gracefully. - - UNSAFE - Force shutdown. Internally send SIGKILL to instance process. - There is high data corruption risk! - - If method is None NORMAL method will used. - - :param method: Method used to shutdown instance - """ - methods = { - 'SOFT': libvirt.VIR_DOMAIN_SHUTDOWN_GUEST_AGENT, - 'NORMAL': libvirt.VIR_DOMAIN_SHUTDOWN_DEFAULT, - 'HARD': libvirt.VIR_DOMAIN_DESTROY_GRACEFUL, - 'UNSAFE': libvirt.VIR_DOMAIN_DESTROY_DEFAULT, - } - if method is None: - method = 'NORMAL' - if not isinstance(method, str): - raise TypeError( - f"Shutdown method must be a 'str', not {type(method)}" - ) - method = method.upper() - if method not in methods: - raise ValueError(f"Unsupported shutdown method: '{method}'") - try: - if method in ['SOFT', 'NORMAL']: - self.domain.shutdownFlags(flags=methods[method]) - elif method in ['HARD', 'UNSAFE']: - self.domain.destroyFlags(flags=methods[method]) - except libvirt.libvirtError as e: - raise InstanceError( - f'Cannot shutdown instance={self.name} ' f'{method=}: {e}' - ) from e - - def reboot(self) -> None: - """Send ACPI signal to guest OS to reboot. OS may ignore this.""" - try: - self.domain.reboot() - except libvirt.libvirtError as e: - raise InstanceError( - f'Cannot reboot instance={self.name}: {e}' - ) from e - - def reset(self) -> None: - """ - Reset instance. - - Copypaste from libvirt doc: - - Reset a domain immediately without any guest OS shutdown. - Reset emulates the power reset button on a machine, where all - hardware sees the RST line set and reinitializes internal state. - - Note that there is a risk of data loss caused by reset without any - guest OS shutdown. - """ - try: - self.domain.reset() - except libvirt.libvirtError as e: - raise InstanceError( - f'Cannot reset instance={self.name}: {e}' - ) from e - - def power_reset(self) -> None: - """ - Shutdown instance and start. - - By analogy with real hardware, this is a normal server shutdown, - and then turning off from the power supply and turning it on again. - - This method is applicable in cases where there has been a - configuration change in libvirt and you need to restart the - instance to apply the new configuration. - """ - self.shutdown(method='NORMAL') - self.start() - - def set_autostart(self, *, enabled: bool) -> None: - """ - Set autostart flag for instance. - - :param enabled: Bool argument to set or unset autostart flag. - """ - autostart = 1 if enabled else 0 - try: - self.domain.setAutostart(autostart) - except libvirt.libvirtError as e: - raise InstanceError( - f'Cannot set autostart flag for instance={self.name} ' - f'{autostart=}: {e}' - ) from e - - def set_vcpus(self, nvcpus: int, *, live: bool = False) -> None: - """ - Set vCPU number. - - If `live` is True and instance is not currently running vCPUs - will set in config and will applied when instance boot. - - NB: Note that if this call is executed before the guest has - finished booting, the guest may fail to process the change. - - :param nvcpus: Number of vCPUs - :param live: Affect a running instance - """ - if nvcpus <= 0: - raise InstanceError('Cannot set zero vCPUs') - if nvcpus > self.get_max_vcpus(): - raise InstanceError('vCPUs count is greather than max_vcpus') - if nvcpus == self.get_info().nproc: - log.warning( - 'Instance instance=%s already have %s vCPUs, nothing to do', - self.name, - nvcpus, - ) - return - try: - flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG - self.domain.setVcpusFlags(nvcpus, flags=flags) - if live is True: - if not self.is_running(): - log.warning( - 'Instance is not running, changes applied in ' - 'instance config.' - ) - return - flags = libvirt.VIR_DOMAIN_AFFECT_LIVE - self.domain.setVcpusFlags(nvcpus, flags=flags) - if self.guest_agent.is_available(): - try: - self.guest_agent.raise_for_commands( - ['guest-set-vcpus'] - ) - flags = libvirt.VIR_DOMAIN_VCPU_GUEST - self.domain.setVcpusFlags(nvcpus, flags=flags) - except GuestAgentCommandNotSupportedError: - log.warning( - 'Cannot set vCPUs in guest via agent, you may ' - 'need to apply changes in guest manually.' - ) - else: - log.warning( - 'Cannot set vCPUs in guest OS on instance=%s. ' - 'You may need to apply CPUs in guest manually.', - self.name, - ) - except libvirt.libvirtError as e: - raise InstanceError( - f'Cannot set vCPUs for instance={self.name}: {e}' - ) from e - - def set_memory(self, memory: int, *, live: bool = False) -> None: - """ - Set memory. - - If `live` is True and instance is not currently running set memory - in config and will applied when instance boot. - - :param memory: Memory value in mebibytes - :param live: Affect a running instance - """ - if memory <= 0: - raise InstanceError('Cannot set zero memory') - if (memory * 1024) > self.get_max_memory(): - raise InstanceError('Memory is greather than max_memory') - if (memory * 1024) == self.get_info().memory: - log.warning( - "Instance '%s' already have %s memory, nothing to do", - self.name, - memory, - ) - return - if live and self.is_running(): - flags = ( - libvirt.VIR_DOMAIN_AFFECT_LIVE - | libvirt.VIR_DOMAIN_AFFECT_CONFIG - ) - else: - flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG - try: - self.domain.setMemoryFlags(memory * 1024, flags=flags) - except libvirt.libvirtError as e: - msg = f'Cannot set memory for instance={self.name} {memory=}: {e}' - raise InstanceError(msg) from e - - def _get_disk_by_target(self, target: str) -> etree.Element: - xml = etree.fromstring(self.dump_xml()) # noqa: S320 - child = xml.xpath(f'/domain/devices/disk/target[@dev="{target}"]') - return child[0].getparent() if child else None - - def attach_device( - self, device: DeviceConfig, *, live: bool = False - ) -> None: - """ - Attach device to compute instance. - - :param device: Object with device description e.g. DiskConfig - :param live: Affect a running instance - """ - if live and self.is_running(): - flags = ( - libvirt.VIR_DOMAIN_AFFECT_LIVE - | libvirt.VIR_DOMAIN_AFFECT_CONFIG - ) - else: - flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG - if isinstance(device, DiskConfig): # noqa: SIM102 - if self._get_disk_by_target(device.target): - log.warning( - "Volume with target '%s' is already attached", - device.target, - ) - return - self.domain.attachDeviceFlags(device.to_xml(), flags=flags) - - def detach_device( - self, device: DeviceConfig, *, live: bool = False - ) -> None: - """ - Dettach device from compute instance. - - :param device: Object with device description e.g. DiskConfig - :param live: Affect a running instance - """ - if live and self.is_running(): - flags = ( - libvirt.VIR_DOMAIN_AFFECT_LIVE - | libvirt.VIR_DOMAIN_AFFECT_CONFIG - ) - else: - flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG - if isinstance(device, DiskConfig): # noqa: SIM102 - if self._get_disk_by_target(device.target) is None: - log.warning( - "Volume with target '%s' is already detached", - device.target, - ) - return - self.domain.detachDeviceFlags(device.to_xml(), flags=flags) - - def detach_disk(self, name: str) -> None: - """ - Detach disk device by target name. - - There is no ``attach_disk()`` method. Use :func:`attach_device` - with :class:`DiskConfig` as argument. - - :param name: Disk name e.g. 'vda', 'sda', etc. This name may - not match the name of the disk inside the guest OS. - """ - xml = self._get_disk_by_target(name) - if xml is None: - log.warning( - "Volume with target '%s' is already detached", - name, - ) - return - disk_params = { - 'disk_type': xml.get('type'), - 'source': xml.find('source').get('file'), - 'target': xml.find('target').get('dev'), - 'readonly': False if xml.find('readonly') is None else True, # noqa: SIM211 - } - for param in disk_params: - if disk_params[param] is None: - msg = ( - f"Cannot detach volume with target '{name}': " - f"parameter '{param}' is not defined in libvirt XML " - 'config on host.' - ) - raise InstanceError(msg) - self.detach_device(DiskConfig(**disk_params), live=True) - - def resize_disk( - self, name: str, capacity: int, unit: units.DataUnit - ) -> None: - """ - Resize attached block device. - - :param name: Disk device name e.g. `vda`, `sda`, etc. - :param capacity: New capacity. - :param unit: Capacity unit. - """ - self.domain.blockResize( - name, - units.to_bytes(capacity, unit=unit), - flags=libvirt.VIR_DOMAIN_BLOCK_RESIZE_BYTES, - ) - - def get_disks(self) -> list[DiskConfig]: - """Return list of attached disks.""" - raise NotImplementedError - - def pause(self) -> None: - """Pause instance.""" - if not self.is_running(): - raise InstanceError('Cannot pause inactive instance') - self.domain.suspend() - - def resume(self) -> None: - """Resume paused instance.""" - self.domain.resume() - - def get_ssh_keys(self, user: str) -> list[str]: - """ - Return list of SSH keys on guest for specific user. - - :param user: Username. - """ - raise NotImplementedError - - def set_ssh_keys(self, user: str, ssh_keys: list[str]) -> None: - """ - Add SSH keys to guest for specific user. - - :param user: Username. - :param ssh_keys: List of public SSH keys. - """ - raise NotImplementedError - - def delete_ssh_keys(self, user: str, ssh_keys: list[str]) -> None: - """ - Remove SSH keys from guest for specific user. - - :param user: Username. - :param ssh_keys: List of public SSH keys. - """ - raise NotImplementedError - - def set_user_password( - self, user: str, password: str, *, encrypted: bool = False - ) -> None: - """ - Set new user password in guest OS. - - This action performs by guest agent inside the guest. - - :param user: Username. - :param password: Password. - :param encrypted: Set it to True if password is already encrypted. - Right encryption method depends on guest OS. - """ - if not self.guest_agent.is_available(): - raise InstanceError( - 'Cannot change password: guest agent is unavailable' - ) - self.guest_agent.raise_for_commands(['guest-set-user-password']) - flags = libvirt.VIR_DOMAIN_PASSWORD_ENCRYPTED if encrypted else 0 - self.domain.setUserPassword(user, password, flags=flags) - - def dump_xml(self, *, inactive: bool = False) -> str: - """Return instance XML description.""" - flags = libvirt.VIR_DOMAIN_XML_INACTIVE if inactive else 0 - return self.domain.XMLDesc(flags) - - def delete(self) -> None: - """Undefine instance.""" - # TODO @ge: delete local disks - self.shutdown(method='HARD') - self.domain.undefine() diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/instance/schemas.py b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/instance/schemas.py deleted file mode 100644 index f5a677c..0000000 --- a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/instance/schemas.py +++ /dev/null @@ -1,165 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Compute instance related objects schemas.""" - -import re -from enum import StrEnum -from pathlib import Path - -from pydantic import BaseModel, Extra, validator - -from compute.utils.units import DataUnit - - -class EntityModel(BaseModel): - """Basic entity model.""" - - class Config: - """Do not allow extra fields.""" - - extra = Extra.forbid - - -class CPUEmulationMode(StrEnum): - """CPU emulation mode enumerated.""" - - HOST_PASSTHROUGH = 'host-passthrough' - HOST_MODEL = 'host-model' - CUSTOM = 'custom' - MAXIMUM = 'maximum' - - -class CPUTopologySchema(EntityModel): - """CPU topology model.""" - - sockets: int - cores: int - threads: int - dies: int = 1 - - -class CPUFeaturesSchema(EntityModel): - """CPU features model.""" - - require: list[str] - disable: list[str] - - -class CPUSchema(EntityModel): - """CPU model.""" - - emulation_mode: CPUEmulationMode - model: str | None - vendor: str | None - topology: CPUTopologySchema | None - features: CPUFeaturesSchema | None - - -class VolumeType(StrEnum): - """Storage volume types enumeration.""" - - FILE = 'file' - - -class VolumeCapacitySchema(EntityModel): - """Storage volume capacity field model.""" - - value: int - unit: DataUnit - - -class VolumeSchema(EntityModel): - """Storage volume model.""" - - type: VolumeType # noqa: A003 - target: str - capacity: VolumeCapacitySchema - source: str | None = None - is_readonly: bool = False - is_system: bool = False - - -class NetworkInterfaceSchema(EntityModel): - """Network inerface model.""" - - source: str - mac: str - - -class BootOptionsSchema(EntityModel): - """Instance boot settings.""" - - order: tuple - - -class InstanceSchema(EntityModel): - """Compute instance model.""" - - name: str - title: str | None - description: str | None - memory: int - max_memory: int - vcpus: int - max_vcpus: int - cpu: CPUSchema - machine: str - emulator: Path - arch: str - boot: BootOptionsSchema - volumes: list[VolumeSchema] - network_interfaces: list[NetworkInterfaceSchema] - image: str | None = None - - @validator('name') - def _check_name(cls, value: str) -> str: # noqa: N805 - if not re.match(r'^[a-z0-9_]+$', value): - msg = ( - 'Name can contain only lowercase letters, numbers ' - 'and underscore.' - ) - raise ValueError(msg) - return value - - @validator('cpu') - def _check_topology(cls, cpu: int, values: dict) -> CPUSchema: # noqa: N805 - topo = cpu.topology - max_vcpus = values['max_vcpus'] - if topo and topo.sockets * topo.cores * topo.threads != max_vcpus: - msg = f'CPU topology does not match with {max_vcpus=}' - raise ValueError(msg) - return cpu - - @validator('volumes') - def _check_volumes(cls, volumes: list) -> list: # noqa: N805 - if len([v for v in volumes if v.is_system is True]) != 1: - msg = 'volumes list must contain one system volume' - raise ValueError(msg) - vol_with_source = 0 - for vol in volumes: - if vol.is_system is True and vol.is_readonly is True: - msg = 'volume marked as system cannot be readonly' - raise ValueError(msg) - if vol.source is not None: - vol_with_source += 1 - return volumes - - @validator('network_interfaces') - def _check_network_interfaces(cls, value: list) -> list: # noqa: N805 - if not value: - msg = 'Network interfaces list must contain at least one element' - raise ValueError(msg) - return value diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/session.py b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/session.py deleted file mode 100644 index de5f900..0000000 --- a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/session.py +++ /dev/null @@ -1,286 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Hypervisor session manager.""" - -import logging -import os -from contextlib import AbstractContextManager -from types import TracebackType -from typing import Any, NamedTuple -from uuid import uuid4 - -import libvirt -from lxml import etree - -from .exceptions import ( - InstanceNotFoundError, - SessionError, - StoragePoolNotFoundError, -) -from .instance import Instance, InstanceConfig, InstanceSchema -from .storage import DiskConfig, StoragePool, VolumeConfig -from .utils import units - - -log = logging.getLogger(__name__) - - -class Capabilities(NamedTuple): - """Store domain capabilities info.""" - - arch: str - virt_type: str - emulator: str - machine: str - max_vcpus: int - cpu_vendor: str - cpu_model: str - cpu_features: dict - usable_cpus: list[dict] - - -class NodeInfo(NamedTuple): - """ - Store compute node info. - - See https://libvirt.org/html/libvirt-libvirt-host.html#virNodeInfo - NOTE: memory unit in libvirt docs is wrong! Actual unit is MiB. - """ - - arch: str - memory: int - cpus: int - mhz: int - nodes: int - sockets: int - cores: int - threads: int - - -class Session(AbstractContextManager): - """ - Hypervisor session context manager. - - :cvar IMAGES_POOL: images storage pool name taken from env - :cvar VOLUMES_POOL: volumes storage pool name taken from env - """ - - IMAGES_POOL = os.getenv('CMP_IMAGES_POOL') - VOLUMES_POOL = os.getenv('CMP_VOLUMES_POOL') - - def __init__(self, uri: str | None = None): - """ - Initialise session with hypervisor. - - :ivar str uri: libvirt connection URI. - :ivar libvirt.virConnect connection: libvirt connection object. - - :param uri: libvirt connection URI. - """ - self.uri = uri or 'qemu:///system' - self.connection = libvirt.open(self.uri) - - def __enter__(self): - """Return Session object.""" - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - exc_traceback: TracebackType | None, - ): - """Close the connection when leaving the context.""" - self.close() - - def close(self) -> None: - """Close connection to libvirt daemon.""" - self.connection.close() - - def get_node_info(self) -> NodeInfo: - """Return information about compute node.""" - info = self.connection.getInfo() - return NodeInfo( - arch=info[0], - memory=info[1], - cpus=info[2], - mhz=info[3], - nodes=info[4], - sockets=info[5], - cores=info[6], - threads=info[7], - ) - - def _cap_get_usable_cpus(self, xml: etree.Element) -> list[dict]: - x = xml.xpath('/domainCapabilities/cpu/mode[@name="custom"]')[0] - cpus = [] - for cpu in x.findall('model'): - if cpu.get('usable') == 'yes': - cpus.append( # noqa: PERF401 - { - 'vendor': cpu.get('vendor'), - 'model': cpu.text, - } - ) - return cpus - - def _cap_get_cpu_features(self, xml: etree.Element) -> dict: - x = xml.xpath('/domainCapabilities/cpu/mode[@name="host-model"]')[0] - require = [] - disable = [] - for feature in x.findall('feature'): - policy = feature.get('policy') - name = feature.get('name') - if policy == 'require': - require.append(name) - if policy == 'disable': - disable.append(name) - return {'require': require, 'disable': disable} - - def get_capabilities(self) -> Capabilities: - """Return capabilities e.g. arch, virt, emulator, etc.""" - prefix = '/domainCapabilities' - hprefix = f'{prefix}/cpu/mode[@name="host-model"]' - caps = etree.fromstring(self.connection.getDomainCapabilities()) # noqa: S320 - return Capabilities( - arch=caps.xpath(f'{prefix}/arch/text()')[0], - virt_type=caps.xpath(f'{prefix}/domain/text()')[0], - emulator=caps.xpath(f'{prefix}/path/text()')[0], - machine=caps.xpath(f'{prefix}/machine/text()')[0], - max_vcpus=int(caps.xpath(f'{prefix}/vcpu/@max')[0]), - cpu_vendor=caps.xpath(f'{hprefix}/vendor/text()')[0], - cpu_model=caps.xpath(f'{hprefix}/model/text()')[0], - cpu_features=self._cap_get_cpu_features(caps), - usable_cpus=self._cap_get_cpus(caps), - ) - - def create_instance(self, **kwargs: Any) -> Instance: - """ - Create and return new compute instance. - - :param name: Instance name. - :type name: str - :param title: Instance title for humans. - :type title: str - :param description: Some information about instance. - :type description: str - :param memory: Memory in MiB. - :type memory: int - :param max_memory: Maximum memory in MiB. - :type max_memory: int - :param vcpus: Number of vCPUs. - :type vcpus: int - :param max_vcpus: Maximum vCPUs. - :type max_vcpus: int - :param cpu: CPU configuration. See :class:`CPUSchema` for info. - :type cpu: dict - :param machine: QEMU emulated machine. - :type machine: str - :param emulator: Path to emulator. - :type emulator: str - :param arch: CPU architecture to virtualization. - :type arch: str - :param boot: Boot settings. See :class:`BootOptionsSchema`. - :type boot: dict - :param image: Source disk image name for system disk. - :type image: str - :param volumes: List of storage volume configs. For more info - see :class:`VolumeSchema`. - :type volumes: list[dict] - :param network_interfaces: List of virtual network interfaces - configs. See :class:`NetworkInterfaceSchema` for more info. - :type network_interfaces: list[dict] - """ - data = InstanceSchema(**kwargs) - config = InstanceConfig(data) - log.info('Define XML...') - log.info(config.to_xml()) - self.connection.defineXML(config.to_xml()) - log.info('Getting instance...') - instance = self.get_instance(config.name) - log.info('Creating volumes...') - for volume in data.volumes: - log.info('Creating volume=%s', volume) - capacity = units.to_bytes( - volume.capacity.value, volume.capacity.unit - ) - log.info('Connecting to images pool...') - images_pool = self.get_storage_pool(self.IMAGES_POOL) - log.info('Connecting to volumes pool...') - volumes_pool = self.get_storage_pool(self.VOLUMES_POOL) - log.info('Building volume configuration...') - if not volume.source: - vol_name = f'{uuid4()}.qcow2' - else: - vol_name = volume.source - vol_conf = VolumeConfig( - name=vol_name, - path=str(volumes_pool.path.joinpath(vol_name)), - capacity=capacity, - ) - log.info('Volume configuration is:\n %s', vol_conf.to_xml()) - if volume.is_system is True and data.image: - log.info( - "Volume is marked as 'system', start cloning image..." - ) - log.info('Get image %s', data.image) - image = images_pool.get_volume(data.image) - log.info('Cloning image into volumes pool...') - vol = volumes_pool.clone_volume(image, vol_conf) - log.info( - 'Resize cloned volume to specified size: %s', - capacity, - ) - vol.resize(capacity, unit=units.DataUnit.BYTES) - else: - log.info('Create volume...') - volumes_pool.create_volume(vol_conf) - log.info('Attaching volume to instance...') - instance.attach_device( - DiskConfig( - disk_type=volume.type, - source=vol_conf.path, - target=volume.target, - readonly=volume.is_readonly, - ) - ) - return instance - - def get_instance(self, name: str) -> Instance: - """Get compute instance by name.""" - try: - return Instance(self.connection.lookupByName(name)) - except libvirt.libvirtError as e: - if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN: - raise InstanceNotFoundError(name) from e - raise SessionError(e) from e - - def list_instances(self) -> list[Instance]: - """List all instances.""" - return [Instance(dom) for dom in self.connection.listAllDomains()] - - def get_storage_pool(self, name: str) -> StoragePool: - """Get storage pool by name.""" - try: - return StoragePool(self.connection.storagePoolLookupByName(name)) - except libvirt.libvirtError as e: - if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_POOL: - raise StoragePoolNotFoundError(name) from e - raise SessionError(e) from e - - def list_storage_pools(self) -> list[StoragePool]: - """List all strage pools.""" - return [StoragePool(p) for p in self.connection.listStoragePools()] diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/storage/__init__.py b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/storage/__init__.py deleted file mode 100644 index 34aae30..0000000 --- a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/storage/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -from .pool import StoragePool -from .volume import DiskConfig, Volume, VolumeConfig diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/storage/pool.py b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/storage/pool.py deleted file mode 100644 index cb17494..0000000 --- a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/storage/pool.py +++ /dev/null @@ -1,124 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Manage storage pools.""" - -import logging -from pathlib import Path -from typing import NamedTuple - -import libvirt -from lxml import etree - -from compute.exceptions import StoragePoolError, VolumeNotFoundError - -from .volume import Volume, VolumeConfig - - -log = logging.getLogger(__name__) - - -class StoragePoolUsageInfo(NamedTuple): - """Storage pool usage info.""" - - capacity: int - allocation: int - available: int - - -class StoragePool: - """Storage pool manipulating class.""" - - def __init__(self, pool: libvirt.virStoragePool): - """Initislise StoragePool.""" - self.pool = pool - self.name = pool.name() - self.path = self._get_path() - - def _get_path(self) -> Path: - """Return storage pool path.""" - xml = etree.fromstring(self.pool.XMLDesc()) # noqa: S320 - return Path(xml.xpath('/pool/target/path/text()')[0]) - - def get_usage_info(self) -> StoragePoolUsageInfo: - """Return info about storage pool usage.""" - xml = etree.fromstring(self.pool.XMLDesc()) # noqa: S320 - return StoragePoolUsageInfo( - capacity=int(xml.xpath('/pool/capacity/text()')[0]), - allocation=int(xml.xpath('/pool/allocation/text()')[0]), - available=int(xml.xpath('/pool/available/text()')[0]), - ) - - def dump_xml(self) -> str: - """Return storage pool XML description as string.""" - return self.pool.XMLDesc() - - def refresh(self) -> None: - """Refresh storage pool.""" - # TODO @ge: handle libvirt asynchronous job related exceptions - self.pool.refresh() - - def create_volume(self, vol_conf: VolumeConfig) -> Volume: - """Create storage volume and return Volume instance.""" - log.info( - 'Create storage volume vol=%s in pool=%s', vol_conf.name, self.name - ) - vol = self.pool.createXML( - vol_conf.to_xml(), - flags=libvirt.VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, - ) - return Volume(self.pool, vol) - - def clone_volume(self, src: Volume, dst: VolumeConfig) -> Volume: - """ - Make storage volume copy. - - :param src: Input volume - :param dst: Output volume config - """ - log.info( - 'Start volume cloning ' - 'src_pool=%s src_vol=%s dst_pool=%s dst_vol=%s', - src.pool_name, - src.name, - self.pool.name, - dst.name, - ) - vol = self.pool.createXMLFrom( - dst.to_xml(), # new volume XML description - src.vol, # source volume virStorageVol object - flags=libvirt.VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, - ) - if vol is None: - raise StoragePoolError - return Volume(self.pool, vol) - - def get_volume(self, name: str) -> Volume | None: - """Lookup and return Volume instance or None.""" - log.info( - 'Lookup for storage volume vol=%s in pool=%s', name, self.pool.name - ) - try: - vol = self.pool.storageVolLookupByName(name) - return Volume(self.pool, vol) - except libvirt.libvirtError as e: - if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_VOL: - raise VolumeNotFoundError(name) from e - log.exception('unexpected error from libvirt') - raise StoragePoolError(e) from e - - def list_volumes(self) -> list[Volume]: - """Return list of volumes in storage pool.""" - return [Volume(self.pool, vol) for vol in self.pool.listAllVolumes()] diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/storage/volume.py b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/storage/volume.py deleted file mode 100644 index 11a1dc4..0000000 --- a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/storage/volume.py +++ /dev/null @@ -1,138 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Manage storage volumes.""" - -from dataclasses import dataclass -from pathlib import Path -from time import time - -import libvirt -from lxml import etree -from lxml.builder import E - -from compute.common import DeviceConfig, EntityConfig -from compute.utils import units - - -@dataclass -class VolumeConfig(EntityConfig): - """ - Storage volume XML config builder. - - Generate XML config for creating a volume in a libvirt - storage pool. - """ - - name: str - path: str - capacity: int - - def to_xml(self) -> str: - """Return XML config for libvirt.""" - unixtime = str(int(time())) - xml = E.volume(type='file') - xml.append(E.name(self.name)) - xml.append(E.key(self.path)) - xml.append(E.source()) - xml.append(E.capacity(str(self.capacity), unit='bytes')) - xml.append(E.allocation('0')) - xml.append( - E.target( - E.path(self.path), - E.format(type='qcow2'), - E.timestamps( - E.atime(unixtime), E.mtime(unixtime), E.ctime(unixtime) - ), - E.compat('1.1'), - E.features(E.lazy_refcounts()), - ) - ) - return etree.tostring(xml, encoding='unicode', pretty_print=True) - - -@dataclass -class DiskConfig(DeviceConfig): - """ - Disk XML config builder. - - Generate XML config for attaching or detaching storage volumes - to compute instances. - """ - - disk_type: str - source: str | Path - target: str - readonly: bool = False - - def to_xml(self) -> str: - """Return XML config for libvirt.""" - xml = E.disk(type=self.disk_type, device='disk') - xml.append(E.driver(name='qemu', type='qcow2', cache='writethrough')) - if self.disk_type == 'file': - xml.append(E.source(file=str(self.source))) - xml.append(E.target(dev=self.target, bus='virtio')) - if self.readonly: - xml.append(E.readonly()) - return etree.tostring(xml, encoding='unicode', pretty_print=True) - - -class Volume: - """Storage volume manipulating class.""" - - def __init__( - self, pool: libvirt.virStoragePool, vol: libvirt.virStorageVol - ): - """ - Initialise Volume. - - :param pool: libvirt virStoragePool object - :param vol: libvirt virStorageVol object - """ - self.pool = pool - self.pool_name = pool.name() - self.vol = vol - self.name = vol.name() - self.path = Path(vol.path()) - - def dump_xml(self) -> str: - """Return volume XML description as string.""" - return self.vol.XMLDesc() - - def clone(self, vol_conf: VolumeConfig) -> None: - """ - Make a copy of volume to the same storage pool. - - :param vol_info VolumeInfo: New storage volume dataclass object - """ - self.pool.createXMLFrom( - vol_conf.to_xml(), - self.vol, - flags=libvirt.VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, - ) - - def resize(self, capacity: int, unit: units.DataUnit) -> None: - """ - Resize volume. - - :param capacity int: Volume new capacity. - :param unit DataUnit: Data unit. Internally converts into bytes. - """ - # TODO @ge: Check actual volume size before resize - self.vol.resize(units.to_bytes(capacity, unit=unit)) - - def delete(self) -> None: - """Delete volume from storage pool.""" - self.vol.delete() diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/utils/__init__.py b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/utils/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/utils/config_loader.py b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/utils/config_loader.py deleted file mode 100644 index aaeb0fe..0000000 --- a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/utils/config_loader.py +++ /dev/null @@ -1,56 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Configuration loader.""" - -import tomllib -from collections import UserDict -from pathlib import Path - -from compute.exceptions import ConfigLoaderError - - -DEFAULT_CONFIGURATION = {} -DEFAULT_CONFIG_FILE = '/etc/computed/computed.toml' - - -class ConfigLoader(UserDict): - """UserDict for storing configuration.""" - - def __init__(self, file: Path | None = None): - """ - Initialise ConfigLoader. - - :param file: Path to configuration file. If `file` is None - use default path from DEFAULT_CONFIG_FILE constant. - """ - # TODO @ge: load deafult configuration - self.file = Path(file) if file else Path(DEFAULT_CONFIG_FILE) - super().__init__(self.load()) - - def load(self) -> dict: - """Load confguration object from TOML file.""" - try: - with Path(self.file).open('rb') as configfile: - return tomllib.load(configfile) - # TODO @ge: add config schema validation - except tomllib.TOMLDecodeError as tomlerr: - raise ConfigLoaderError( - f'Bad TOML syntax in config file: {self.file}: {tomlerr}' - ) from tomlerr - except (OSError, ValueError) as readerr: - raise ConfigLoaderError( - f'Cannot read config file: {self.file}: {readerr}' - ) from readerr diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/utils/ids.py b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/utils/ids.py deleted file mode 100644 index 8a6454a..0000000 --- a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/utils/ids.py +++ /dev/null @@ -1,33 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Random identificators.""" - -# ruff: noqa: S311, C417 - -import random - - -def random_mac() -> str: - """Retrun random MAC address.""" - mac = [ - 0x00, - 0x16, - 0x3E, - random.randint(0x00, 0x7F), - random.randint(0x00, 0xFF), - random.randint(0x00, 0xFF), - ] - return ':'.join(map(lambda x: '%02x' % x, mac)) diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/utils/units.py b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/utils/units.py deleted file mode 100644 index 57a4583..0000000 --- a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/build/compute/utils/units.py +++ /dev/null @@ -1,54 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Tools for data units convertion.""" - -from enum import StrEnum - - -class DataUnit(StrEnum): - """Data units enumerated.""" - - BYTES = 'bytes' - KIB = 'KiB' - MIB = 'MiB' - GIB = 'GiB' - TIB = 'TiB' - - -class InvalidDataUnitError(ValueError): - """Data unit is not valid.""" - - def __init__(self, msg: str): - """Initialise InvalidDataUnitError.""" - super().__init__( - f'{msg}, valid units are: {", ".join(list(DataUnit))}' - ) - - -def to_bytes(value: int, unit: DataUnit = DataUnit.BYTES) -> int: - """Convert value to bytes. See :class:`DataUnit`.""" - try: - _ = DataUnit(unit) - except ValueError as e: - raise InvalidDataUnitError(e) from e - powers = { - DataUnit.BYTES: 0, - DataUnit.KIB: 1, - DataUnit.MIB: 2, - DataUnit.GIB: 3, - DataUnit.TIB: 4, - } - return value * pow(1024, powers[unit]) diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/compute-0.1.0.dev1-py3-none-any.whl b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/compute-0.1.0.dev1-py3-none-any.whl deleted file mode 100644 index acf2d647ea5aed7660809b61bc9dc2491bbe1720..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30693 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 diff --git a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/scripts/compute b/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/scripts/compute deleted file mode 100755 index 56e33f2..0000000 --- a/packaging/build/compute-0.1.0.dev1/.pybuild/cpython3_3.11/scripts/compute +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/python3 -# -*- coding: utf-8 -*- -import re -import sys -from compute.cli.control import cli -if __name__ == "__main__": - sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) - sys.exit(cli()) diff --git a/packaging/build/compute-0.1.0.dev1/PKG-INFO b/packaging/build/compute-0.1.0.dev1/PKG-INFO deleted file mode 100644 index f4c22ad..0000000 --- a/packaging/build/compute-0.1.0.dev1/PKG-INFO +++ /dev/null @@ -1,81 +0,0 @@ -Metadata-Version: 2.1 -Name: compute -Version: 0.1.0.dev1 -Summary: Compute instances management library and tools -Author: ge -Author-email: ge@nixhacks.net -Requires-Python: >=3.11,<4.0 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.11 -Requires-Dist: libvirt-python (==9.0.0) -Requires-Dist: lxml (>=4.9.2,<5.0.0) -Requires-Dist: pydantic (==1.10.4) -Requires-Dist: pyyaml (>=6.0.1,<7.0.0) -Description-Content-Type: text/markdown - -# Compute - -Compute instances management library and tools. - -## Docs - -Run `make serve-docs`. See [Development](#development) below. - -## Roadmap - -- [x] Create instances -- [ ] CDROM -- [ ] cloud-init for provisioning instances -- [x] Instance power management -- [x] Instance pause and resume -- [x] vCPU hotplug -- [x] Memory hotplug -- [x] Hot disk resize [not tested] -- [ ] CPU topology customization -- [x] CPU customization (emulation mode, model, vendor, features) -- [ ] BIOS/UEFI settings -- [x] Device attaching -- [x] Device detaching -- [ ] GPU passthrough -- [ ] CPU guarantied resource percent support -- [x] QEMU Guest Agent management -- [ ] Instance resources usage stats -- [ ] SSH-keys management -- [x] Setting user passwords in guest -- [x] QCOW2 disks support -- [ ] ZVOL support -- [ ] Network disks support -- [ ] Images service integration (Images service is not implemented yet) -- [ ] Manage storage pools -- [ ] Idempotency -- [ ] CLI [in progress] -- [ ] HTTP API -- [ ] Instance migrations -- [ ] Instance snapshots -- [ ] Instance backups -- [ ] LXC - -## Development - -Python 3.11+ is required. - -Install [poetry](https://python-poetry.org/), clone this repository and run: - -``` -poetry install --with dev --with docs -``` - -# Build Debian package - -Install Docker first, then run: - -``` -make build-deb -``` - -`compute` and `compute-doc` packages will built. See packaging/build directory. Packages can be installed via `dpkg` or `apt-get`: - -``` -apt-get install ./compute*.deb -``` - diff --git a/packaging/build/compute-0.1.0.dev1/README.md b/packaging/build/compute-0.1.0.dev1/README.md deleted file mode 100644 index 0131e8e..0000000 --- a/packaging/build/compute-0.1.0.dev1/README.md +++ /dev/null @@ -1,65 +0,0 @@ -# Compute - -Compute instances management library and tools. - -## Docs - -Run `make serve-docs`. See [Development](#development) below. - -## Roadmap - -- [x] Create instances -- [ ] CDROM -- [ ] cloud-init for provisioning instances -- [x] Instance power management -- [x] Instance pause and resume -- [x] vCPU hotplug -- [x] Memory hotplug -- [x] Hot disk resize [not tested] -- [ ] CPU topology customization -- [x] CPU customization (emulation mode, model, vendor, features) -- [ ] BIOS/UEFI settings -- [x] Device attaching -- [x] Device detaching -- [ ] GPU passthrough -- [ ] CPU guarantied resource percent support -- [x] QEMU Guest Agent management -- [ ] Instance resources usage stats -- [ ] SSH-keys management -- [x] Setting user passwords in guest -- [x] QCOW2 disks support -- [ ] ZVOL support -- [ ] Network disks support -- [ ] Images service integration (Images service is not implemented yet) -- [ ] Manage storage pools -- [ ] Idempotency -- [ ] CLI [in progress] -- [ ] HTTP API -- [ ] Instance migrations -- [ ] Instance snapshots -- [ ] Instance backups -- [ ] LXC - -## Development - -Python 3.11+ is required. - -Install [poetry](https://python-poetry.org/), clone this repository and run: - -``` -poetry install --with dev --with docs -``` - -# Build Debian package - -Install Docker first, then run: - -``` -make build-deb -``` - -`compute` and `compute-doc` packages will built. See packaging/build directory. Packages can be installed via `dpkg` or `apt-get`: - -``` -apt-get install ./compute*.deb -``` diff --git a/packaging/build/compute-0.1.0.dev1/compute/__init__.py b/packaging/build/compute-0.1.0.dev1/compute/__init__.py deleted file mode 100644 index ffe06d7..0000000 --- a/packaging/build/compute-0.1.0.dev1/compute/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Compute instances management library.""" - -__version__ = '0.1.0-dev1' - -from .instance import Instance, InstanceConfig, InstanceSchema -from .session import Session -from .storage import StoragePool, Volume, VolumeConfig diff --git a/packaging/build/compute-0.1.0.dev1/compute/__main__.py b/packaging/build/compute-0.1.0.dev1/compute/__main__.py deleted file mode 100644 index 4995fbd..0000000 --- a/packaging/build/compute-0.1.0.dev1/compute/__main__.py +++ /dev/null @@ -1,21 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Command line interface for compute module.""" - -from compute.cli import main - - -main.cli() diff --git a/packaging/build/compute-0.1.0.dev1/compute/cli/__init__.py b/packaging/build/compute-0.1.0.dev1/compute/cli/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/packaging/build/compute-0.1.0.dev1/compute/cli/control.py b/packaging/build/compute-0.1.0.dev1/compute/cli/control.py deleted file mode 100644 index f5a5b91..0000000 --- a/packaging/build/compute-0.1.0.dev1/compute/cli/control.py +++ /dev/null @@ -1,501 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Command line interface.""" - -import argparse -import io -import logging -import os -import shlex -import sys -from collections import UserDict -from typing import Any -from uuid import uuid4 - -import libvirt -import yaml -from pydantic import ValidationError - -from compute import __version__ -from compute.exceptions import ComputeError, GuestAgentTimeoutExceededError -from compute.instance import GuestAgent -from compute.session import Session -from compute.utils import ids - - -log = logging.getLogger(__name__) -log_levels = [lv.lower() for lv in logging.getLevelNamesMapping()] - -libvirt.registerErrorHandler( - lambda userdata, err: None, # noqa: ARG005 - ctx=None, -) - - -class Table: - """Minimalistic text table constructor.""" - - def __init__(self, whitespace: str | None = None): - """Initialise Table.""" - self.whitespace = whitespace or '\t' - self.header = [] - self.rows = [] - self.table = '' - - def add_row(self, row: list) -> None: - """Add table row.""" - self.rows.append([str(col) for col in row]) - - def add_rows(self, rows: list[list]) -> None: - """Add multiple rows.""" - for row in rows: - self.add_row(row) - - def __str__(self) -> str: - """Build table and return.""" - widths = [max(map(len, col)) for col in zip(*self.rows, strict=True)] - self.rows.insert(0, [str(h).upper() for h in self.header]) - for row in self.rows: - self.table += self.whitespace.join( - ( - val.ljust(width) - for val, width in zip(row, widths, strict=True) - ) - ) - self.table += '\n' - return self.table.strip() - - -def _list_instances(session: Session) -> None: - table = Table() - table.header = ['NAME', 'STATE'] - for instance in session.list_instances(): - table.add_row( - [ - instance.name, - instance.get_status(), - ] - ) - print(table) - sys.exit() - - -def _exec_guest_agent_command( - session: Session, args: argparse.Namespace -) -> None: - instance = session.get_instance(args.instance) - ga = GuestAgent(instance.domain, timeout=args.timeout) - arguments = args.arguments.copy() - if len(arguments) > 1 and not args.no_join_args: - arguments = [shlex.join(arguments)] - if not args.no_join_args: - arguments.insert(0, '-c') - stdin = None - if not sys.stdin.isatty(): - stdin = sys.stdin.read() - try: - output = ga.guest_exec( - path=args.executable, - args=arguments, - env=args.env, - stdin=stdin, - capture_output=True, - decode_output=True, - poll=True, - ) - except GuestAgentTimeoutExceededError as e: - sys.exit( - f'{e}. NOTE: command may still running in guest, ' - f'PID={ga.last_pid}' - ) - if output.stderr: - print(output.stderr.strip(), file=sys.stderr) - if output.stdout: - print(output.stdout.strip(), file=sys.stdout) - sys.exit(output.exitcode) - - -class _NotPresent: - """ - Type for representing non-existent dictionary keys. - - See :class:`_FillableDict`. - """ - - -class _FillableDict(UserDict): - """Use :method:`fill` to add key if not present.""" - - def __init__(self, data: dict): - self.data = data - - def fill(self, key: str, value: Any) -> None: # noqa: ANN401 - if self.data.get(key, _NotPresent) is _NotPresent: - self.data[key] = value - - -def _merge_dicts(a: dict, b: dict, path: list[str] | None = None) -> dict: - """Merge `b` into `a`. Return modified `a`.""" - if path is None: - path = [] - for key in b: - if key in a: - if isinstance(a[key], dict) and isinstance(b[key], dict): - _merge_dicts(a[key], b[key], [path + str(key)]) - elif a[key] == b[key]: - pass # same leaf value - else: - a[key] = b[key] # replace existing key's values - else: - a[key] = b[key] - return a - - -def _create_instance(session: Session, file: io.TextIOWrapper) -> None: - try: - data = _FillableDict(yaml.load(file.read(), Loader=yaml.SafeLoader)) - log.debug('Read from file: %s', data) - except yaml.YAMLError as e: - sys.exit(f'error: cannot parse YAML: {e}') - - capabilities = session.get_capabilities() - node_info = session.get_node_info() - - data.fill('name', uuid4().hex) - data.fill('title', None) - data.fill('description', None) - data.fill('arch', capabilities.arch) - data.fill('machine', capabilities.machine) - data.fill('emulator', capabilities.emulator) - data.fill('max_vcpus', node_info.cpus) - data.fill('max_memory', node_info.memory) - data.fill('cpu', {}) - cpu = { - 'emulation_mode': 'host-passthrough', - 'model': None, - 'vendor': None, - 'topology': None, - 'features': None, - } - data['cpu'] = _merge_dicts(data['cpu'], cpu) - data.fill( - 'network_interfaces', - [{'source': 'default', 'mac': ids.random_mac()}], - ) - data.fill('boot', {'order': ['cdrom', 'hd']}) - - try: - log.debug('Input data: %s', data) - session.create_instance(**data) - except ValidationError as e: - for error in e.errors(): - fields = '.'.join([str(lc) for lc in error['loc']]) - print( - f"validation error: {fields}: {error['msg']}", - file=sys.stderr, - ) - sys.exit() - - -def _shutdown_instance(session: Session, args: argparse.Namespace) -> None: - instance = session.get_instance(args.instance) - if args.soft: - method = 'SOFT' - elif args.hard: - method = 'HARD' - elif args.unsafe: - method = 'UNSAFE' - else: - method = 'NORMAL' - instance.shutdown(method) - - -def main(session: Session, args: argparse.Namespace) -> None: - """Perform actions.""" - match args.command: - case 'init': - _create_instance(session, args.file) - case 'exec': - _exec_guest_agent_command(session, args) - case 'ls': - _list_instances(session) - case 'start': - instance = session.get_instance(args.instance) - instance.start() - case 'shutdown': - _shutdown_instance(session, args) - case 'reboot': - instance = session.get_instance(args.instance) - instance.reboot() - case 'reset': - instance = session.get_instance(args.instance) - instance.reset() - case 'powrst': - instance = session.get_instance(args.instance) - instance.power_reset() - case 'pause': - instance = session.get_instance(args.instance) - instance.pause() - case 'resume': - instance = session.get_instance(args.instance) - instance.resume() - case 'status': - instance = session.get_instance(args.instance) - print(instance.status) - case 'setvcpus': - instance = session.get_instance(args.instance) - instance.set_vcpus(args.nvcpus, live=True) - case 'setmem': - instance = session.get_instance(args.instance) - instance.set_memory(args.memory, live=True) - case 'setpass': - instance = session.get_instance(args.instance) - instance.set_user_password( - args.username, - args.password, - encrypted=args.encrypted, - ) - - -def cli() -> None: # noqa: PLR0915 - """Return command line arguments parser.""" - root = argparse.ArgumentParser( - prog='compute', - description='manage compute instances', - formatter_class=argparse.RawTextHelpFormatter, - ) - root.add_argument( - '-v', - '--verbose', - action='store_true', - default=False, - help='enable verbose mode', - ) - root.add_argument( - '-c', - '--connect', - metavar='URI', - help='libvirt connection URI', - ) - root.add_argument( - '-l', - '--log-level', - type=str.lower, - metavar='LEVEL', - choices=log_levels, - help='log level', - ) - root.add_argument( - '-V', - '--version', - action='version', - version=__version__, - ) - subparsers = root.add_subparsers(dest='command', metavar='COMMAND') - - # init command - init = subparsers.add_parser( - 'init', help='initialise instance using YAML config file' - ) - init.add_argument( - 'file', - type=argparse.FileType('r', encoding='UTF-8'), - nargs='?', - default='instance.yaml', - help='instance config [default: instance.yaml]', - ) - - # exec subcommand - execute = subparsers.add_parser( - 'exec', - help='execute command in guest via guest agent', - description=( - 'NOTE: any argument after instance name will be passed into ' - 'guest as shell command.' - ), - ) - execute.add_argument('instance') - execute.add_argument('arguments', nargs=argparse.REMAINDER) - execute.add_argument( - '-t', - '--timeout', - type=int, - default=60, - help=( - 'waiting time in seconds for a command to be executed ' - 'in guest [default: 60]' - ), - ) - execute.add_argument( - '-x', - '--executable', - default='/bin/sh', - help='path to executable in guest [default: /bin/sh]', - ) - execute.add_argument( - '-e', - '--env', - type=str, - nargs='?', - action='append', - help='environment variables to pass to executable in guest', - ) - execute.add_argument( - '-n', - '--no-join-args', - action='store_true', - default=False, - help=( - "do not join arguments list and add '-c' option, suitable " - 'for non-shell executables and other specific cases.' - ), - ) - - # ls subcommand - listall = subparsers.add_parser('ls', help='list instances') - listall.add_argument( - '-a', - '--all', - action='store_true', - default=False, - help='list all instances including inactive', - ) - - # start subcommand - start = subparsers.add_parser('start', help='start instance') - start.add_argument('instance') - - # shutdown subcommand - shutdown = subparsers.add_parser('shutdown', help='shutdown instance') - shutdown.add_argument('instance') - shutdown_opts = shutdown.add_mutually_exclusive_group() - shutdown_opts.add_argument( - '-s', - '--soft', - action='store_true', - help='normal guest OS shutdown, guest agent is used', - ) - shutdown_opts.add_argument( - '-n', - '--normal', - action='store_true', - help='shutdown with hypervisor selected method [default]', - ) - shutdown_opts.add_argument( - '-H', - '--hard', - action='store_true', - help=( - "gracefully destroy instance, it's like long " - 'pressing the power button' - ), - ) - shutdown_opts.add_argument( - '-u', - '--unsafe', - action='store_true', - help=( - 'destroy instance, this is similar to a power outage ' - 'and may result in data loss or corruption' - ), - ) - - # reboot subcommand - reboot = subparsers.add_parser('reboot', help='reboot instance') - reboot.add_argument('instance') - - # reset subcommand - reset = subparsers.add_parser('reset', help='reset instance') - reset.add_argument('instance') - - # powrst subcommand - powrst = subparsers.add_parser('powrst', help='power reset instance') - powrst.add_argument('instance') - - # pause subcommand - pause = subparsers.add_parser('pause', help='pause instance') - pause.add_argument('instance') - - # resume subcommand - resume = subparsers.add_parser('resume', help='resume paused instance') - resume.add_argument('instance') - - # status subcommand - status = subparsers.add_parser('status', help='display instance status') - status.add_argument('instance') - - # setvcpus subcommand - setvcpus = subparsers.add_parser('setvcpus', help='set vCPU number') - setvcpus.add_argument('instance') - setvcpus.add_argument('nvcpus', type=int) - - # setmem subcommand - setmem = subparsers.add_parser('setmem', help='set memory size') - setmem.add_argument('instance') - setmem.add_argument('memory', type=int, help='memory in MiB') - - # setpass subcommand - setpass = subparsers.add_parser( - 'setpass', - help='set user password in guest', - ) - setpass.add_argument('instance') - setpass.add_argument('username') - setpass.add_argument('password') - setpass.add_argument( - '-e', - '--encrypted', - action='store_true', - default=False, - help='set it if password is already encrypted', - ) - - args = root.parse_args() - if args.command is None: - root.print_help() - sys.exit() - - log_level = args.log_level or os.getenv('CMP_LOG') - - if isinstance(log_level, str) and log_level.lower() in log_levels: - logging.basicConfig( - level=logging.getLevelNamesMapping()[log_level.upper()] - ) - - log.debug('CLI started with args: %s', args) - - connect_uri = ( - args.connect - or os.getenv('CMP_LIBVIRT_URI') - or os.getenv('LIBVIRT_DEFAULT_URI') - or 'qemu:///system' - ) - - try: - with Session(connect_uri) as session: - main(session, args) - except ComputeError as e: - sys.exit(f'error: {e}') - except KeyboardInterrupt: - sys.exit() - except SystemExit as e: - sys.exit(e) - except Exception as e: # noqa: BLE001 - sys.exit(f'unexpected error {type(e)}: {e}') - - -if __name__ == '__main__': - cli() diff --git a/packaging/build/compute-0.1.0.dev1/compute/common.py b/packaging/build/compute-0.1.0.dev1/compute/common.py deleted file mode 100644 index 34a339a..0000000 --- a/packaging/build/compute-0.1.0.dev1/compute/common.py +++ /dev/null @@ -1,30 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Common symbols.""" - -from abc import ABC, abstractmethod - - -class EntityConfig(ABC): - """An abstract entity XML config builder class.""" - - @abstractmethod - def to_xml(self) -> str: - """Return device XML config.""" - raise NotImplementedError - - -DeviceConfig = EntityConfig diff --git a/packaging/build/compute-0.1.0.dev1/compute/exceptions.py b/packaging/build/compute-0.1.0.dev1/compute/exceptions.py deleted file mode 100644 index 1eef8de..0000000 --- a/packaging/build/compute-0.1.0.dev1/compute/exceptions.py +++ /dev/null @@ -1,80 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Exceptions.""" - - -class ComputeError(Exception): - """Basic exception class.""" - - -class ConfigLoaderError(ComputeError): - """Something went wrong when loading configuration.""" - - -class SessionError(ComputeError): - """Something went wrong while connecting to libvirtd.""" - - -class GuestAgentError(ComputeError): - """Something went wring when QEMU Guest Agent call.""" - - -class GuestAgentUnavailableError(GuestAgentError): - """Guest agent is not connected or is unavailable.""" - - -class GuestAgentTimeoutExceededError(GuestAgentError): - """QEMU timeout exceeded.""" - - def __init__(self, msg: int): - """Initialise GuestAgentTimeoutExceededError.""" - super().__init__(f'QEMU timeout ({msg} sec) exceeded') - - -class GuestAgentCommandNotSupportedError(GuestAgentError): - """Guest agent command is not supported or blacklisted on guest.""" - - -class StoragePoolError(ComputeError): - """Something went wrong when operating with storage pool.""" - - -class StoragePoolNotFoundError(StoragePoolError): - """Storage pool not found.""" - - def __init__(self, msg: str): - """Initialise StoragePoolNotFoundError.""" - super().__init__(f"storage pool named '{msg}' not found") - - -class VolumeNotFoundError(StoragePoolError): - """Storage volume not found.""" - - def __init__(self, msg: str): - """Initialise VolumeNotFoundError.""" - super().__init__(f"storage volume '{msg}' not found") - - -class InstanceError(ComputeError): - """Something went wrong while interacting with the domain.""" - - -class InstanceNotFoundError(InstanceError): - """Virtual machine or container not found on compute node.""" - - def __init__(self, msg: str): - """Initialise InstanceNotFoundError.""" - super().__init__(f"compute instance '{msg}' not found") diff --git a/packaging/build/compute-0.1.0.dev1/compute/instance/__init__.py b/packaging/build/compute-0.1.0.dev1/compute/instance/__init__.py deleted file mode 100644 index 6e2b150..0000000 --- a/packaging/build/compute-0.1.0.dev1/compute/instance/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -from .guest_agent import GuestAgent -from .instance import Instance, InstanceConfig -from .schemas import InstanceSchema diff --git a/packaging/build/compute-0.1.0.dev1/compute/instance/guest_agent.py b/packaging/build/compute-0.1.0.dev1/compute/instance/guest_agent.py deleted file mode 100644 index 4381591..0000000 --- a/packaging/build/compute-0.1.0.dev1/compute/instance/guest_agent.py +++ /dev/null @@ -1,208 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Interacting with the QEMU Guest Agent.""" - -import json -import logging -from base64 import b64decode, standard_b64encode -from time import sleep, time -from typing import NamedTuple - -import libvirt -import libvirt_qemu - -from compute.exceptions import ( - GuestAgentCommandNotSupportedError, - GuestAgentError, - GuestAgentTimeoutExceededError, - GuestAgentUnavailableError, -) - - -log = logging.getLogger(__name__) - - -class GuestExecOutput(NamedTuple): - """QEMU guest-exec command output.""" - - exited: bool | None = None - exitcode: int | None = None - stdout: str | None = None - stderr: str | None = None - - -class GuestAgent: - """Class for interacting with QEMU guest agent.""" - - def __init__(self, domain: libvirt.virDomain, timeout: int = 60): - """ - Initialise GuestAgent. - - :param domain: Libvirt domain object - :param timeout: QEMU timeout - """ - self.domain = domain - self.timeout = timeout - self.flags = libvirt_qemu.VIR_DOMAIN_QEMU_MONITOR_COMMAND_DEFAULT - self.last_pid = None - - def execute(self, command: dict) -> dict: - """ - Execute QEMU guest agent command. - - See: https://qemu-project.gitlab.io/qemu/interop/qemu-ga-ref.html - - :param command: QEMU guest agent command as dict - :return: Command output - :rtype: dict - """ - log.debug(command) - try: - output = libvirt_qemu.qemuAgentCommand( - self.domain, json.dumps(command), self.timeout, self.flags - ) - return json.loads(output) - except libvirt.libvirtError as e: - if e.get_error_code() == libvirt.VIR_ERR_AGENT_UNRESPONSIVE: - raise GuestAgentUnavailableError(e) from e - raise GuestAgentError(e) from e - - def is_available(self) -> bool: - """ - Execute guest-ping. - - :return: True or False if guest agent is unreachable. - :rtype: bool - """ - try: - if self.execute({'execute': 'guest-ping', 'arguments': {}}): - return True - except GuestAgentError: - return False - - def get_supported_commands(self) -> set[str]: - """Return set of supported guest agent commands.""" - output = self.execute({'execute': 'guest-info', 'arguments': {}}) - return { - cmd['name'] - for cmd in output['return']['supported_commands'] - if cmd['enabled'] is True - } - - def raise_for_commands(self, commands: list[str]) -> None: - """ - Raise exception if QEMU GA command is not available. - - :param commands: List of required commands - :raise: GuestAgentCommandNotSupportedError - """ - supported = self.get_supported_commands() - for command in commands: - if command not in supported: - raise GuestAgentCommandNotSupportedError(command) - - def guest_exec( # noqa: PLR0913 - self, - path: str, - args: list[str] | None = None, - env: list[str] | None = None, - stdin: str | None = None, - *, - capture_output: bool = False, - decode_output: bool = False, - poll: bool = False, - ) -> GuestExecOutput: - """ - Execute qemu-exec command and return output. - - :param path: Path ot executable on guest. - :param arg: List of arguments to pass to executable. - :param env: List of environment variables to pass to executable. - For example: ``['LANG=C', 'TERM=xterm']`` - :param stdin: Data to pass to executable STDIN. - :param capture_output: Capture command output. - :param decode_output: Use base64_decode() to decode command output. - Affects only if `capture_output` is True. - :param poll: Poll command output. Uses `self.timeout` and - POLL_INTERVAL constant. - :return: Command output - :rtype: GuestExecOutput - """ - self.raise_for_commands(['guest-exec', 'guest-exec-status']) - command = { - 'execute': 'guest-exec', - 'arguments': { - 'path': path, - **({'arg': args} if args else {}), - **({'env': env} if env else {}), - **( - { - 'input-data': standard_b64encode( - stdin.encode('utf-8') - ).decode('utf-8') - } - if stdin - else {} - ), - 'capture-output': capture_output, - }, - } - output = self.execute(command) - self.last_pid = pid = output['return']['pid'] - command_status = self.guest_exec_status(pid, poll=poll)['return'] - exited = command_status['exited'] - exitcode = command_status['exitcode'] - stdout = command_status.get('out-data', None) - stderr = command_status.get('err-data', None) - if decode_output: - stdout = b64decode(stdout or '').decode('utf-8') - stderr = b64decode(stderr or '').decode('utf-8') - return GuestExecOutput(exited, exitcode, stdout, stderr) - - def guest_exec_status( - self, pid: int, *, poll: bool = False, poll_interval: float = 0.3 - ) -> dict: - """ - Execute guest-exec-status and return output. - - :param pid: PID in guest. - :param poll: If True poll command status. - :param poll_interval: Time between attempts to obtain command status. - :return: Command output - :rtype: dict - """ - self.raise_for_commands(['guest-exec-status']) - command = { - 'execute': 'guest-exec-status', - 'arguments': {'pid': pid}, - } - if not poll: - return self.execute(command) - start_time = time() - while True: - command_status = self.execute(command) - if command_status['return']['exited']: - break - sleep(poll_interval) - now = time() - if now - start_time > self.timeout: - raise GuestAgentTimeoutExceededError(self.timeout) - log.debug( - 'Polling command pid=%s finished, time taken: %s seconds', - pid, - int(time() - start_time), - ) - return command_status diff --git a/packaging/build/compute-0.1.0.dev1/compute/instance/instance.py b/packaging/build/compute-0.1.0.dev1/compute/instance/instance.py deleted file mode 100644 index 5b806e6..0000000 --- a/packaging/build/compute-0.1.0.dev1/compute/instance/instance.py +++ /dev/null @@ -1,675 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Manage compute instances.""" - -__all__ = ['Instance', 'InstanceConfig', 'InstanceInfo'] - -import logging -from typing import NamedTuple - -import libvirt -from lxml import etree -from lxml.builder import E - -from compute.common import DeviceConfig, EntityConfig -from compute.exceptions import ( - GuestAgentCommandNotSupportedError, - InstanceError, -) -from compute.storage import DiskConfig -from compute.utils import units - -from .guest_agent import GuestAgent -from .schemas import ( - CPUEmulationMode, - CPUSchema, - InstanceSchema, - NetworkInterfaceSchema, -) - - -log = logging.getLogger(__name__) - - -class InstanceConfig(EntityConfig): - """Compute instance XML config builder.""" - - def __init__(self, schema: InstanceSchema): - """ - Initialise InstanceConfig. - - :param schema: InstanceSchema object - """ - self.name = schema.name - self.title = schema.title - self.description = schema.description - self.memory = schema.memory - self.max_memory = schema.max_memory - self.vcpus = schema.vcpus - self.max_vcpus = schema.max_vcpus - self.cpu = schema.cpu - self.machine = schema.machine - self.emulator = schema.emulator - self.arch = schema.arch - self.boot = schema.boot - self.network_interfaces = schema.network_interfaces - - def _gen_cpu_xml(self, cpu: CPUSchema) -> etree.Element: - options = { - 'mode': cpu.emulation_mode, - 'match': 'exact', - 'check': 'partial', - } - if cpu.emulation_mode == CPUEmulationMode.HOST_PASSTHROUGH: - options['check'] = 'none' - options['migratable'] = 'on' - xml = E.cpu(**options) - if cpu.model: - xml.append(E.model(cpu.model, fallback='forbid')) - if cpu.vendor: - xml.append(E.vendor(cpu.vendor)) - if cpu.topology: - xml.append( - E.topology( - sockets=str(cpu.topology.sockets), - dies=str(cpu.topology.dies), - cores=str(cpu.topology.cores), - threads=str(cpu.topology.threads), - ) - ) - if cpu.features: - for feature in cpu.features.require: - xml.append(E.feature(policy='require', name=feature)) - for feature in cpu.features.disable: - xml.append(E.feature(policy='disable', name=feature)) - return xml - - def _gen_vcpus_xml(self, vcpus: int, max_vcpus: int) -> etree.Element: - xml = E.vcpus() - xml.append(E.vcpu(id='0', enabled='yes', hotpluggable='no', order='1')) - for i in range(max_vcpus - 1): - enabled = 'yes' if (i + 2) <= vcpus else 'no' - xml.append( - E.vcpu( - id=str(i + 1), - enabled=enabled, - hotpluggable='yes', - order=str(i + 2), - ) - ) - return xml - - def _gen_network_interface_xml( - self, interface: NetworkInterfaceSchema - ) -> etree.Element: - return E.interface( - E.source(network=interface.source), - E.mac(address=interface.mac), - type='network', - ) - - def to_xml(self) -> str: - """Return XML config for libvirt.""" - xml = E.domain(type='kvm') - xml.append(E.name(self.name)) - if self.title: - xml.append(E.title(self.title)) - if self.description: - xml.append(E.description(self.description)) - xml.append(E.metadata()) - xml.append(E.memory(str(self.max_memory * 1024), unit='KiB')) - xml.append(E.currentMemory(str(self.memory * 1024), unit='KiB')) - xml.append( - E.vcpu( - str(self.max_vcpus), - placement='static', - current=str(self.vcpus), - ) - ) - xml.append(self._gen_cpu_xml(self.cpu)) - os = E.os(E.type('hvm', machine=self.machine, arch=self.arch)) - for dev in self.boot.order: - os.append(E.boot(dev=dev)) - xml.append(os) - xml.append(E.features(E.acpi(), E.apic())) - xml.append(E.on_poweroff('destroy')) - xml.append(E.on_reboot('restart')) - xml.append(E.on_crash('restart')) - xml.append( - E.pm( - E('suspend-to-mem', enabled='no'), - E('suspend-to-disk', enabled='no'), - ) - ) - devices = E.devices() - devices.append(E.emulator(str(self.emulator))) - for interface in self.network_interfaces: - devices.append(self._gen_network_interface_xml(interface)) - devices.append(E.graphics(type='vnc', port='-1', autoport='yes')) - devices.append(E.input(type='tablet', bus='usb')) - devices.append( - E.channel( - E.source(mode='bind'), - E.target(type='virtio', name='org.qemu.guest_agent.0'), - E.address( - type='virtio-serial', controller='0', bus='0', port='1' - ), - type='unix', - ) - ) - devices.append( - E.console(E.target(type='serial', port='0'), type='pty') - ) - devices.append( - E.video( - E.model(type='vga', vram='16384', heads='1', primary='yes') - ) - ) - xml.append(devices) - return etree.tostring(xml, encoding='unicode', pretty_print=True) - - -class InstanceInfo(NamedTuple): - """ - Store compute instance info. - - Reference: - https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainInfo - """ - - state: str - max_memory: int - memory: int - nproc: int - cputime: int - - -class Instance: - """Manage compute instances.""" - - def __init__(self, domain: libvirt.virDomain): - """ - Initialise Instance. - - :ivar libvirt.virDomain domain: domain object - :ivar libvirt.virConnect connection: connection object - :ivar str name: domain name - :ivar GuestAgent guest_agent: :class:`GuestAgent` object - - :param domain: libvirt domain object - """ - self.domain = domain - self.connection = domain.connect() - self.name = domain.name() - self.guest_agent = GuestAgent(domain) - - def _expand_instance_state(self, state: int) -> str: - states = { - libvirt.VIR_DOMAIN_NOSTATE: 'nostate', - libvirt.VIR_DOMAIN_RUNNING: 'running', - libvirt.VIR_DOMAIN_BLOCKED: 'blocked', - libvirt.VIR_DOMAIN_PAUSED: 'paused', - libvirt.VIR_DOMAIN_SHUTDOWN: 'shutdown', - libvirt.VIR_DOMAIN_SHUTOFF: 'shutoff', - libvirt.VIR_DOMAIN_CRASHED: 'crashed', - libvirt.VIR_DOMAIN_PMSUSPENDED: 'pmsuspended', - } - return states[state] - - def get_info(self) -> InstanceInfo: - """Return instance info.""" - info = self.domain.info() - return InstanceInfo( - state=self._expand_instance_state(info[0]), - max_memory=info[1], - memory=info[2], - nproc=info[3], - cputime=info[4], - ) - - def get_status(self) -> str: - """ - Return instance state: 'running', 'shutoff', etc. - - Reference: - https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainState - """ - try: - state, _ = self.domain.state() - except libvirt.libvirtError as e: - raise InstanceError( - 'Cannot fetch status of ' f'instance={self.name}: {e}' - ) from e - return self._expand_instance_state(state) - - def is_running(self) -> bool: - """Return True if instance is running, else return False.""" - if self.domain.isActive() != 1: - # 0 - is inactive, -1 - is error - return False - return True - - def is_autostart(self) -> bool: - """Return True if instance autostart is enabled, else return False.""" - try: - return bool(self.domain.autostart()) - except libvirt.libvirtError as e: - raise InstanceError( - f'Cannot get autostart status for ' - f'instance={self.name}: {e}' - ) from e - - def get_max_memory(self) -> int: - """Maximum memory value for domain in KiB.""" - return self.domain.maxMemory() - - def get_max_vcpus(self) -> int: - """Maximum vCPUs number for domain.""" - return self.domain.maxVcpus() - - def start(self) -> None: - """Start defined instance.""" - log.info('Starting instnce=%s', self.name) - if self.is_running(): - log.warning( - 'Already started, nothing to do instance=%s', self.name - ) - return - try: - self.domain.create() - except libvirt.libvirtError as e: - raise InstanceError( - f'Cannot start instance={self.name}: {e}' - ) from e - - def shutdown(self, method: str | None = None) -> None: - """ - Shutdown instance. - - Shutdown methods: - - SOFT - Use guest agent to shutdown. If guest agent is unavailable - NORMAL method will be used. - - NORMAL - Use method choosen by hypervisor to shutdown. Usually send ACPI - signal to guest OS. OS may ignore ACPI e.g. if guest is hanged. - - HARD - Shutdown instance without any guest OS shutdown. This is simular - to unplugging machine from power. Internally send SIGTERM to - instance process and destroy it gracefully. - - UNSAFE - Force shutdown. Internally send SIGKILL to instance process. - There is high data corruption risk! - - If method is None NORMAL method will used. - - :param method: Method used to shutdown instance - """ - methods = { - 'SOFT': libvirt.VIR_DOMAIN_SHUTDOWN_GUEST_AGENT, - 'NORMAL': libvirt.VIR_DOMAIN_SHUTDOWN_DEFAULT, - 'HARD': libvirt.VIR_DOMAIN_DESTROY_GRACEFUL, - 'UNSAFE': libvirt.VIR_DOMAIN_DESTROY_DEFAULT, - } - if method is None: - method = 'NORMAL' - if not isinstance(method, str): - raise TypeError( - f"Shutdown method must be a 'str', not {type(method)}" - ) - method = method.upper() - if method not in methods: - raise ValueError(f"Unsupported shutdown method: '{method}'") - try: - if method in ['SOFT', 'NORMAL']: - self.domain.shutdownFlags(flags=methods[method]) - elif method in ['HARD', 'UNSAFE']: - self.domain.destroyFlags(flags=methods[method]) - except libvirt.libvirtError as e: - raise InstanceError( - f'Cannot shutdown instance={self.name} ' f'{method=}: {e}' - ) from e - - def reboot(self) -> None: - """Send ACPI signal to guest OS to reboot. OS may ignore this.""" - try: - self.domain.reboot() - except libvirt.libvirtError as e: - raise InstanceError( - f'Cannot reboot instance={self.name}: {e}' - ) from e - - def reset(self) -> None: - """ - Reset instance. - - Copypaste from libvirt doc: - - Reset a domain immediately without any guest OS shutdown. - Reset emulates the power reset button on a machine, where all - hardware sees the RST line set and reinitializes internal state. - - Note that there is a risk of data loss caused by reset without any - guest OS shutdown. - """ - try: - self.domain.reset() - except libvirt.libvirtError as e: - raise InstanceError( - f'Cannot reset instance={self.name}: {e}' - ) from e - - def power_reset(self) -> None: - """ - Shutdown instance and start. - - By analogy with real hardware, this is a normal server shutdown, - and then turning off from the power supply and turning it on again. - - This method is applicable in cases where there has been a - configuration change in libvirt and you need to restart the - instance to apply the new configuration. - """ - self.shutdown(method='NORMAL') - self.start() - - def set_autostart(self, *, enabled: bool) -> None: - """ - Set autostart flag for instance. - - :param enabled: Bool argument to set or unset autostart flag. - """ - autostart = 1 if enabled else 0 - try: - self.domain.setAutostart(autostart) - except libvirt.libvirtError as e: - raise InstanceError( - f'Cannot set autostart flag for instance={self.name} ' - f'{autostart=}: {e}' - ) from e - - def set_vcpus(self, nvcpus: int, *, live: bool = False) -> None: - """ - Set vCPU number. - - If `live` is True and instance is not currently running vCPUs - will set in config and will applied when instance boot. - - NB: Note that if this call is executed before the guest has - finished booting, the guest may fail to process the change. - - :param nvcpus: Number of vCPUs - :param live: Affect a running instance - """ - if nvcpus <= 0: - raise InstanceError('Cannot set zero vCPUs') - if nvcpus > self.get_max_vcpus(): - raise InstanceError('vCPUs count is greather than max_vcpus') - if nvcpus == self.get_info().nproc: - log.warning( - 'Instance instance=%s already have %s vCPUs, nothing to do', - self.name, - nvcpus, - ) - return - try: - flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG - self.domain.setVcpusFlags(nvcpus, flags=flags) - if live is True: - if not self.is_running(): - log.warning( - 'Instance is not running, changes applied in ' - 'instance config.' - ) - return - flags = libvirt.VIR_DOMAIN_AFFECT_LIVE - self.domain.setVcpusFlags(nvcpus, flags=flags) - if self.guest_agent.is_available(): - try: - self.guest_agent.raise_for_commands( - ['guest-set-vcpus'] - ) - flags = libvirt.VIR_DOMAIN_VCPU_GUEST - self.domain.setVcpusFlags(nvcpus, flags=flags) - except GuestAgentCommandNotSupportedError: - log.warning( - 'Cannot set vCPUs in guest via agent, you may ' - 'need to apply changes in guest manually.' - ) - else: - log.warning( - 'Cannot set vCPUs in guest OS on instance=%s. ' - 'You may need to apply CPUs in guest manually.', - self.name, - ) - except libvirt.libvirtError as e: - raise InstanceError( - f'Cannot set vCPUs for instance={self.name}: {e}' - ) from e - - def set_memory(self, memory: int, *, live: bool = False) -> None: - """ - Set memory. - - If `live` is True and instance is not currently running set memory - in config and will applied when instance boot. - - :param memory: Memory value in mebibytes - :param live: Affect a running instance - """ - if memory <= 0: - raise InstanceError('Cannot set zero memory') - if (memory * 1024) > self.get_max_memory(): - raise InstanceError('Memory is greather than max_memory') - if (memory * 1024) == self.get_info().memory: - log.warning( - "Instance '%s' already have %s memory, nothing to do", - self.name, - memory, - ) - return - if live and self.is_running(): - flags = ( - libvirt.VIR_DOMAIN_AFFECT_LIVE - | libvirt.VIR_DOMAIN_AFFECT_CONFIG - ) - else: - flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG - try: - self.domain.setMemoryFlags(memory * 1024, flags=flags) - except libvirt.libvirtError as e: - msg = f'Cannot set memory for instance={self.name} {memory=}: {e}' - raise InstanceError(msg) from e - - def _get_disk_by_target(self, target: str) -> etree.Element: - xml = etree.fromstring(self.dump_xml()) # noqa: S320 - child = xml.xpath(f'/domain/devices/disk/target[@dev="{target}"]') - return child[0].getparent() if child else None - - def attach_device( - self, device: DeviceConfig, *, live: bool = False - ) -> None: - """ - Attach device to compute instance. - - :param device: Object with device description e.g. DiskConfig - :param live: Affect a running instance - """ - if live and self.is_running(): - flags = ( - libvirt.VIR_DOMAIN_AFFECT_LIVE - | libvirt.VIR_DOMAIN_AFFECT_CONFIG - ) - else: - flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG - if isinstance(device, DiskConfig): # noqa: SIM102 - if self._get_disk_by_target(device.target): - log.warning( - "Volume with target '%s' is already attached", - device.target, - ) - return - self.domain.attachDeviceFlags(device.to_xml(), flags=flags) - - def detach_device( - self, device: DeviceConfig, *, live: bool = False - ) -> None: - """ - Dettach device from compute instance. - - :param device: Object with device description e.g. DiskConfig - :param live: Affect a running instance - """ - if live and self.is_running(): - flags = ( - libvirt.VIR_DOMAIN_AFFECT_LIVE - | libvirt.VIR_DOMAIN_AFFECT_CONFIG - ) - else: - flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG - if isinstance(device, DiskConfig): # noqa: SIM102 - if self._get_disk_by_target(device.target) is None: - log.warning( - "Volume with target '%s' is already detached", - device.target, - ) - return - self.domain.detachDeviceFlags(device.to_xml(), flags=flags) - - def detach_disk(self, name: str) -> None: - """ - Detach disk device by target name. - - There is no ``attach_disk()`` method. Use :func:`attach_device` - with :class:`DiskConfig` as argument. - - :param name: Disk name e.g. 'vda', 'sda', etc. This name may - not match the name of the disk inside the guest OS. - """ - xml = self._get_disk_by_target(name) - if xml is None: - log.warning( - "Volume with target '%s' is already detached", - name, - ) - return - disk_params = { - 'disk_type': xml.get('type'), - 'source': xml.find('source').get('file'), - 'target': xml.find('target').get('dev'), - 'readonly': False if xml.find('readonly') is None else True, # noqa: SIM211 - } - for param in disk_params: - if disk_params[param] is None: - msg = ( - f"Cannot detach volume with target '{name}': " - f"parameter '{param}' is not defined in libvirt XML " - 'config on host.' - ) - raise InstanceError(msg) - self.detach_device(DiskConfig(**disk_params), live=True) - - def resize_disk( - self, name: str, capacity: int, unit: units.DataUnit - ) -> None: - """ - Resize attached block device. - - :param name: Disk device name e.g. `vda`, `sda`, etc. - :param capacity: New capacity. - :param unit: Capacity unit. - """ - self.domain.blockResize( - name, - units.to_bytes(capacity, unit=unit), - flags=libvirt.VIR_DOMAIN_BLOCK_RESIZE_BYTES, - ) - - def get_disks(self) -> list[DiskConfig]: - """Return list of attached disks.""" - raise NotImplementedError - - def pause(self) -> None: - """Pause instance.""" - if not self.is_running(): - raise InstanceError('Cannot pause inactive instance') - self.domain.suspend() - - def resume(self) -> None: - """Resume paused instance.""" - self.domain.resume() - - def get_ssh_keys(self, user: str) -> list[str]: - """ - Return list of SSH keys on guest for specific user. - - :param user: Username. - """ - raise NotImplementedError - - def set_ssh_keys(self, user: str, ssh_keys: list[str]) -> None: - """ - Add SSH keys to guest for specific user. - - :param user: Username. - :param ssh_keys: List of public SSH keys. - """ - raise NotImplementedError - - def delete_ssh_keys(self, user: str, ssh_keys: list[str]) -> None: - """ - Remove SSH keys from guest for specific user. - - :param user: Username. - :param ssh_keys: List of public SSH keys. - """ - raise NotImplementedError - - def set_user_password( - self, user: str, password: str, *, encrypted: bool = False - ) -> None: - """ - Set new user password in guest OS. - - This action performs by guest agent inside the guest. - - :param user: Username. - :param password: Password. - :param encrypted: Set it to True if password is already encrypted. - Right encryption method depends on guest OS. - """ - if not self.guest_agent.is_available(): - raise InstanceError( - 'Cannot change password: guest agent is unavailable' - ) - self.guest_agent.raise_for_commands(['guest-set-user-password']) - flags = libvirt.VIR_DOMAIN_PASSWORD_ENCRYPTED if encrypted else 0 - self.domain.setUserPassword(user, password, flags=flags) - - def dump_xml(self, *, inactive: bool = False) -> str: - """Return instance XML description.""" - flags = libvirt.VIR_DOMAIN_XML_INACTIVE if inactive else 0 - return self.domain.XMLDesc(flags) - - def delete(self) -> None: - """Undefine instance.""" - # TODO @ge: delete local disks - self.shutdown(method='HARD') - self.domain.undefine() diff --git a/packaging/build/compute-0.1.0.dev1/compute/instance/schemas.py b/packaging/build/compute-0.1.0.dev1/compute/instance/schemas.py deleted file mode 100644 index f5a677c..0000000 --- a/packaging/build/compute-0.1.0.dev1/compute/instance/schemas.py +++ /dev/null @@ -1,165 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Compute instance related objects schemas.""" - -import re -from enum import StrEnum -from pathlib import Path - -from pydantic import BaseModel, Extra, validator - -from compute.utils.units import DataUnit - - -class EntityModel(BaseModel): - """Basic entity model.""" - - class Config: - """Do not allow extra fields.""" - - extra = Extra.forbid - - -class CPUEmulationMode(StrEnum): - """CPU emulation mode enumerated.""" - - HOST_PASSTHROUGH = 'host-passthrough' - HOST_MODEL = 'host-model' - CUSTOM = 'custom' - MAXIMUM = 'maximum' - - -class CPUTopologySchema(EntityModel): - """CPU topology model.""" - - sockets: int - cores: int - threads: int - dies: int = 1 - - -class CPUFeaturesSchema(EntityModel): - """CPU features model.""" - - require: list[str] - disable: list[str] - - -class CPUSchema(EntityModel): - """CPU model.""" - - emulation_mode: CPUEmulationMode - model: str | None - vendor: str | None - topology: CPUTopologySchema | None - features: CPUFeaturesSchema | None - - -class VolumeType(StrEnum): - """Storage volume types enumeration.""" - - FILE = 'file' - - -class VolumeCapacitySchema(EntityModel): - """Storage volume capacity field model.""" - - value: int - unit: DataUnit - - -class VolumeSchema(EntityModel): - """Storage volume model.""" - - type: VolumeType # noqa: A003 - target: str - capacity: VolumeCapacitySchema - source: str | None = None - is_readonly: bool = False - is_system: bool = False - - -class NetworkInterfaceSchema(EntityModel): - """Network inerface model.""" - - source: str - mac: str - - -class BootOptionsSchema(EntityModel): - """Instance boot settings.""" - - order: tuple - - -class InstanceSchema(EntityModel): - """Compute instance model.""" - - name: str - title: str | None - description: str | None - memory: int - max_memory: int - vcpus: int - max_vcpus: int - cpu: CPUSchema - machine: str - emulator: Path - arch: str - boot: BootOptionsSchema - volumes: list[VolumeSchema] - network_interfaces: list[NetworkInterfaceSchema] - image: str | None = None - - @validator('name') - def _check_name(cls, value: str) -> str: # noqa: N805 - if not re.match(r'^[a-z0-9_]+$', value): - msg = ( - 'Name can contain only lowercase letters, numbers ' - 'and underscore.' - ) - raise ValueError(msg) - return value - - @validator('cpu') - def _check_topology(cls, cpu: int, values: dict) -> CPUSchema: # noqa: N805 - topo = cpu.topology - max_vcpus = values['max_vcpus'] - if topo and topo.sockets * topo.cores * topo.threads != max_vcpus: - msg = f'CPU topology does not match with {max_vcpus=}' - raise ValueError(msg) - return cpu - - @validator('volumes') - def _check_volumes(cls, volumes: list) -> list: # noqa: N805 - if len([v for v in volumes if v.is_system is True]) != 1: - msg = 'volumes list must contain one system volume' - raise ValueError(msg) - vol_with_source = 0 - for vol in volumes: - if vol.is_system is True and vol.is_readonly is True: - msg = 'volume marked as system cannot be readonly' - raise ValueError(msg) - if vol.source is not None: - vol_with_source += 1 - return volumes - - @validator('network_interfaces') - def _check_network_interfaces(cls, value: list) -> list: # noqa: N805 - if not value: - msg = 'Network interfaces list must contain at least one element' - raise ValueError(msg) - return value diff --git a/packaging/build/compute-0.1.0.dev1/compute/session.py b/packaging/build/compute-0.1.0.dev1/compute/session.py deleted file mode 100644 index de5f900..0000000 --- a/packaging/build/compute-0.1.0.dev1/compute/session.py +++ /dev/null @@ -1,286 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Hypervisor session manager.""" - -import logging -import os -from contextlib import AbstractContextManager -from types import TracebackType -from typing import Any, NamedTuple -from uuid import uuid4 - -import libvirt -from lxml import etree - -from .exceptions import ( - InstanceNotFoundError, - SessionError, - StoragePoolNotFoundError, -) -from .instance import Instance, InstanceConfig, InstanceSchema -from .storage import DiskConfig, StoragePool, VolumeConfig -from .utils import units - - -log = logging.getLogger(__name__) - - -class Capabilities(NamedTuple): - """Store domain capabilities info.""" - - arch: str - virt_type: str - emulator: str - machine: str - max_vcpus: int - cpu_vendor: str - cpu_model: str - cpu_features: dict - usable_cpus: list[dict] - - -class NodeInfo(NamedTuple): - """ - Store compute node info. - - See https://libvirt.org/html/libvirt-libvirt-host.html#virNodeInfo - NOTE: memory unit in libvirt docs is wrong! Actual unit is MiB. - """ - - arch: str - memory: int - cpus: int - mhz: int - nodes: int - sockets: int - cores: int - threads: int - - -class Session(AbstractContextManager): - """ - Hypervisor session context manager. - - :cvar IMAGES_POOL: images storage pool name taken from env - :cvar VOLUMES_POOL: volumes storage pool name taken from env - """ - - IMAGES_POOL = os.getenv('CMP_IMAGES_POOL') - VOLUMES_POOL = os.getenv('CMP_VOLUMES_POOL') - - def __init__(self, uri: str | None = None): - """ - Initialise session with hypervisor. - - :ivar str uri: libvirt connection URI. - :ivar libvirt.virConnect connection: libvirt connection object. - - :param uri: libvirt connection URI. - """ - self.uri = uri or 'qemu:///system' - self.connection = libvirt.open(self.uri) - - def __enter__(self): - """Return Session object.""" - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - exc_traceback: TracebackType | None, - ): - """Close the connection when leaving the context.""" - self.close() - - def close(self) -> None: - """Close connection to libvirt daemon.""" - self.connection.close() - - def get_node_info(self) -> NodeInfo: - """Return information about compute node.""" - info = self.connection.getInfo() - return NodeInfo( - arch=info[0], - memory=info[1], - cpus=info[2], - mhz=info[3], - nodes=info[4], - sockets=info[5], - cores=info[6], - threads=info[7], - ) - - def _cap_get_usable_cpus(self, xml: etree.Element) -> list[dict]: - x = xml.xpath('/domainCapabilities/cpu/mode[@name="custom"]')[0] - cpus = [] - for cpu in x.findall('model'): - if cpu.get('usable') == 'yes': - cpus.append( # noqa: PERF401 - { - 'vendor': cpu.get('vendor'), - 'model': cpu.text, - } - ) - return cpus - - def _cap_get_cpu_features(self, xml: etree.Element) -> dict: - x = xml.xpath('/domainCapabilities/cpu/mode[@name="host-model"]')[0] - require = [] - disable = [] - for feature in x.findall('feature'): - policy = feature.get('policy') - name = feature.get('name') - if policy == 'require': - require.append(name) - if policy == 'disable': - disable.append(name) - return {'require': require, 'disable': disable} - - def get_capabilities(self) -> Capabilities: - """Return capabilities e.g. arch, virt, emulator, etc.""" - prefix = '/domainCapabilities' - hprefix = f'{prefix}/cpu/mode[@name="host-model"]' - caps = etree.fromstring(self.connection.getDomainCapabilities()) # noqa: S320 - return Capabilities( - arch=caps.xpath(f'{prefix}/arch/text()')[0], - virt_type=caps.xpath(f'{prefix}/domain/text()')[0], - emulator=caps.xpath(f'{prefix}/path/text()')[0], - machine=caps.xpath(f'{prefix}/machine/text()')[0], - max_vcpus=int(caps.xpath(f'{prefix}/vcpu/@max')[0]), - cpu_vendor=caps.xpath(f'{hprefix}/vendor/text()')[0], - cpu_model=caps.xpath(f'{hprefix}/model/text()')[0], - cpu_features=self._cap_get_cpu_features(caps), - usable_cpus=self._cap_get_cpus(caps), - ) - - def create_instance(self, **kwargs: Any) -> Instance: - """ - Create and return new compute instance. - - :param name: Instance name. - :type name: str - :param title: Instance title for humans. - :type title: str - :param description: Some information about instance. - :type description: str - :param memory: Memory in MiB. - :type memory: int - :param max_memory: Maximum memory in MiB. - :type max_memory: int - :param vcpus: Number of vCPUs. - :type vcpus: int - :param max_vcpus: Maximum vCPUs. - :type max_vcpus: int - :param cpu: CPU configuration. See :class:`CPUSchema` for info. - :type cpu: dict - :param machine: QEMU emulated machine. - :type machine: str - :param emulator: Path to emulator. - :type emulator: str - :param arch: CPU architecture to virtualization. - :type arch: str - :param boot: Boot settings. See :class:`BootOptionsSchema`. - :type boot: dict - :param image: Source disk image name for system disk. - :type image: str - :param volumes: List of storage volume configs. For more info - see :class:`VolumeSchema`. - :type volumes: list[dict] - :param network_interfaces: List of virtual network interfaces - configs. See :class:`NetworkInterfaceSchema` for more info. - :type network_interfaces: list[dict] - """ - data = InstanceSchema(**kwargs) - config = InstanceConfig(data) - log.info('Define XML...') - log.info(config.to_xml()) - self.connection.defineXML(config.to_xml()) - log.info('Getting instance...') - instance = self.get_instance(config.name) - log.info('Creating volumes...') - for volume in data.volumes: - log.info('Creating volume=%s', volume) - capacity = units.to_bytes( - volume.capacity.value, volume.capacity.unit - ) - log.info('Connecting to images pool...') - images_pool = self.get_storage_pool(self.IMAGES_POOL) - log.info('Connecting to volumes pool...') - volumes_pool = self.get_storage_pool(self.VOLUMES_POOL) - log.info('Building volume configuration...') - if not volume.source: - vol_name = f'{uuid4()}.qcow2' - else: - vol_name = volume.source - vol_conf = VolumeConfig( - name=vol_name, - path=str(volumes_pool.path.joinpath(vol_name)), - capacity=capacity, - ) - log.info('Volume configuration is:\n %s', vol_conf.to_xml()) - if volume.is_system is True and data.image: - log.info( - "Volume is marked as 'system', start cloning image..." - ) - log.info('Get image %s', data.image) - image = images_pool.get_volume(data.image) - log.info('Cloning image into volumes pool...') - vol = volumes_pool.clone_volume(image, vol_conf) - log.info( - 'Resize cloned volume to specified size: %s', - capacity, - ) - vol.resize(capacity, unit=units.DataUnit.BYTES) - else: - log.info('Create volume...') - volumes_pool.create_volume(vol_conf) - log.info('Attaching volume to instance...') - instance.attach_device( - DiskConfig( - disk_type=volume.type, - source=vol_conf.path, - target=volume.target, - readonly=volume.is_readonly, - ) - ) - return instance - - def get_instance(self, name: str) -> Instance: - """Get compute instance by name.""" - try: - return Instance(self.connection.lookupByName(name)) - except libvirt.libvirtError as e: - if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN: - raise InstanceNotFoundError(name) from e - raise SessionError(e) from e - - def list_instances(self) -> list[Instance]: - """List all instances.""" - return [Instance(dom) for dom in self.connection.listAllDomains()] - - def get_storage_pool(self, name: str) -> StoragePool: - """Get storage pool by name.""" - try: - return StoragePool(self.connection.storagePoolLookupByName(name)) - except libvirt.libvirtError as e: - if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_POOL: - raise StoragePoolNotFoundError(name) from e - raise SessionError(e) from e - - def list_storage_pools(self) -> list[StoragePool]: - """List all strage pools.""" - return [StoragePool(p) for p in self.connection.listStoragePools()] diff --git a/packaging/build/compute-0.1.0.dev1/compute/storage/__init__.py b/packaging/build/compute-0.1.0.dev1/compute/storage/__init__.py deleted file mode 100644 index 34aae30..0000000 --- a/packaging/build/compute-0.1.0.dev1/compute/storage/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -from .pool import StoragePool -from .volume import DiskConfig, Volume, VolumeConfig diff --git a/packaging/build/compute-0.1.0.dev1/compute/storage/pool.py b/packaging/build/compute-0.1.0.dev1/compute/storage/pool.py deleted file mode 100644 index cb17494..0000000 --- a/packaging/build/compute-0.1.0.dev1/compute/storage/pool.py +++ /dev/null @@ -1,124 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Manage storage pools.""" - -import logging -from pathlib import Path -from typing import NamedTuple - -import libvirt -from lxml import etree - -from compute.exceptions import StoragePoolError, VolumeNotFoundError - -from .volume import Volume, VolumeConfig - - -log = logging.getLogger(__name__) - - -class StoragePoolUsageInfo(NamedTuple): - """Storage pool usage info.""" - - capacity: int - allocation: int - available: int - - -class StoragePool: - """Storage pool manipulating class.""" - - def __init__(self, pool: libvirt.virStoragePool): - """Initislise StoragePool.""" - self.pool = pool - self.name = pool.name() - self.path = self._get_path() - - def _get_path(self) -> Path: - """Return storage pool path.""" - xml = etree.fromstring(self.pool.XMLDesc()) # noqa: S320 - return Path(xml.xpath('/pool/target/path/text()')[0]) - - def get_usage_info(self) -> StoragePoolUsageInfo: - """Return info about storage pool usage.""" - xml = etree.fromstring(self.pool.XMLDesc()) # noqa: S320 - return StoragePoolUsageInfo( - capacity=int(xml.xpath('/pool/capacity/text()')[0]), - allocation=int(xml.xpath('/pool/allocation/text()')[0]), - available=int(xml.xpath('/pool/available/text()')[0]), - ) - - def dump_xml(self) -> str: - """Return storage pool XML description as string.""" - return self.pool.XMLDesc() - - def refresh(self) -> None: - """Refresh storage pool.""" - # TODO @ge: handle libvirt asynchronous job related exceptions - self.pool.refresh() - - def create_volume(self, vol_conf: VolumeConfig) -> Volume: - """Create storage volume and return Volume instance.""" - log.info( - 'Create storage volume vol=%s in pool=%s', vol_conf.name, self.name - ) - vol = self.pool.createXML( - vol_conf.to_xml(), - flags=libvirt.VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, - ) - return Volume(self.pool, vol) - - def clone_volume(self, src: Volume, dst: VolumeConfig) -> Volume: - """ - Make storage volume copy. - - :param src: Input volume - :param dst: Output volume config - """ - log.info( - 'Start volume cloning ' - 'src_pool=%s src_vol=%s dst_pool=%s dst_vol=%s', - src.pool_name, - src.name, - self.pool.name, - dst.name, - ) - vol = self.pool.createXMLFrom( - dst.to_xml(), # new volume XML description - src.vol, # source volume virStorageVol object - flags=libvirt.VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, - ) - if vol is None: - raise StoragePoolError - return Volume(self.pool, vol) - - def get_volume(self, name: str) -> Volume | None: - """Lookup and return Volume instance or None.""" - log.info( - 'Lookup for storage volume vol=%s in pool=%s', name, self.pool.name - ) - try: - vol = self.pool.storageVolLookupByName(name) - return Volume(self.pool, vol) - except libvirt.libvirtError as e: - if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_VOL: - raise VolumeNotFoundError(name) from e - log.exception('unexpected error from libvirt') - raise StoragePoolError(e) from e - - def list_volumes(self) -> list[Volume]: - """Return list of volumes in storage pool.""" - return [Volume(self.pool, vol) for vol in self.pool.listAllVolumes()] diff --git a/packaging/build/compute-0.1.0.dev1/compute/storage/volume.py b/packaging/build/compute-0.1.0.dev1/compute/storage/volume.py deleted file mode 100644 index 11a1dc4..0000000 --- a/packaging/build/compute-0.1.0.dev1/compute/storage/volume.py +++ /dev/null @@ -1,138 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Manage storage volumes.""" - -from dataclasses import dataclass -from pathlib import Path -from time import time - -import libvirt -from lxml import etree -from lxml.builder import E - -from compute.common import DeviceConfig, EntityConfig -from compute.utils import units - - -@dataclass -class VolumeConfig(EntityConfig): - """ - Storage volume XML config builder. - - Generate XML config for creating a volume in a libvirt - storage pool. - """ - - name: str - path: str - capacity: int - - def to_xml(self) -> str: - """Return XML config for libvirt.""" - unixtime = str(int(time())) - xml = E.volume(type='file') - xml.append(E.name(self.name)) - xml.append(E.key(self.path)) - xml.append(E.source()) - xml.append(E.capacity(str(self.capacity), unit='bytes')) - xml.append(E.allocation('0')) - xml.append( - E.target( - E.path(self.path), - E.format(type='qcow2'), - E.timestamps( - E.atime(unixtime), E.mtime(unixtime), E.ctime(unixtime) - ), - E.compat('1.1'), - E.features(E.lazy_refcounts()), - ) - ) - return etree.tostring(xml, encoding='unicode', pretty_print=True) - - -@dataclass -class DiskConfig(DeviceConfig): - """ - Disk XML config builder. - - Generate XML config for attaching or detaching storage volumes - to compute instances. - """ - - disk_type: str - source: str | Path - target: str - readonly: bool = False - - def to_xml(self) -> str: - """Return XML config for libvirt.""" - xml = E.disk(type=self.disk_type, device='disk') - xml.append(E.driver(name='qemu', type='qcow2', cache='writethrough')) - if self.disk_type == 'file': - xml.append(E.source(file=str(self.source))) - xml.append(E.target(dev=self.target, bus='virtio')) - if self.readonly: - xml.append(E.readonly()) - return etree.tostring(xml, encoding='unicode', pretty_print=True) - - -class Volume: - """Storage volume manipulating class.""" - - def __init__( - self, pool: libvirt.virStoragePool, vol: libvirt.virStorageVol - ): - """ - Initialise Volume. - - :param pool: libvirt virStoragePool object - :param vol: libvirt virStorageVol object - """ - self.pool = pool - self.pool_name = pool.name() - self.vol = vol - self.name = vol.name() - self.path = Path(vol.path()) - - def dump_xml(self) -> str: - """Return volume XML description as string.""" - return self.vol.XMLDesc() - - def clone(self, vol_conf: VolumeConfig) -> None: - """ - Make a copy of volume to the same storage pool. - - :param vol_info VolumeInfo: New storage volume dataclass object - """ - self.pool.createXMLFrom( - vol_conf.to_xml(), - self.vol, - flags=libvirt.VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, - ) - - def resize(self, capacity: int, unit: units.DataUnit) -> None: - """ - Resize volume. - - :param capacity int: Volume new capacity. - :param unit DataUnit: Data unit. Internally converts into bytes. - """ - # TODO @ge: Check actual volume size before resize - self.vol.resize(units.to_bytes(capacity, unit=unit)) - - def delete(self) -> None: - """Delete volume from storage pool.""" - self.vol.delete() diff --git a/packaging/build/compute-0.1.0.dev1/compute/utils/__init__.py b/packaging/build/compute-0.1.0.dev1/compute/utils/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/packaging/build/compute-0.1.0.dev1/compute/utils/config_loader.py b/packaging/build/compute-0.1.0.dev1/compute/utils/config_loader.py deleted file mode 100644 index aaeb0fe..0000000 --- a/packaging/build/compute-0.1.0.dev1/compute/utils/config_loader.py +++ /dev/null @@ -1,56 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Configuration loader.""" - -import tomllib -from collections import UserDict -from pathlib import Path - -from compute.exceptions import ConfigLoaderError - - -DEFAULT_CONFIGURATION = {} -DEFAULT_CONFIG_FILE = '/etc/computed/computed.toml' - - -class ConfigLoader(UserDict): - """UserDict for storing configuration.""" - - def __init__(self, file: Path | None = None): - """ - Initialise ConfigLoader. - - :param file: Path to configuration file. If `file` is None - use default path from DEFAULT_CONFIG_FILE constant. - """ - # TODO @ge: load deafult configuration - self.file = Path(file) if file else Path(DEFAULT_CONFIG_FILE) - super().__init__(self.load()) - - def load(self) -> dict: - """Load confguration object from TOML file.""" - try: - with Path(self.file).open('rb') as configfile: - return tomllib.load(configfile) - # TODO @ge: add config schema validation - except tomllib.TOMLDecodeError as tomlerr: - raise ConfigLoaderError( - f'Bad TOML syntax in config file: {self.file}: {tomlerr}' - ) from tomlerr - except (OSError, ValueError) as readerr: - raise ConfigLoaderError( - f'Cannot read config file: {self.file}: {readerr}' - ) from readerr diff --git a/packaging/build/compute-0.1.0.dev1/compute/utils/ids.py b/packaging/build/compute-0.1.0.dev1/compute/utils/ids.py deleted file mode 100644 index 8a6454a..0000000 --- a/packaging/build/compute-0.1.0.dev1/compute/utils/ids.py +++ /dev/null @@ -1,33 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Random identificators.""" - -# ruff: noqa: S311, C417 - -import random - - -def random_mac() -> str: - """Retrun random MAC address.""" - mac = [ - 0x00, - 0x16, - 0x3E, - random.randint(0x00, 0x7F), - random.randint(0x00, 0xFF), - random.randint(0x00, 0xFF), - ] - return ':'.join(map(lambda x: '%02x' % x, mac)) diff --git a/packaging/build/compute-0.1.0.dev1/compute/utils/units.py b/packaging/build/compute-0.1.0.dev1/compute/utils/units.py deleted file mode 100644 index 57a4583..0000000 --- a/packaging/build/compute-0.1.0.dev1/compute/utils/units.py +++ /dev/null @@ -1,54 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Tools for data units convertion.""" - -from enum import StrEnum - - -class DataUnit(StrEnum): - """Data units enumerated.""" - - BYTES = 'bytes' - KIB = 'KiB' - MIB = 'MiB' - GIB = 'GiB' - TIB = 'TiB' - - -class InvalidDataUnitError(ValueError): - """Data unit is not valid.""" - - def __init__(self, msg: str): - """Initialise InvalidDataUnitError.""" - super().__init__( - f'{msg}, valid units are: {", ".join(list(DataUnit))}' - ) - - -def to_bytes(value: int, unit: DataUnit = DataUnit.BYTES) -> int: - """Convert value to bytes. See :class:`DataUnit`.""" - try: - _ = DataUnit(unit) - except ValueError as e: - raise InvalidDataUnitError(e) from e - powers = { - DataUnit.BYTES: 0, - DataUnit.KIB: 1, - DataUnit.MIB: 2, - DataUnit.GIB: 3, - DataUnit.TIB: 4, - } - return value * pow(1024, powers[unit]) diff --git a/packaging/build/compute-0.1.0.dev1/debian/.debhelper/generated/compute-doc/dh_installchangelogs.dch.trimmed b/packaging/build/compute-0.1.0.dev1/debian/.debhelper/generated/compute-doc/dh_installchangelogs.dch.trimmed deleted file mode 100644 index bb9efc5..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/.debhelper/generated/compute-doc/dh_installchangelogs.dch.trimmed +++ /dev/null @@ -1,5 +0,0 @@ -compute (0.1.0.dev1-1) UNRELEASED; urgency=medium - - * This is the development build, see commits in upstream repo for info. - - -- ge Wed, 22 Nov 2023 23:06:43 +0000 diff --git a/packaging/build/compute-0.1.0.dev1/debian/.debhelper/generated/compute-doc/installed-by-dh_installdocs b/packaging/build/compute-0.1.0.dev1/debian/.debhelper/generated/compute-doc/installed-by-dh_installdocs deleted file mode 100644 index e69de29..0000000 diff --git a/packaging/build/compute-0.1.0.dev1/debian/.debhelper/generated/compute/dh_installchangelogs.dch.trimmed b/packaging/build/compute-0.1.0.dev1/debian/.debhelper/generated/compute/dh_installchangelogs.dch.trimmed deleted file mode 100644 index bb9efc5..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/.debhelper/generated/compute/dh_installchangelogs.dch.trimmed +++ /dev/null @@ -1,5 +0,0 @@ -compute (0.1.0.dev1-1) UNRELEASED; urgency=medium - - * This is the development build, see commits in upstream repo for info. - - -- ge Wed, 22 Nov 2023 23:06:43 +0000 diff --git a/packaging/build/compute-0.1.0.dev1/debian/.debhelper/generated/compute/installed-by-dh_installdocs b/packaging/build/compute-0.1.0.dev1/debian/.debhelper/generated/compute/installed-by-dh_installdocs deleted file mode 100644 index c2dd0c3..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/.debhelper/generated/compute/installed-by-dh_installdocs +++ /dev/null @@ -1 +0,0 @@ -./README.md diff --git a/packaging/build/compute-0.1.0.dev1/debian/changelog b/packaging/build/compute-0.1.0.dev1/debian/changelog deleted file mode 100644 index bb9efc5..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/changelog +++ /dev/null @@ -1,5 +0,0 @@ -compute (0.1.0.dev1-1) UNRELEASED; urgency=medium - - * This is the development build, see commits in upstream repo for info. - - -- ge Wed, 22 Nov 2023 23:06:43 +0000 diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc.debhelper.log b/packaging/build/compute-0.1.0.dev1/debian/compute-doc.debhelper.log deleted file mode 100644 index 8dc2028..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc.debhelper.log +++ /dev/null @@ -1 +0,0 @@ -dh_sphinxdoc diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc.substvars b/packaging/build/compute-0.1.0.dev1/debian/compute-doc.substvars deleted file mode 100644 index c41bfd3..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc.substvars +++ /dev/null @@ -1,4 +0,0 @@ -sphinxdoc:Depends=libjs-sphinxdoc (>= 1.0), libjs-sphinxdoc (>= 2.4.3-5~), libjs-sphinxdoc (>= 5.0), libjs-sphinxdoc (>= 5.2) -sphinxdoc:Built-Using=alabaster (= 0.7.12-1), sphinx (= 5.3.0-4) -misc:Depends= -misc:Pre-Depends= diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/DEBIAN/control b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/DEBIAN/control deleted file mode 100644 index 72814c9..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/DEBIAN/control +++ /dev/null @@ -1,11 +0,0 @@ -Package: compute-doc -Source: compute -Version: 0.1.0.dev1-1 -Architecture: all -Maintainer: ge -Installed-Size: 376 -Depends: libjs-sphinxdoc (>= 5.2) -Section: doc -Priority: optional -Homepage: https://git.lulzette.ru/hstack/compute -Description: Compute instances management library and tools (documentation) diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/DEBIAN/md5sums b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/DEBIAN/md5sums deleted file mode 100644 index 5ab5be6..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/DEBIAN/md5sums +++ /dev/null @@ -1,40 +0,0 @@ -6845278a102bd147f30f770ed1134ce5 usr/share/doc/compute-doc/changelog.Debian.gz -fb1a6c11d7a8fa5f238617c20b13b6a1 usr/share/doc/compute-doc/copyright -705113edf19bbf7f9d406fccd98ebef9 usr/share/doc/compute-doc/html/_sources/index.rst.txt -91934f7b742b8395043e25cfa73682af usr/share/doc/compute-doc/html/_sources/pyapi/exceptions.rst.txt -de8bc1c2c00774ddee5363aef80c0775 usr/share/doc/compute-doc/html/_sources/pyapi/index.rst.txt -2a0040e0a150de53ed929e963af635a8 usr/share/doc/compute-doc/html/_sources/pyapi/instance/guest_agent.rst.txt -dd6324cb85dc57ef37c4f8161aa2d233 usr/share/doc/compute-doc/html/_sources/pyapi/instance/index.rst.txt -c594567565cc48a247932409d9adcc4a usr/share/doc/compute-doc/html/_sources/pyapi/instance/instance.rst.txt -e6a69ab447e455dba6e7b865a3d872d2 usr/share/doc/compute-doc/html/_sources/pyapi/instance/schemas.rst.txt -ba27654c086857e64d58468b13bc31c4 usr/share/doc/compute-doc/html/_sources/pyapi/session.rst.txt -801ccc953fc57199b06ec122e10f784c usr/share/doc/compute-doc/html/_sources/pyapi/storage/index.rst.txt -324ae7c877f3cf7895b2a5d3af579345 usr/share/doc/compute-doc/html/_sources/pyapi/storage/pool.rst.txt -db91c0d83c2c80e9f9323a8943eeeff4 usr/share/doc/compute-doc/html/_sources/pyapi/storage/volume.rst.txt -572ed749dd8924c36f1afe9e8e14d4d3 usr/share/doc/compute-doc/html/_sources/pyapi/utils.rst.txt -4fc9d553e40384beedf38e21f205d2a7 usr/share/doc/compute-doc/html/_static/alabaster.css -23ffe661f835b08e157d492a86aae74d usr/share/doc/compute-doc/html/_static/basic.css -dad0c9b31e59069c83018ce87594ed65 usr/share/doc/compute-doc/html/_static/custom.css -5e103d51310d4e0c065325d795cc9def usr/share/doc/compute-doc/html/_static/documentation_options.js -ba0c95766a77a6c598a7ca542f1db738 usr/share/doc/compute-doc/html/_static/file.png -5b6b3233153feca50a94aa6c60873a5f usr/share/doc/compute-doc/html/_static/forkme_right_darkblue_121621.png -36b1a4b05451c7acde7ced60b2f6bc21 usr/share/doc/compute-doc/html/_static/minus.png -0d7849fd4d4148b7f78cab60a087633a usr/share/doc/compute-doc/html/_static/plus.png -4f81be1c1dd97a6ec76af15b8f926189 usr/share/doc/compute-doc/html/_static/pygments.css -fd297228a19ece7e38824d0704f3635d usr/share/doc/compute-doc/html/genindex.html -3e038e6169c721ebacf889ea4ac5c1bf usr/share/doc/compute-doc/html/index.html -b8e4906e5136e907ab0d7ae826720603 usr/share/doc/compute-doc/html/objects.inv -2658558520c0c9f209dd4c69516facfd usr/share/doc/compute-doc/html/py-modindex.html -4254a2ecc3e154f52646febebd0ef6e6 usr/share/doc/compute-doc/html/pyapi/exceptions.html -bf4609f321d2c60399574c3e52dd6a44 usr/share/doc/compute-doc/html/pyapi/index.html -730aab71986cb938e9aff03ba203c9a9 usr/share/doc/compute-doc/html/pyapi/instance/guest_agent.html -fad8eba8a9cb9b1befd8e0ecdf1bbe5f usr/share/doc/compute-doc/html/pyapi/instance/index.html -781272676f0b35c52f43b99f2ca86647 usr/share/doc/compute-doc/html/pyapi/instance/instance.html -ede88501ec628083bb1ad1cb86cdec9f usr/share/doc/compute-doc/html/pyapi/instance/schemas.html -4c8d372d298068aba7272d11feb2cc52 usr/share/doc/compute-doc/html/pyapi/session.html -000f86f6184a455843017772ff2fec9d usr/share/doc/compute-doc/html/pyapi/storage/index.html -a2b63c0194a1e55be8d7036b46851986 usr/share/doc/compute-doc/html/pyapi/storage/pool.html -8d4e9081b213585aad36b4daadc37e26 usr/share/doc/compute-doc/html/pyapi/storage/volume.html -307d7a44f4343b0f34ee758e4ab20d88 usr/share/doc/compute-doc/html/pyapi/utils.html -5999199d4710213969f7fb1b50647f4a usr/share/doc/compute-doc/html/search.html -148b182d3691ae88c629783c3623007d usr/share/doc/compute-doc/html/searchindex.js diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/changelog.Debian.gz b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/changelog.Debian.gz deleted file mode 100644 index 40eae6fedeef605a8bc33ff14a672c4eec8e46c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 176 zcmV;h08jrPiwFP!000020}YJJ4uUWgME88fEPc_GVqD-On#j($@DbNoF3?C@LR+GL zZzr>woH^3!A$Y=!vy5?8)0Cyz9M9{myp*SVdEO$7EgAXSYpPYyNdheJ=#)dO?+Ecj zy&W_ek9Sagy@Dfxv|1}4DT6RLKT@SJ(qPfpF^-L8QI)1>3A>h#Mt!?VejGF855S9} eMhIN(1i?iPkr#YZtaB`RO!5cgr!y+J0000<1Wum- diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/copyright b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/copyright deleted file mode 100644 index 185dcbf..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/copyright +++ /dev/null @@ -1,32 +0,0 @@ -Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Source: https://git.lulzette.ru/hstack/compute -Upstream-Name: compute - -Files: - * -Copyright: - 2023 ge -License: GPL-3.0+ - -Files: - debian/* -Copyright: - 2023 ge -License: GPL-3.0+ - -License: GPL-3.0+ - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - . - This package is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - . - You should have received a copy of the GNU General Public License - along with this program. If not, see . -Comment: - On Debian systems, the complete text of the GNU General - Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/index.rst.txt b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/index.rst.txt deleted file mode 100644 index 81222c2..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/index.rst.txt +++ /dev/null @@ -1,16 +0,0 @@ -Compute -======= - -Compute instances management library. - -.. toctree:: - :maxdepth: 1 - - pyapi/index - -Indices and tables ------------------- - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/exceptions.rst.txt b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/exceptions.rst.txt deleted file mode 100644 index 3912721..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/exceptions.rst.txt +++ /dev/null @@ -1,5 +0,0 @@ -``exceptions`` -============== - -.. automodule:: compute.exceptions - :members: diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/index.rst.txt b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/index.rst.txt deleted file mode 100644 index e0cebb8..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/index.rst.txt +++ /dev/null @@ -1,49 +0,0 @@ -Python API -========== - -The API allows you to perform actions on instances programmatically. Below is -an example of changing parameters and launching the `myinstance` instance. - -.. code-block:: python - - import logging - - from compute import Session - - logging.basicConfig(level=logging.DEBUG) - - with Session() as session: - instance = session.get_instance('myinstance') - instance.set_vcpus(4) - instance.start() - instance.set_autostart(enabled=True) - - -:class:`Session` context manager provides an abstraction over :class:`libvirt.virConnect` -and returns objects of other classes of the present library. - -Entity representation ---------------------- - -Entities such as a compute-instance are represented as classes. These classes directly -call libvirt methods to perform operations on the hypervisor. An example class is -:class:`Volume`. - -The configuration files of various libvirt objects in `compute` are described by special -dataclasses. The dataclass stores object parameters in its properties and can return an -XML config for libvirt using the ``to_xml()`` method. For example :class:`VolumeConfig`. - -`Pydantic `_ models are used to validate input data. -For example :class:`VolumeSchema`. - -Modules documentation ---------------------- - -.. toctree:: - :maxdepth: 4 - - session - instance/index - storage/index - utils - exceptions diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/instance/guest_agent.rst.txt b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/instance/guest_agent.rst.txt deleted file mode 100644 index 1305140..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/instance/guest_agent.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -``guest_agent`` -=============== - -.. automodule:: compute.instance.guest_agent - :members: - :special-members: __init__ diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/instance/index.rst.txt b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/instance/index.rst.txt deleted file mode 100644 index 659ffc2..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/instance/index.rst.txt +++ /dev/null @@ -1,10 +0,0 @@ -``instance`` -============ - -.. toctree:: - :maxdepth: 1 - :caption: Contents: - - instance - guest_agent - schemas diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/instance/instance.rst.txt b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/instance/instance.rst.txt deleted file mode 100644 index 3c58f1f..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/instance/instance.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -``instance`` -============ - -.. automodule:: compute.instance.instance - :members: - :special-members: __init__ diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/instance/schemas.rst.txt b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/instance/schemas.rst.txt deleted file mode 100644 index 7dacabf..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/instance/schemas.rst.txt +++ /dev/null @@ -1,5 +0,0 @@ -``schemas`` -=========== - -.. automodule:: compute.instance.schemas - :members: diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/session.rst.txt b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/session.rst.txt deleted file mode 100644 index 2dec16e..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/session.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -``session`` -=========== - -.. automodule:: compute.session - :members: - :special-members: __init__ diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/storage/index.rst.txt b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/storage/index.rst.txt deleted file mode 100644 index e9ea734..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/storage/index.rst.txt +++ /dev/null @@ -1,9 +0,0 @@ -``storage`` -============ - -.. toctree:: - :maxdepth: 1 - :caption: Contents: - - pool - volume diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/storage/pool.rst.txt b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/storage/pool.rst.txt deleted file mode 100644 index 398124e..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/storage/pool.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -``pool`` -======== - -.. automodule:: compute.storage.pool - :members: - :special-members: __init__ diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/storage/volume.rst.txt b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/storage/volume.rst.txt deleted file mode 100644 index e1ba8d0..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/storage/volume.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -``volume`` -========== - -.. automodule:: compute.storage.volume - :members: - :special-members: __init__ diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/utils.rst.txt b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/utils.rst.txt deleted file mode 100644 index b5ab60a..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_sources/pyapi/utils.rst.txt +++ /dev/null @@ -1,14 +0,0 @@ -``utils`` -========= - -``utils.units`` ---------------- - -.. automodule:: compute.utils.units - :members: - -``utils.ids`` -------------- - -.. automodule:: compute.utils.ids - :members: diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/_sphinx_javascript_frameworks_compat.js b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/_sphinx_javascript_frameworks_compat.js deleted file mode 120000 index e04de6d..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/_sphinx_javascript_frameworks_compat.js +++ /dev/null @@ -1 +0,0 @@ -../../../../javascript/sphinxdoc/1.0/_sphinx_javascript_frameworks_compat.js \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/alabaster.css b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/alabaster.css deleted file mode 100644 index 0eddaeb..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/alabaster.css +++ /dev/null @@ -1,701 +0,0 @@ -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -body { - font-family: Georgia, serif; - font-size: 17px; - background-color: #fff; - color: #000; - margin: 0; - padding: 0; -} - - -div.document { - width: 940px; - margin: 30px auto 0 auto; -} - -div.documentwrapper { - float: left; - width: 100%; -} - -div.bodywrapper { - margin: 0 0 0 220px; -} - -div.sphinxsidebar { - width: 220px; - font-size: 14px; - line-height: 1.5; -} - -hr { - border: 1px solid #B1B4B6; -} - -div.body { - background-color: #fff; - color: #3E4349; - padding: 0 30px 0 30px; -} - -div.body > .section { - text-align: left; -} - -div.footer { - width: 940px; - margin: 20px auto 30px auto; - font-size: 14px; - color: #888; - text-align: right; -} - -div.footer a { - color: #888; -} - -p.caption { - font-family: inherit; - font-size: inherit; -} - - -div.relations { - display: none; -} - - -div.sphinxsidebar a { - color: #444; - text-decoration: none; - border-bottom: 1px dotted #999; -} - -div.sphinxsidebar a:hover { - border-bottom: 1px solid #999; -} - -div.sphinxsidebarwrapper { - padding: 18px 10px; -} - -div.sphinxsidebarwrapper p.logo { - padding: 0; - margin: -10px 0 0 0px; - text-align: center; -} - -div.sphinxsidebarwrapper h1.logo { - margin-top: -10px; - text-align: center; - margin-bottom: 5px; - text-align: left; -} - -div.sphinxsidebarwrapper h1.logo-name { - margin-top: 0px; -} - -div.sphinxsidebarwrapper p.blurb { - margin-top: 0; - font-style: normal; -} - -div.sphinxsidebar h3, -div.sphinxsidebar h4 { - font-family: Georgia, serif; - color: #444; - font-size: 24px; - font-weight: normal; - margin: 0 0 5px 0; - padding: 0; -} - -div.sphinxsidebar h4 { - font-size: 20px; -} - -div.sphinxsidebar h3 a { - color: #444; -} - -div.sphinxsidebar p.logo a, -div.sphinxsidebar h3 a, -div.sphinxsidebar p.logo a:hover, -div.sphinxsidebar h3 a:hover { - border: none; -} - -div.sphinxsidebar p { - color: #555; - margin: 10px 0; -} - -div.sphinxsidebar ul { - margin: 10px 0; - padding: 0; - color: #000; -} - -div.sphinxsidebar ul li.toctree-l1 > a { - font-size: 120%; -} - -div.sphinxsidebar ul li.toctree-l2 > a { - font-size: 110%; -} - -div.sphinxsidebar input { - border: 1px solid #CCC; - font-family: Georgia, serif; - font-size: 1em; -} - -div.sphinxsidebar hr { - border: none; - height: 1px; - color: #AAA; - background: #AAA; - - text-align: left; - margin-left: 0; - width: 50%; -} - -div.sphinxsidebar .badge { - border-bottom: none; -} - -div.sphinxsidebar .badge:hover { - border-bottom: none; -} - -/* To address an issue with donation coming after search */ -div.sphinxsidebar h3.donation { - margin-top: 10px; -} - -/* -- body styles ----------------------------------------------------------- */ - -a { - color: #004B6B; - text-decoration: underline; -} - -a:hover { - color: #6D4100; - text-decoration: underline; -} - -div.body h1, -div.body h2, -div.body h3, -div.body h4, -div.body h5, -div.body h6 { - font-family: Georgia, serif; - font-weight: normal; - margin: 30px 0px 10px 0px; - padding: 0; -} - -div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } -div.body h2 { font-size: 180%; } -div.body h3 { font-size: 150%; } -div.body h4 { font-size: 130%; } -div.body h5 { font-size: 100%; } -div.body h6 { font-size: 100%; } - -a.headerlink { - color: #DDD; - padding: 0 4px; - text-decoration: none; -} - -a.headerlink:hover { - color: #444; - background: #EAEAEA; -} - -div.body p, div.body dd, div.body li { - line-height: 1.4em; -} - -div.admonition { - margin: 20px 0px; - padding: 10px 30px; - background-color: #EEE; - border: 1px solid #CCC; -} - -div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { - background-color: #FBFBFB; - border-bottom: 1px solid #fafafa; -} - -div.admonition p.admonition-title { - font-family: Georgia, serif; - font-weight: normal; - font-size: 24px; - margin: 0 0 10px 0; - padding: 0; - line-height: 1; -} - -div.admonition p.last { - margin-bottom: 0; -} - -div.highlight { - background-color: #fff; -} - -dt:target, .highlight { - background: #FAF3E8; -} - -div.warning { - background-color: #FCC; - border: 1px solid #FAA; -} - -div.danger { - background-color: #FCC; - border: 1px solid #FAA; - -moz-box-shadow: 2px 2px 4px #D52C2C; - -webkit-box-shadow: 2px 2px 4px #D52C2C; - box-shadow: 2px 2px 4px #D52C2C; -} - -div.error { - background-color: #FCC; - border: 1px solid #FAA; - -moz-box-shadow: 2px 2px 4px #D52C2C; - -webkit-box-shadow: 2px 2px 4px #D52C2C; - box-shadow: 2px 2px 4px #D52C2C; -} - -div.caution { - background-color: #FCC; - border: 1px solid #FAA; -} - -div.attention { - background-color: #FCC; - border: 1px solid #FAA; -} - -div.important { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.note { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.tip { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.hint { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.seealso { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.topic { - background-color: #EEE; -} - -p.admonition-title { - display: inline; -} - -p.admonition-title:after { - content: ":"; -} - -pre, tt, code { - font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; - font-size: 0.9em; -} - -.hll { - background-color: #FFC; - margin: 0 -12px; - padding: 0 12px; - display: block; -} - -img.screenshot { -} - -tt.descname, tt.descclassname, code.descname, code.descclassname { - font-size: 0.95em; -} - -tt.descname, code.descname { - padding-right: 0.08em; -} - -img.screenshot { - -moz-box-shadow: 2px 2px 4px #EEE; - -webkit-box-shadow: 2px 2px 4px #EEE; - box-shadow: 2px 2px 4px #EEE; -} - -table.docutils { - border: 1px solid #888; - -moz-box-shadow: 2px 2px 4px #EEE; - -webkit-box-shadow: 2px 2px 4px #EEE; - box-shadow: 2px 2px 4px #EEE; -} - -table.docutils td, table.docutils th { - border: 1px solid #888; - padding: 0.25em 0.7em; -} - -table.field-list, table.footnote { - border: none; - -moz-box-shadow: none; - -webkit-box-shadow: none; - box-shadow: none; -} - -table.footnote { - margin: 15px 0; - width: 100%; - border: 1px solid #EEE; - background: #FDFDFD; - font-size: 0.9em; -} - -table.footnote + table.footnote { - margin-top: -15px; - border-top: none; -} - -table.field-list th { - padding: 0 0.8em 0 0; -} - -table.field-list td { - padding: 0; -} - -table.field-list p { - margin-bottom: 0.8em; -} - -/* Cloned from - * https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68 - */ -.field-name { - -moz-hyphens: manual; - -ms-hyphens: manual; - -webkit-hyphens: manual; - hyphens: manual; -} - -table.footnote td.label { - width: .1px; - padding: 0.3em 0 0.3em 0.5em; -} - -table.footnote td { - padding: 0.3em 0.5em; -} - -dl { - margin: 0; - padding: 0; -} - -dl dd { - margin-left: 30px; -} - -blockquote { - margin: 0 0 0 30px; - padding: 0; -} - -ul, ol { - /* Matches the 30px from the narrow-screen "li > ul" selector below */ - margin: 10px 0 10px 30px; - padding: 0; -} - -pre { - background: #EEE; - padding: 7px 30px; - margin: 15px 0px; - line-height: 1.3em; -} - -div.viewcode-block:target { - background: #ffd; -} - -dl pre, blockquote pre, li pre { - margin-left: 0; - padding-left: 30px; -} - -tt, code { - background-color: #ecf0f3; - color: #222; - /* padding: 1px 2px; */ -} - -tt.xref, code.xref, a tt { - background-color: #FBFBFB; - border-bottom: 1px solid #fff; -} - -a.reference { - text-decoration: none; - border-bottom: 1px dotted #004B6B; -} - -/* Don't put an underline on images */ -a.image-reference, a.image-reference:hover { - border-bottom: none; -} - -a.reference:hover { - border-bottom: 1px solid #6D4100; -} - -a.footnote-reference { - text-decoration: none; - font-size: 0.7em; - vertical-align: top; - border-bottom: 1px dotted #004B6B; -} - -a.footnote-reference:hover { - border-bottom: 1px solid #6D4100; -} - -a:hover tt, a:hover code { - background: #EEE; -} - - -@media screen and (max-width: 870px) { - - div.sphinxsidebar { - display: none; - } - - div.document { - width: 100%; - - } - - div.documentwrapper { - margin-left: 0; - margin-top: 0; - margin-right: 0; - margin-bottom: 0; - } - - div.bodywrapper { - margin-top: 0; - margin-right: 0; - margin-bottom: 0; - margin-left: 0; - } - - ul { - margin-left: 0; - } - - li > ul { - /* Matches the 30px from the "ul, ol" selector above */ - margin-left: 30px; - } - - .document { - width: auto; - } - - .footer { - width: auto; - } - - .bodywrapper { - margin: 0; - } - - .footer { - width: auto; - } - - .github { - display: none; - } - - - -} - - - -@media screen and (max-width: 875px) { - - body { - margin: 0; - padding: 20px 30px; - } - - div.documentwrapper { - float: none; - background: #fff; - } - - div.sphinxsidebar { - display: block; - float: none; - width: 102.5%; - margin: 50px -30px -20px -30px; - padding: 10px 20px; - background: #333; - color: #FFF; - } - - div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, - div.sphinxsidebar h3 a { - color: #fff; - } - - div.sphinxsidebar a { - color: #AAA; - } - - div.sphinxsidebar p.logo { - display: none; - } - - div.document { - width: 100%; - margin: 0; - } - - div.footer { - display: none; - } - - div.bodywrapper { - margin: 0; - } - - div.body { - min-height: 0; - padding: 0; - } - - .rtd_doc_footer { - display: none; - } - - .document { - width: auto; - } - - .footer { - width: auto; - } - - .footer { - width: auto; - } - - .github { - display: none; - } -} - - -/* misc. */ - -.revsys-inline { - display: none!important; -} - -/* Make nested-list/multi-paragraph items look better in Releases changelog - * pages. Without this, docutils' magical list fuckery causes inconsistent - * formatting between different release sub-lists. - */ -div#changelog > div.section > ul > li > p:only-child { - margin-bottom: 0; -} - -/* Hide fugly table cell borders in ..bibliography:: directive output */ -table.docutils.citation, table.docutils.citation td, table.docutils.citation th { - border: none; - /* Below needed in some edge cases; if not applied, bottom shadows appear */ - -moz-box-shadow: none; - -webkit-box-shadow: none; - box-shadow: none; -} - - -/* relbar */ - -.related { - line-height: 30px; - width: 100%; - font-size: 0.9rem; -} - -.related.top { - border-bottom: 1px solid #EEE; - margin-bottom: 20px; -} - -.related.bottom { - border-top: 1px solid #EEE; -} - -.related ul { - padding: 0; - margin: 0; - list-style: none; -} - -.related li { - display: inline; -} - -nav#rellinks { - float: right; -} - -nav#rellinks li+li:before { - content: "|"; -} - -nav#breadcrumbs li+li:before { - content: "\00BB"; -} - -/* Hide certain items when printing */ -@media print { - div.related { - display: none; - } -} \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/basic.css b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/basic.css deleted file mode 100644 index 4e9a9f1..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/basic.css +++ /dev/null @@ -1,900 +0,0 @@ -/* - * basic.css - * ~~~~~~~~~ - * - * Sphinx stylesheet -- basic theme. - * - * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/* -- main layout ----------------------------------------------------------- */ - -div.clearer { - clear: both; -} - -div.section::after { - display: block; - content: ''; - clear: left; -} - -/* -- relbar ---------------------------------------------------------------- */ - -div.related { - width: 100%; - font-size: 90%; -} - -div.related h3 { - display: none; -} - -div.related ul { - margin: 0; - padding: 0 0 0 10px; - list-style: none; -} - -div.related li { - display: inline; -} - -div.related li.right { - float: right; - margin-right: 5px; -} - -/* -- sidebar --------------------------------------------------------------- */ - -div.sphinxsidebarwrapper { - padding: 10px 5px 0 10px; -} - -div.sphinxsidebar { - float: left; - width: 230px; - margin-left: -100%; - font-size: 90%; - word-wrap: break-word; - overflow-wrap : break-word; -} - -div.sphinxsidebar ul { - list-style: none; -} - -div.sphinxsidebar ul ul, -div.sphinxsidebar ul.want-points { - margin-left: 20px; - list-style: square; -} - -div.sphinxsidebar ul ul { - margin-top: 0; - margin-bottom: 0; -} - -div.sphinxsidebar form { - margin-top: 10px; -} - -div.sphinxsidebar input { - border: 1px solid #98dbcc; - font-family: sans-serif; - font-size: 1em; -} - -div.sphinxsidebar #searchbox form.search { - overflow: hidden; -} - -div.sphinxsidebar #searchbox input[type="text"] { - float: left; - width: 80%; - padding: 0.25em; - box-sizing: border-box; -} - -div.sphinxsidebar #searchbox input[type="submit"] { - float: left; - width: 20%; - border-left: none; - padding: 0.25em; - box-sizing: border-box; -} - - -img { - border: 0; - max-width: 100%; -} - -/* -- search page ----------------------------------------------------------- */ - -ul.search { - margin: 10px 0 0 20px; - padding: 0; -} - -ul.search li { - padding: 5px 0 5px 20px; - background-image: url(file.png); - background-repeat: no-repeat; - background-position: 0 7px; -} - -ul.search li a { - font-weight: bold; -} - -ul.search li p.context { - color: #888; - margin: 2px 0 0 30px; - text-align: left; -} - -ul.keywordmatches li.goodmatch a { - font-weight: bold; -} - -/* -- index page ------------------------------------------------------------ */ - -table.contentstable { - width: 90%; - margin-left: auto; - margin-right: auto; -} - -table.contentstable p.biglink { - line-height: 150%; -} - -a.biglink { - font-size: 1.3em; -} - -span.linkdescr { - font-style: italic; - padding-top: 5px; - font-size: 90%; -} - -/* -- general index --------------------------------------------------------- */ - -table.indextable { - width: 100%; -} - -table.indextable td { - text-align: left; - vertical-align: top; -} - -table.indextable ul { - margin-top: 0; - margin-bottom: 0; - list-style-type: none; -} - -table.indextable > tbody > tr > td > ul { - padding-left: 0em; -} - -table.indextable tr.pcap { - height: 10px; -} - -table.indextable tr.cap { - margin-top: 10px; - background-color: #f2f2f2; -} - -img.toggler { - margin-right: 3px; - margin-top: 3px; - cursor: pointer; -} - -div.modindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -div.genindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -/* -- domain module index --------------------------------------------------- */ - -table.modindextable td { - padding: 2px; - border-collapse: collapse; -} - -/* -- general body styles --------------------------------------------------- */ - -div.body { - min-width: 360px; - max-width: 800px; -} - -div.body p, div.body dd, div.body li, div.body blockquote { - -moz-hyphens: auto; - -ms-hyphens: auto; - -webkit-hyphens: auto; - hyphens: auto; -} - -a.headerlink { - visibility: hidden; -} - -h1:hover > a.headerlink, -h2:hover > a.headerlink, -h3:hover > a.headerlink, -h4:hover > a.headerlink, -h5:hover > a.headerlink, -h6:hover > a.headerlink, -dt:hover > a.headerlink, -caption:hover > a.headerlink, -p.caption:hover > a.headerlink, -div.code-block-caption:hover > a.headerlink { - visibility: visible; -} - -div.body p.caption { - text-align: inherit; -} - -div.body td { - text-align: left; -} - -.first { - margin-top: 0 !important; -} - -p.rubric { - margin-top: 30px; - font-weight: bold; -} - -img.align-left, figure.align-left, .figure.align-left, object.align-left { - clear: left; - float: left; - margin-right: 1em; -} - -img.align-right, figure.align-right, .figure.align-right, object.align-right { - clear: right; - float: right; - margin-left: 1em; -} - -img.align-center, figure.align-center, .figure.align-center, object.align-center { - display: block; - margin-left: auto; - margin-right: auto; -} - -img.align-default, figure.align-default, .figure.align-default { - display: block; - margin-left: auto; - margin-right: auto; -} - -.align-left { - text-align: left; -} - -.align-center { - text-align: center; -} - -.align-default { - text-align: center; -} - -.align-right { - text-align: right; -} - -/* -- sidebars -------------------------------------------------------------- */ - -div.sidebar, -aside.sidebar { - margin: 0 0 0.5em 1em; - border: 1px solid #ddb; - padding: 7px; - background-color: #ffe; - width: 40%; - float: right; - clear: right; - overflow-x: auto; -} - -p.sidebar-title { - font-weight: bold; -} -nav.contents, -aside.topic, -div.admonition, div.topic, blockquote { - clear: left; -} - -/* -- topics ---------------------------------------------------------------- */ -nav.contents, -aside.topic, -div.topic { - border: 1px solid #ccc; - padding: 7px; - margin: 10px 0 10px 0; -} - -p.topic-title { - font-size: 1.1em; - font-weight: bold; - margin-top: 10px; -} - -/* -- admonitions ----------------------------------------------------------- */ - -div.admonition { - margin-top: 10px; - margin-bottom: 10px; - padding: 7px; -} - -div.admonition dt { - font-weight: bold; -} - -p.admonition-title { - margin: 0px 10px 5px 0px; - font-weight: bold; -} - -div.body p.centered { - text-align: center; - margin-top: 25px; -} - -/* -- content of sidebars/topics/admonitions -------------------------------- */ - -div.sidebar > :last-child, -aside.sidebar > :last-child, -nav.contents > :last-child, -aside.topic > :last-child, -div.topic > :last-child, -div.admonition > :last-child { - margin-bottom: 0; -} - -div.sidebar::after, -aside.sidebar::after, -nav.contents::after, -aside.topic::after, -div.topic::after, -div.admonition::after, -blockquote::after { - display: block; - content: ''; - clear: both; -} - -/* -- tables ---------------------------------------------------------------- */ - -table.docutils { - margin-top: 10px; - margin-bottom: 10px; - border: 0; - border-collapse: collapse; -} - -table.align-center { - margin-left: auto; - margin-right: auto; -} - -table.align-default { - margin-left: auto; - margin-right: auto; -} - -table caption span.caption-number { - font-style: italic; -} - -table caption span.caption-text { -} - -table.docutils td, table.docutils th { - padding: 1px 8px 1px 5px; - border-top: 0; - border-left: 0; - border-right: 0; - border-bottom: 1px solid #aaa; -} - -th { - text-align: left; - padding-right: 5px; -} - -table.citation { - border-left: solid 1px gray; - margin-left: 1px; -} - -table.citation td { - border-bottom: none; -} - -th > :first-child, -td > :first-child { - margin-top: 0px; -} - -th > :last-child, -td > :last-child { - margin-bottom: 0px; -} - -/* -- figures --------------------------------------------------------------- */ - -div.figure, figure { - margin: 0.5em; - padding: 0.5em; -} - -div.figure p.caption, figcaption { - padding: 0.3em; -} - -div.figure p.caption span.caption-number, -figcaption span.caption-number { - font-style: italic; -} - -div.figure p.caption span.caption-text, -figcaption span.caption-text { -} - -/* -- field list styles ----------------------------------------------------- */ - -table.field-list td, table.field-list th { - border: 0 !important; -} - -.field-list ul { - margin: 0; - padding-left: 1em; -} - -.field-list p { - margin: 0; -} - -.field-name { - -moz-hyphens: manual; - -ms-hyphens: manual; - -webkit-hyphens: manual; - hyphens: manual; -} - -/* -- hlist styles ---------------------------------------------------------- */ - -table.hlist { - margin: 1em 0; -} - -table.hlist td { - vertical-align: top; -} - -/* -- object description styles --------------------------------------------- */ - -.sig { - font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; -} - -.sig-name, code.descname { - background-color: transparent; - font-weight: bold; -} - -.sig-name { - font-size: 1.1em; -} - -code.descname { - font-size: 1.2em; -} - -.sig-prename, code.descclassname { - background-color: transparent; -} - -.optional { - font-size: 1.3em; -} - -.sig-paren { - font-size: larger; -} - -.sig-param.n { - font-style: italic; -} - -/* C++ specific styling */ - -.sig-inline.c-texpr, -.sig-inline.cpp-texpr { - font-family: unset; -} - -.sig.c .k, .sig.c .kt, -.sig.cpp .k, .sig.cpp .kt { - color: #0033B3; -} - -.sig.c .m, -.sig.cpp .m { - color: #1750EB; -} - -.sig.c .s, .sig.c .sc, -.sig.cpp .s, .sig.cpp .sc { - color: #067D17; -} - - -/* -- other body styles ----------------------------------------------------- */ - -ol.arabic { - list-style: decimal; -} - -ol.loweralpha { - list-style: lower-alpha; -} - -ol.upperalpha { - list-style: upper-alpha; -} - -ol.lowerroman { - list-style: lower-roman; -} - -ol.upperroman { - list-style: upper-roman; -} - -:not(li) > ol > li:first-child > :first-child, -:not(li) > ul > li:first-child > :first-child { - margin-top: 0px; -} - -:not(li) > ol > li:last-child > :last-child, -:not(li) > ul > li:last-child > :last-child { - margin-bottom: 0px; -} - -ol.simple ol p, -ol.simple ul p, -ul.simple ol p, -ul.simple ul p { - margin-top: 0; -} - -ol.simple > li:not(:first-child) > p, -ul.simple > li:not(:first-child) > p { - margin-top: 0; -} - -ol.simple p, -ul.simple p { - margin-bottom: 0; -} -aside.footnote > span, -div.citation > span { - float: left; -} -aside.footnote > span:last-of-type, -div.citation > span:last-of-type { - padding-right: 0.5em; -} -aside.footnote > p { - margin-left: 2em; -} -div.citation > p { - margin-left: 4em; -} -aside.footnote > p:last-of-type, -div.citation > p:last-of-type { - margin-bottom: 0em; -} -aside.footnote > p:last-of-type:after, -div.citation > p:last-of-type:after { - content: ""; - clear: both; -} - -dl.field-list { - display: grid; - grid-template-columns: fit-content(30%) auto; -} - -dl.field-list > dt { - font-weight: bold; - word-break: break-word; - padding-left: 0.5em; - padding-right: 5px; -} - -dl.field-list > dd { - padding-left: 0.5em; - margin-top: 0em; - margin-left: 0em; - margin-bottom: 0em; -} - -dl { - margin-bottom: 15px; -} - -dd > :first-child { - margin-top: 0px; -} - -dd ul, dd table { - margin-bottom: 10px; -} - -dd { - margin-top: 3px; - margin-bottom: 10px; - margin-left: 30px; -} - -dl > dd:last-child, -dl > dd:last-child > :last-child { - margin-bottom: 0; -} - -dt:target, span.highlighted { - background-color: #fbe54e; -} - -rect.highlighted { - fill: #fbe54e; -} - -dl.glossary dt { - font-weight: bold; - font-size: 1.1em; -} - -.versionmodified { - font-style: italic; -} - -.system-message { - background-color: #fda; - padding: 5px; - border: 3px solid red; -} - -.footnote:target { - background-color: #ffa; -} - -.line-block { - display: block; - margin-top: 1em; - margin-bottom: 1em; -} - -.line-block .line-block { - margin-top: 0; - margin-bottom: 0; - margin-left: 1.5em; -} - -.guilabel, .menuselection { - font-family: sans-serif; -} - -.accelerator { - text-decoration: underline; -} - -.classifier { - font-style: oblique; -} - -.classifier:before { - font-style: normal; - margin: 0 0.5em; - content: ":"; - display: inline-block; -} - -abbr, acronym { - border-bottom: dotted 1px; - cursor: help; -} - -/* -- code displays --------------------------------------------------------- */ - -pre { - overflow: auto; - overflow-y: hidden; /* fixes display issues on Chrome browsers */ -} - -pre, div[class*="highlight-"] { - clear: both; -} - -span.pre { - -moz-hyphens: none; - -ms-hyphens: none; - -webkit-hyphens: none; - hyphens: none; - white-space: nowrap; -} - -div[class*="highlight-"] { - margin: 1em 0; -} - -td.linenos pre { - border: 0; - background-color: transparent; - color: #aaa; -} - -table.highlighttable { - display: block; -} - -table.highlighttable tbody { - display: block; -} - -table.highlighttable tr { - display: flex; -} - -table.highlighttable td { - margin: 0; - padding: 0; -} - -table.highlighttable td.linenos { - padding-right: 0.5em; -} - -table.highlighttable td.code { - flex: 1; - overflow: hidden; -} - -.highlight .hll { - display: block; -} - -div.highlight pre, -table.highlighttable pre { - margin: 0; -} - -div.code-block-caption + div { - margin-top: 0; -} - -div.code-block-caption { - margin-top: 1em; - padding: 2px 5px; - font-size: small; -} - -div.code-block-caption code { - background-color: transparent; -} - -table.highlighttable td.linenos, -span.linenos, -div.highlight span.gp { /* gp: Generic.Prompt */ - user-select: none; - -webkit-user-select: text; /* Safari fallback only */ - -webkit-user-select: none; /* Chrome/Safari */ - -moz-user-select: none; /* Firefox */ - -ms-user-select: none; /* IE10+ */ -} - -div.code-block-caption span.caption-number { - padding: 0.1em 0.3em; - font-style: italic; -} - -div.code-block-caption span.caption-text { -} - -div.literal-block-wrapper { - margin: 1em 0; -} - -code.xref, a code { - background-color: transparent; - font-weight: bold; -} - -h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { - background-color: transparent; -} - -.viewcode-link { - float: right; -} - -.viewcode-back { - float: right; - font-family: sans-serif; -} - -div.viewcode-block:target { - margin: -1px -10px; - padding: 0 10px; -} - -/* -- math display ---------------------------------------------------------- */ - -img.math { - vertical-align: middle; -} - -div.body div.math p { - text-align: center; -} - -span.eqno { - float: right; -} - -span.eqno a.headerlink { - position: absolute; - z-index: 1; -} - -div.math:hover a.headerlink { - visibility: visible; -} - -/* -- printout stylesheet --------------------------------------------------- */ - -@media print { - div.document, - div.documentwrapper, - div.bodywrapper { - margin: 0 !important; - width: 100%; - } - - div.sphinxsidebar, - div.related, - div.footer, - #top-link { - display: none; - } -} \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/custom.css b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/custom.css deleted file mode 100644 index 2a924f1..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/custom.css +++ /dev/null @@ -1 +0,0 @@ -/* This file intentionally left blank. */ diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/doctools.js b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/doctools.js deleted file mode 120000 index e51872e..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/doctools.js +++ /dev/null @@ -1 +0,0 @@ -../../../../javascript/sphinxdoc/1.0/doctools.js \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/documentation_options.js b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/documentation_options.js deleted file mode 100644 index e49ed18..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/documentation_options.js +++ /dev/null @@ -1,14 +0,0 @@ -var DOCUMENTATION_OPTIONS = { - URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), - VERSION: '0.1.0', - LANGUAGE: 'en', - COLLAPSE_INDEX: false, - BUILDER: 'html', - FILE_SUFFIX: '.html', - LINK_SUFFIX: '.html', - HAS_SOURCE: true, - SOURCELINK_SUFFIX: '.txt', - NAVIGATION_WITH_KEYS: false, - SHOW_SEARCH_SUMMARY: true, - ENABLE_SEARCH_SHORTCUTS: true, -}; \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/file.png b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/file.png deleted file mode 100644 index a858a410e4faa62ce324d814e4b816fff83a6fb3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 286 zcmV+(0pb3MP)s`hMrGg#P~ix$^RISR_I47Y|r1 z_CyJOe}D1){SET-^Amu_i71Lt6eYfZjRyw@I6OQAIXXHDfiX^GbOlHe=Ae4>0m)d(f|Me07*qoM6N<$f}vM^LjV8( diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/forkme_right_darkblue_121621.png b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/forkme_right_darkblue_121621.png deleted file mode 100644 index 146ef8a800602169cf78c686fc5a6d138a76bc0a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7791 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 diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/plus.png b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/plus.png deleted file mode 100644 index 7107cec93a979b9a5f64843235a16651d563ce2d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*WBp7;*Yy1LIik>cxAr*|t7R?Mi>2?kWtu>-2 m3q%Vub%g%s<8sJhVPMczOq}xhg9DJoz~JfX=d#Wzp$Pyb1r*Kz diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/pygments.css b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/pygments.css deleted file mode 100644 index 9abe04b..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/pygments.css +++ /dev/null @@ -1,83 +0,0 @@ -pre { line-height: 125%; } -td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } -span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } -td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } -span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } -.highlight .hll { background-color: #ffffcc } -.highlight { background: #f8f8f8; } -.highlight .c { color: #8f5902; font-style: italic } /* Comment */ -.highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */ -.highlight .g { color: #000000 } /* Generic */ -.highlight .k { color: #004461; font-weight: bold } /* Keyword */ -.highlight .l { color: #000000 } /* Literal */ -.highlight .n { color: #000000 } /* Name */ -.highlight .o { color: #582800 } /* Operator */ -.highlight .x { color: #000000 } /* Other */ -.highlight .p { color: #000000; font-weight: bold } /* Punctuation */ -.highlight .ch { color: #8f5902; font-style: italic } /* Comment.Hashbang */ -.highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */ -.highlight .cp { color: #8f5902 } /* Comment.Preproc */ -.highlight .cpf { color: #8f5902; font-style: italic } /* Comment.PreprocFile */ -.highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */ -.highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */ -.highlight .gd { color: #a40000 } /* Generic.Deleted */ -.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */ -.highlight .gr { color: #ef2929 } /* Generic.Error */ -.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ -.highlight .gi { color: #00A000 } /* Generic.Inserted */ -.highlight .go { color: #888888 } /* Generic.Output */ -.highlight .gp { color: #745334 } /* Generic.Prompt */ -.highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */ -.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ -.highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */ -.highlight .kc { color: #004461; font-weight: bold } /* Keyword.Constant */ -.highlight .kd { color: #004461; font-weight: bold } /* Keyword.Declaration */ -.highlight .kn { color: #004461; font-weight: bold } /* Keyword.Namespace */ -.highlight .kp { color: #004461; font-weight: bold } /* Keyword.Pseudo */ -.highlight .kr { color: #004461; font-weight: bold } /* Keyword.Reserved */ -.highlight .kt { color: #004461; font-weight: bold } /* Keyword.Type */ -.highlight .ld { color: #000000 } /* Literal.Date */ -.highlight .m { color: #990000 } /* Literal.Number */ -.highlight .s { color: #4e9a06 } /* Literal.String */ -.highlight .na { color: #c4a000 } /* Name.Attribute */ -.highlight .nb { color: #004461 } /* Name.Builtin */ -.highlight .nc { color: #000000 } /* Name.Class */ -.highlight .no { color: #000000 } /* Name.Constant */ -.highlight .nd { color: #888888 } /* Name.Decorator */ -.highlight .ni { color: #ce5c00 } /* Name.Entity */ -.highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */ -.highlight .nf { color: #000000 } /* Name.Function */ -.highlight .nl { color: #f57900 } /* Name.Label */ -.highlight .nn { color: #000000 } /* Name.Namespace */ -.highlight .nx { color: #000000 } /* Name.Other */ -.highlight .py { color: #000000 } /* Name.Property */ -.highlight .nt { color: #004461; font-weight: bold } /* Name.Tag */ -.highlight .nv { color: #000000 } /* Name.Variable */ -.highlight .ow { color: #004461; font-weight: bold } /* Operator.Word */ -.highlight .pm { color: #000000; font-weight: bold } /* Punctuation.Marker */ -.highlight .w { color: #f8f8f8; text-decoration: underline } /* Text.Whitespace */ -.highlight .mb { color: #990000 } /* Literal.Number.Bin */ -.highlight .mf { color: #990000 } /* Literal.Number.Float */ -.highlight .mh { color: #990000 } /* Literal.Number.Hex */ -.highlight .mi { color: #990000 } /* Literal.Number.Integer */ -.highlight .mo { color: #990000 } /* Literal.Number.Oct */ -.highlight .sa { color: #4e9a06 } /* Literal.String.Affix */ -.highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */ -.highlight .sc { color: #4e9a06 } /* Literal.String.Char */ -.highlight .dl { color: #4e9a06 } /* Literal.String.Delimiter */ -.highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */ -.highlight .s2 { color: #4e9a06 } /* Literal.String.Double */ -.highlight .se { color: #4e9a06 } /* Literal.String.Escape */ -.highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */ -.highlight .si { color: #4e9a06 } /* Literal.String.Interpol */ -.highlight .sx { color: #4e9a06 } /* Literal.String.Other */ -.highlight .sr { color: #4e9a06 } /* Literal.String.Regex */ -.highlight .s1 { color: #4e9a06 } /* Literal.String.Single */ -.highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */ -.highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */ -.highlight .fm { color: #000000 } /* Name.Function.Magic */ -.highlight .vc { color: #000000 } /* Name.Variable.Class */ -.highlight .vg { color: #000000 } /* Name.Variable.Global */ -.highlight .vi { color: #000000 } /* Name.Variable.Instance */ -.highlight .vm { color: #000000 } /* Name.Variable.Magic */ -.highlight .il { color: #990000 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/searchtools.js b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/searchtools.js deleted file mode 120000 index 2d33672..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/searchtools.js +++ /dev/null @@ -1 +0,0 @@ -../../../../javascript/sphinxdoc/1.0/searchtools.js \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/sphinx_highlight.js b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/sphinx_highlight.js deleted file mode 120000 index 75db705..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/sphinx_highlight.js +++ /dev/null @@ -1 +0,0 @@ -../../../../javascript/sphinxdoc/1.0/sphinx_highlight.js \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/underscore.js b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/underscore.js deleted file mode 120000 index 94df107..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/_static/underscore.js +++ /dev/null @@ -1 +0,0 @@ -../../../../javascript/sphinxdoc/1.0/underscore.js \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/genindex.html b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/genindex.html deleted file mode 100644 index 9434347..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/genindex.html +++ /dev/null @@ -1,614 +0,0 @@ - - - - - - - - Index — Compute 0.1.0 documentation - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- - -

Index

- -
- _ - | A - | B - | C - | D - | E - | G - | I - | L - | M - | N - | P - | R - | S - | T - | U - | V - -
-

_

- - -
- -

A

- - - -
- -

B

- - -
- -

C

- - - -
- -

D

- - - -
- -

E

- - - -
- -

G

- - - -
- -

I

- - - -
- -

L

- - - -
- -

M

- - -
- -

N

- - - -
- -

P

- - - -
- -

R

- - - -
- -

S

- - - -
- -

T

- - - -
- -

U

- - -
- -

V

- - - -
- - - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/index.html b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/index.html deleted file mode 100644 index dfb6fab..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/index.html +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - - - - Compute — Compute 0.1.0 documentation - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Compute

-

Compute instances management library.

-
- -
-
-

Indices and tables

- -
-
- - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/objects.inv b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/objects.inv deleted file mode 100644 index 353c123751df5365109b8d8b5dcc61c9dc93921b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1463 zcmV;o1xWfMAX9K?X>NERX>N99Zgg*Qc_4OWa&u{KZXhxWBOp+6Z)#;@bUGkIZ*6dO zbY%)7AXa5^b7^mGIv@%oAXI2&AaZ4GVQFq;WpW^IW*~HEX>%ZEX>4U6X>%ZBZ*6dL zWpi_7WFU2OX>MmAdTeQ8E(&-cWzZqAusEj<4})?5G% zs&^_d7glR`s!p(QTdoW-?Sz>Cd$5);9*A9Bb&jR)8B9($?*nAIQumBg!Pga(_3ya| zVH2}Qqb1vbnT;`P1vHczOio))p%3|OS>+w z(SR>bn}K*^9x$UtAz8Bz4=hu2`TZ9W_;}WC&*sp3HZ|^_yueux)rx)PdK20-j}b3I zUE-y#hXzk5uSEXZYjD7FiPELJUXzK54W{TSFd`ay7*+G`IV1xIMJd}RrjGy9`G&KF z*wTXM9pl6+&I@4nC%o>AUrf(wVFiMV9NtrH^3QgWfFiy5lyp*mHZOXR1B!tVxNFwTDkz`yCv8_L?5PlkRx#!@zpkgNDC6 zE|TyQuQ5X4Az0eWNRI9p0=?;%drFs=1ggW|Tn&q|Jijd1mSD3ZEVGUlMdm3s~>_35NHv5xB<=3Ck%6AjI&)4 - - - - - - Python Module Index — Compute 0.1.0 documentation - - - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- - -

Python Module Index

- -
- c -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
- c
- compute -
    - compute.exceptions -
    - compute.instance.guest_agent -
    - compute.instance.instance -
    - compute.instance.schemas -
    - compute.session -
    - compute.storage.pool -
    - compute.storage.volume -
    - compute.utils.ids -
    - compute.utils.units -
- - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/exceptions.html b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/exceptions.html deleted file mode 100644 index 1868528..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/exceptions.html +++ /dev/null @@ -1,183 +0,0 @@ - - - - - - - - - exceptions — Compute 0.1.0 documentation - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

exceptions

-

Exceptions.

-
-
-exception compute.exceptions.ComputeError
-

Basic exception class.

-
- -
-
-exception compute.exceptions.ConfigLoaderError
-

Something went wrong when loading configuration.

-
- -
-
-exception compute.exceptions.GuestAgentCommandNotSupportedError
-

Guest agent command is not supported or blacklisted on guest.

-
- -
-
-exception compute.exceptions.GuestAgentError
-

Something went wring when QEMU Guest Agent call.

-
- -
-
-exception compute.exceptions.GuestAgentTimeoutExceededError(msg: int)
-

QEMU timeout exceeded.

-
- -
-
-exception compute.exceptions.GuestAgentUnavailableError
-

Guest agent is not connected or is unavailable.

-
- -
-
-exception compute.exceptions.InstanceError
-

Something went wrong while interacting with the domain.

-
- -
-
-exception compute.exceptions.InstanceNotFoundError(msg: str)
-

Virtual machine or container not found on compute node.

-
- -
-
-exception compute.exceptions.SessionError
-

Something went wrong while connecting to libvirtd.

-
- -
-
-exception compute.exceptions.StoragePoolError
-

Something went wrong when operating with storage pool.

-
- -
-
-exception compute.exceptions.StoragePoolNotFoundError(msg: str)
-

Storage pool not found.

-
- -
-
-exception compute.exceptions.VolumeNotFoundError(msg: str)
-

Storage volume not found.

-
- -
- - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/index.html b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/index.html deleted file mode 100644 index 7162de0..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/index.html +++ /dev/null @@ -1,342 +0,0 @@ - - - - - - - - - Python API — Compute 0.1.0 documentation - - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Python API

-

The API allows you to perform actions on instances programmatically. Below is -an example of changing parameters and launching the myinstance instance.

-
import logging
-
-from compute import Session
-
-logging.basicConfig(level=logging.DEBUG)
-
-with Session() as session:
-    instance = session.get_instance('myinstance')
-    instance.set_vcpus(4)
-    instance.start()
-    instance.set_autostart(enabled=True)
-
-
-

Session context manager provides an abstraction over libvirt.virConnect -and returns objects of other classes of the present library.

-
-

Entity representation

-

Entities such as a compute-instance are represented as classes. These classes directly -call libvirt methods to perform operations on the hypervisor. An example class is -Volume.

-

The configuration files of various libvirt objects in compute are described by special -dataclasses. The dataclass stores object parameters in its properties and can return an -XML config for libvirt using the to_xml() method. For example VolumeConfig.

-

Pydantic models are used to validate input data. -For example VolumeSchema.

-
-
-

Modules documentation

-
- -
-
-
- - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/instance/guest_agent.html b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/instance/guest_agent.html deleted file mode 100644 index a8cca32..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/instance/guest_agent.html +++ /dev/null @@ -1,266 +0,0 @@ - - - - - - - - - guest_agent — Compute 0.1.0 documentation - - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

guest_agent

-

Interacting with the QEMU Guest Agent.

-
-
-class compute.instance.guest_agent.GuestAgent(domain: virDomain, timeout: int = 60)
-

Class for interacting with QEMU guest agent.

-
-
-__init__(domain: virDomain, timeout: int = 60)
-

Initialise GuestAgent.

-
-
Parameters:
-
    -
  • domain – Libvirt domain object

  • -
  • timeout – QEMU timeout

  • -
-
-
-
- -
-
-execute(command: dict) dict
-

Execute QEMU guest agent command.

-

See: https://qemu-project.gitlab.io/qemu/interop/qemu-ga-ref.html

-
-
Parameters:
-

command – QEMU guest agent command as dict

-
-
Returns:
-

Command output

-
-
Return type:
-

dict

-
-
-
- -
-
-get_supported_commands() set[str]
-

Return set of supported guest agent commands.

-
- -
-
-guest_exec(path: str, args: list[str] | None = None, env: list[str] | None = None, stdin: str | None = None, *, capture_output: bool = False, decode_output: bool = False, poll: bool = False) GuestExecOutput
-

Execute qemu-exec command and return output.

-
-
Parameters:
-
    -
  • path – Path ot executable on guest.

  • -
  • arg – List of arguments to pass to executable.

  • -
  • env – List of environment variables to pass to executable. -For example: ['LANG=C', 'TERM=xterm']

  • -
  • stdin – Data to pass to executable STDIN.

  • -
  • capture_output – Capture command output.

  • -
  • decode_output – Use base64_decode() to decode command output. -Affects only if capture_output is True.

  • -
  • poll – Poll command output. Uses self.timeout and -POLL_INTERVAL constant.

  • -
-
-
Returns:
-

Command output

-
-
Return type:
-

GuestExecOutput

-
-
-
- -
-
-guest_exec_status(pid: int, *, poll: bool = False, poll_interval: float = 0.3) dict
-

Execute guest-exec-status and return output.

-
-
Parameters:
-
    -
  • pid – PID in guest.

  • -
  • poll – If True poll command status.

  • -
  • poll_interval – Time between attempts to obtain command status.

  • -
-
-
Returns:
-

Command output

-
-
Return type:
-

dict

-
-
-
- -
-
-is_available() bool
-

Execute guest-ping.

-
-
Returns:
-

True or False if guest agent is unreachable.

-
-
Return type:
-

bool

-
-
-
- -
-
-raise_for_commands(commands: list[str]) None
-

Raise exception if QEMU GA command is not available.

-
-
Parameters:
-

commands – List of required commands

-
-
Raise:
-

GuestAgentCommandNotSupportedError

-
-
-
- -
- -
-
-class compute.instance.guest_agent.GuestExecOutput(exited: bool | None = None, exitcode: int | None = None, stdout: str | None = None, stderr: str | None = None)
-

QEMU guest-exec command output.

-
-
-exitcode: int | None
-

Alias for field number 1

-
- -
-
-exited: bool | None
-

Alias for field number 0

-
- -
-
-stderr: str | None
-

Alias for field number 3

-
- -
-
-stdout: str | None
-

Alias for field number 2

-
- -
- -
- - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/instance/index.html b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/instance/index.html deleted file mode 100644 index 87e074f..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/instance/index.html +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - instance — Compute 0.1.0 documentation - - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

instance

-
-

Contents:

- -
-
- - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/instance/instance.html b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/instance/instance.html deleted file mode 100644 index 9f34c04..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/instance/instance.html +++ /dev/null @@ -1,490 +0,0 @@ - - - - - - - - - instance — Compute 0.1.0 documentation - - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

instance

-

Manage compute instances.

-
-
-class compute.instance.instance.Instance(domain: virDomain)
-

Manage compute instances.

-
-
-__init__(domain: virDomain)
-

Initialise Instance.

-
-
Variables:
-
    -
  • domain (libvirt.virDomain) – domain object

  • -
  • connection (libvirt.virConnect) – connection object

  • -
  • name (str) – domain name

  • -
  • guest_agent (GuestAgent) – GuestAgent object

  • -
-
-
Parameters:
-

domain – libvirt domain object

-
-
-
- -
-
-attach_device(device: EntityConfig, *, live: bool = False) None
-

Attach device to compute instance.

-
-
Parameters:
-
    -
  • device – Object with device description e.g. DiskConfig

  • -
  • live – Affect a running instance

  • -
-
-
-
- -
-
-delete() None
-

Undefine instance.

-
- -
-
-delete_ssh_keys(user: str, ssh_keys: list[str]) None
-

Remove SSH keys from guest for specific user.

-
-
Parameters:
-
    -
  • user – Username.

  • -
  • ssh_keys – List of public SSH keys.

  • -
-
-
-
- -
-
-detach_device(device: EntityConfig, *, live: bool = False) None
-

Dettach device from compute instance.

-
-
Parameters:
-
    -
  • device – Object with device description e.g. DiskConfig

  • -
  • live – Affect a running instance

  • -
-
-
-
- -
-
-detach_disk(name: str) None
-

Detach disk device by target name.

-

There is no attach_disk() method. Use attach_device() -with DiskConfig as argument.

-
-
Parameters:
-

name – Disk name e.g. ‘vda’, ‘sda’, etc. This name may -not match the name of the disk inside the guest OS.

-
-
-
- -
-
-dump_xml(*, inactive: bool = False) str
-

Return instance XML description.

-
- -
-
-get_disks() list[compute.storage.volume.DiskConfig]
-

Return list of attached disks.

-
- -
-
-get_info() InstanceInfo
-

Return instance info.

-
- -
-
-get_max_memory() int
-

Maximum memory value for domain in KiB.

-
- -
-
-get_max_vcpus() int
-

Maximum vCPUs number for domain.

-
- -
-
-get_ssh_keys(user: str) list[str]
-

Return list of SSH keys on guest for specific user.

-
-
Parameters:
-

user – Username.

-
-
-
- -
-
-get_status() str
-

Return instance state: ‘running’, ‘shutoff’, etc.

-

Reference: -https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainState

-
- -
-
-is_autostart() bool
-

Return True if instance autostart is enabled, else return False.

-
- -
-
-is_running() bool
-

Return True if instance is running, else return False.

-
- -
-
-pause() None
-

Pause instance.

-
- -
-
-power_reset() None
-

Shutdown instance and start.

-

By analogy with real hardware, this is a normal server shutdown, -and then turning off from the power supply and turning it on again.

-

This method is applicable in cases where there has been a -configuration change in libvirt and you need to restart the -instance to apply the new configuration.

-
- -
-
-reboot() None
-

Send ACPI signal to guest OS to reboot. OS may ignore this.

-
- -
-
-reset() None
-

Reset instance.

-

Copypaste from libvirt doc:

-

Reset a domain immediately without any guest OS shutdown. -Reset emulates the power reset button on a machine, where all -hardware sees the RST line set and reinitializes internal state.

-

Note that there is a risk of data loss caused by reset without any -guest OS shutdown.

-
- -
-
-resize_disk(name: str, capacity: int, unit: DataUnit) None
-

Resize attached block device.

-
-
Parameters:
-
    -
  • name – Disk device name e.g. vda, sda, etc.

  • -
  • capacity – New capacity.

  • -
  • unit – Capacity unit.

  • -
-
-
-
- -
-
-resume() None
-

Resume paused instance.

-
- -
-
-set_autostart(*, enabled: bool) None
-

Set autostart flag for instance.

-
-
Parameters:
-

enabled – Bool argument to set or unset autostart flag.

-
-
-
- -
-
-set_memory(memory: int, *, live: bool = False) None
-

Set memory.

-

If live is True and instance is not currently running set memory -in config and will applied when instance boot.

-
-
Parameters:
-
    -
  • memory – Memory value in mebibytes

  • -
  • live – Affect a running instance

  • -
-
-
-
- -
-
-set_ssh_keys(user: str, ssh_keys: list[str]) None
-

Add SSH keys to guest for specific user.

-
-
Parameters:
-
    -
  • user – Username.

  • -
  • ssh_keys – List of public SSH keys.

  • -
-
-
-
- -
-
-set_user_password(user: str, password: str, *, encrypted: bool = False) None
-

Set new user password in guest OS.

-

This action performs by guest agent inside the guest.

-
-
Parameters:
-
    -
  • user – Username.

  • -
  • password – Password.

  • -
  • encrypted – Set it to True if password is already encrypted. -Right encryption method depends on guest OS.

  • -
-
-
-
- -
-
-set_vcpus(nvcpus: int, *, live: bool = False) None
-

Set vCPU number.

-

If live is True and instance is not currently running vCPUs -will set in config and will applied when instance boot.

-

NB: Note that if this call is executed before the guest has -finished booting, the guest may fail to process the change.

-
-
Parameters:
-
    -
  • nvcpus – Number of vCPUs

  • -
  • live – Affect a running instance

  • -
-
-
-
- -
-
-shutdown(method: str | None = None) None
-

Shutdown instance.

-

Shutdown methods:

-
-
SOFT

Use guest agent to shutdown. If guest agent is unavailable -NORMAL method will be used.

-
-
NORMAL

Use method choosen by hypervisor to shutdown. Usually send ACPI -signal to guest OS. OS may ignore ACPI e.g. if guest is hanged.

-
-
HARD

Shutdown instance without any guest OS shutdown. This is simular -to unplugging machine from power. Internally send SIGTERM to -instance process and destroy it gracefully.

-
-
UNSAFE

Force shutdown. Internally send SIGKILL to instance process. -There is high data corruption risk!

-
-
-

If method is None NORMAL method will used.

-
-
Parameters:
-

method – Method used to shutdown instance

-
-
-
- -
-
-start() None
-

Start defined instance.

-
- -
- -
-
-class compute.instance.instance.InstanceConfig(schema: InstanceSchema)
-

Compute instance XML config builder.

-
-
-__init__(schema: InstanceSchema)
-

Initialise InstanceConfig.

-
-
Parameters:
-

schema – InstanceSchema object

-
-
-
- -
-
-to_xml() str
-

Return XML config for libvirt.

-
- -
- -
-
-class compute.instance.instance.InstanceInfo(state: str, max_memory: int, memory: int, nproc: int, cputime: int)
-

Store compute instance info.

-

Reference: -https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainInfo

-
-
-cputime: int
-

Alias for field number 4

-
- -
-
-max_memory: int
-

Alias for field number 1

-
- -
-
-memory: int
-

Alias for field number 2

-
- -
-
-nproc: int
-

Alias for field number 3

-
- -
-
-state: str
-

Alias for field number 0

-
- -
- -
- - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/instance/schemas.html b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/instance/schemas.html deleted file mode 100644 index ef15eb2..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/instance/schemas.html +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - schemas — Compute 0.1.0 documentation - - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

schemas

-

Compute instance related objects schemas.

-
-
-class compute.instance.schemas.BootOptionsSchema(*, order: tuple)
-

Instance boot settings.

-
- -
-
-class compute.instance.schemas.CPUEmulationMode(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
-

CPU emulation mode enumerated.

-
- -
-
-class compute.instance.schemas.CPUFeaturesSchema(*, require: list[str], disable: list[str])
-

CPU features model.

-
- -
-
-class compute.instance.schemas.CPUSchema(*, emulation_mode: CPUEmulationMode, model: str | None = None, vendor: str | None = None, topology: compute.instance.schemas.CPUTopologySchema | None = None, features: compute.instance.schemas.CPUFeaturesSchema | None = None)
-

CPU model.

-
- -
-
-class compute.instance.schemas.CPUTopologySchema(*, sockets: int, cores: int, threads: int, dies: int = 1)
-

CPU topology model.

-
- -
-
-class compute.instance.schemas.EntityModel
-

Basic entity model.

-
-
-class Config
-

Do not allow extra fields.

-
- -
- -
-
-class compute.instance.schemas.InstanceSchema(*, name: str, title: str | None = None, description: str | None = None, memory: int, max_memory: int, vcpus: int, max_vcpus: int, cpu: CPUSchema, machine: str, emulator: Path, arch: str, boot: BootOptionsSchema, volumes: list[compute.instance.schemas.VolumeSchema], network_interfaces: list[compute.instance.schemas.NetworkInterfaceSchema], image: str | None = None)
-

Compute instance model.

-
- -
-
-class compute.instance.schemas.NetworkInterfaceSchema(*, source: str, mac: str)
-

Network inerface model.

-
- -
-
-class compute.instance.schemas.VolumeCapacitySchema(*, value: int, unit: DataUnit)
-

Storage volume capacity field model.

-
- -
-
-class compute.instance.schemas.VolumeSchema(*, type: VolumeType, target: str, capacity: VolumeCapacitySchema, source: str | None = None, is_readonly: bool = False, is_system: bool = False)
-

Storage volume model.

-
- -
-
-class compute.instance.schemas.VolumeType(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
-

Storage volume types enumeration.

-
- -
- - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/session.html b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/session.html deleted file mode 100644 index 6babb3e..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/session.html +++ /dev/null @@ -1,331 +0,0 @@ - - - - - - - - - session — Compute 0.1.0 documentation - - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

session

-

Hypervisor session manager.

-
-
-class compute.session.Capabilities(arch: str, virt_type: str, emulator: str, machine: str, max_vcpus: int, cpu_vendor: str, cpu_model: str, cpu_features: dict, usable_cpus: list[dict])
-

Store domain capabilities info.

-
-
-arch: str
-

Alias for field number 0

-
- -
-
-cpu_features: dict
-

Alias for field number 7

-
- -
-
-cpu_model: str
-

Alias for field number 6

-
- -
-
-cpu_vendor: str
-

Alias for field number 5

-
- -
-
-emulator: str
-

Alias for field number 2

-
- -
-
-machine: str
-

Alias for field number 3

-
- -
-
-max_vcpus: int
-

Alias for field number 4

-
- -
-
-usable_cpus: list[dict]
-

Alias for field number 8

-
- -
-
-virt_type: str
-

Alias for field number 1

-
- -
- -
-
-class compute.session.NodeInfo(arch: str, memory: int, cpus: int, mhz: int, nodes: int, sockets: int, cores: int, threads: int)
-

Store compute node info.

-

See https://libvirt.org/html/libvirt-libvirt-host.html#virNodeInfo -NOTE: memory unit in libvirt docs is wrong! Actual unit is MiB.

-
-
-arch: str
-

Alias for field number 0

-
- -
-
-cores: int
-

Alias for field number 6

-
- -
-
-cpus: int
-

Alias for field number 2

-
- -
-
-memory: int
-

Alias for field number 1

-
- -
-
-mhz: int
-

Alias for field number 3

-
- -
-
-nodes: int
-

Alias for field number 4

-
- -
-
-sockets: int
-

Alias for field number 5

-
- -
-
-threads: int
-

Alias for field number 7

-
- -
- -
-
-class compute.session.Session(uri: str | None = None)
-

Hypervisor session context manager.

-
-
Variables:
-
    -
  • IMAGES_POOL – images storage pool name taken from env

  • -
  • VOLUMES_POOL – volumes storage pool name taken from env

  • -
-
-
-
-
-__init__(uri: str | None = None)
-

Initialise session with hypervisor.

-
-
Variables:
-
    -
  • uri (str) – libvirt connection URI.

  • -
  • connection (libvirt.virConnect) – libvirt connection object.

  • -
-
-
Parameters:
-

uri – libvirt connection URI.

-
-
-
- -
-
-close() None
-

Close connection to libvirt daemon.

-
- -
-
-create_instance(**kwargs: Any) Instance
-

Create and return new compute instance.

-
-
Parameters:
-
    -
  • name (str) – Instance name.

  • -
  • title (str) – Instance title for humans.

  • -
  • description (str) – Some information about instance.

  • -
  • memory (int) – Memory in MiB.

  • -
  • max_memory (int) – Maximum memory in MiB.

  • -
  • vcpus (int) – Number of vCPUs.

  • -
  • max_vcpus (int) – Maximum vCPUs.

  • -
  • cpu (dict) – CPU configuration. See CPUSchema for info.

  • -
  • machine (str) – QEMU emulated machine.

  • -
  • emulator (str) – Path to emulator.

  • -
  • arch (str) – CPU architecture to virtualization.

  • -
  • boot (dict) – Boot settings. See BootOptionsSchema.

  • -
  • image (str) – Source disk image name for system disk.

  • -
  • volumes (list[dict]) – List of storage volume configs. For more info -see VolumeSchema.

  • -
  • network_interfaces (list[dict]) – List of virtual network interfaces -configs. See NetworkInterfaceSchema for more info.

  • -
-
-
-
- -
-
-get_capabilities() Capabilities
-

Return capabilities e.g. arch, virt, emulator, etc.

-
- -
-
-get_instance(name: str) Instance
-

Get compute instance by name.

-
- -
-
-get_node_info() NodeInfo
-

Return information about compute node.

-
- -
-
-get_storage_pool(name: str) StoragePool
-

Get storage pool by name.

-
- -
-
-list_instances() list[compute.instance.instance.Instance]
-

List all instances.

-
- -
-
-list_storage_pools() list[compute.storage.pool.StoragePool]
-

List all strage pools.

-
- -
- -
- - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/storage/index.html b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/storage/index.html deleted file mode 100644 index 0a6ca1b..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/storage/index.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - - - - storage — Compute 0.1.0 documentation - - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

storage

-
-

Contents:

- -
-
- - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/storage/pool.html b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/storage/pool.html deleted file mode 100644 index 43fa341..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/storage/pool.html +++ /dev/null @@ -1,201 +0,0 @@ - - - - - - - - - pool — Compute 0.1.0 documentation - - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

pool

-

Manage storage pools.

-
-
-class compute.storage.pool.StoragePool(pool: virStoragePool)
-

Storage pool manipulating class.

-
-
-__init__(pool: virStoragePool)
-

Initislise StoragePool.

-
- -
-
-clone_volume(src: Volume, dst: VolumeConfig) Volume
-

Make storage volume copy.

-
-
Parameters:
-
    -
  • src – Input volume

  • -
  • dst – Output volume config

  • -
-
-
-
- -
-
-create_volume(vol_conf: VolumeConfig) Volume
-

Create storage volume and return Volume instance.

-
- -
-
-dump_xml() str
-

Return storage pool XML description as string.

-
- -
-
-get_usage_info() StoragePoolUsageInfo
-

Return info about storage pool usage.

-
- -
-
-get_volume(name: str) compute.storage.volume.Volume | None
-

Lookup and return Volume instance or None.

-
- -
-
-list_volumes() list[compute.storage.volume.Volume]
-

Return list of volumes in storage pool.

-
- -
-
-refresh() None
-

Refresh storage pool.

-
- -
- -
-
-class compute.storage.pool.StoragePoolUsageInfo(capacity: int, allocation: int, available: int)
-

Storage pool usage info.

-
-
-allocation: int
-

Alias for field number 1

-
- -
-
-available: int
-

Alias for field number 2

-
- -
-
-capacity: int
-

Alias for field number 0

-
- -
- -
- - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/storage/volume.html b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/storage/volume.html deleted file mode 100644 index 9e35b8f..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/storage/volume.html +++ /dev/null @@ -1,210 +0,0 @@ - - - - - - - - - volume — Compute 0.1.0 documentation - - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

volume

-

Manage storage volumes.

-
-
-class compute.storage.volume.DiskConfig(disk_type: str, source: str | pathlib.Path, target: str, readonly: bool = False)
-

Disk XML config builder.

-

Generate XML config for attaching or detaching storage volumes -to compute instances.

-
-
-__init__(disk_type: str, source: str | pathlib.Path, target: str, readonly: bool = False) None
-
- -
-
-to_xml() str
-

Return XML config for libvirt.

-
- -
- -
-
-class compute.storage.volume.Volume(pool: virStoragePool, vol: virStorageVol)
-

Storage volume manipulating class.

-
-
-__init__(pool: virStoragePool, vol: virStorageVol)
-

Initialise Volume.

-
-
Parameters:
-
    -
  • pool – libvirt virStoragePool object

  • -
  • vol – libvirt virStorageVol object

  • -
-
-
-
- -
-
-clone(vol_conf: VolumeConfig) None
-

Make a copy of volume to the same storage pool.

-
-
Parameters:
-

VolumeInfo (vol_info) – New storage volume dataclass object

-
-
-
- -
-
-delete() None
-

Delete volume from storage pool.

-
- -
-
-dump_xml() str
-

Return volume XML description as string.

-
- -
-
-resize(capacity: int, unit: DataUnit) None
-

Resize volume.

-
-
Parameters:
-
    -
  • int (capacity) – Volume new capacity.

  • -
  • DataUnit (unit) – Data unit. Internally converts into bytes.

  • -
-
-
-
- -
- -
-
-class compute.storage.volume.VolumeConfig(name: str, path: str, capacity: int)
-

Storage volume XML config builder.

-

Generate XML config for creating a volume in a libvirt -storage pool.

-
-
-__init__(name: str, path: str, capacity: int) None
-
- -
-
-to_xml() str
-

Return XML config for libvirt.

-
- -
- -
- - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/utils.html b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/utils.html deleted file mode 100644 index b09e008..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/pyapi/utils.html +++ /dev/null @@ -1,144 +0,0 @@ - - - - - - - - - utils — Compute 0.1.0 documentation - - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

utils

-
-

utils.units

-

Tools for data units convertion.

-
-
-class compute.utils.units.DataUnit(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
-

Data units enumerated.

-
- -
-
-exception compute.utils.units.InvalidDataUnitError(msg: str)
-

Data unit is not valid.

-
- -
-
-compute.utils.units.to_bytes(value: int, unit: DataUnit = DataUnit.BYTES) int
-

Convert value to bytes. See DataUnit.

-
- -
-
-

utils.ids

-

Random identificators.

-
-
-compute.utils.ids.random_mac() str
-

Retrun random MAC address.

-
- -
-
- - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/search.html b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/search.html deleted file mode 100644 index 60189cf..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/search.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - Search — Compute 0.1.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -

Search

- - - - -

- Searching for multiple words only shows matches that contain - all words. -

- - -
- - - -
- - - -
- -
- - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/searchindex.js b/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/searchindex.js deleted file mode 100644 index d20a6ca..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute-doc/usr/share/doc/compute-doc/html/searchindex.js +++ /dev/null @@ -1 +0,0 @@ -Search.setIndex({"docnames": ["index", "pyapi/exceptions", "pyapi/index", "pyapi/instance/guest_agent", "pyapi/instance/index", "pyapi/instance/instance", "pyapi/instance/schemas", "pyapi/session", "pyapi/storage/index", "pyapi/storage/pool", "pyapi/storage/volume", "pyapi/utils"], "filenames": ["index.rst", "pyapi/exceptions.rst", "pyapi/index.rst", "pyapi/instance/guest_agent.rst", "pyapi/instance/index.rst", "pyapi/instance/instance.rst", "pyapi/instance/schemas.rst", "pyapi/session.rst", "pyapi/storage/index.rst", "pyapi/storage/pool.rst", "pyapi/storage/volume.rst", "pyapi/utils.rst"], "titles": ["Compute", "exceptions", "Python API", "guest_agent", "instance", "instance", "schemas", "session", "storage", "pool", "volume", "utils"], "terms": {"instanc": [0, 2, 3, 6, 7, 9, 10], "manag": [0, 2, 5, 7, 9, 10], "librari": [0, 2], "python": 0, "api": 0, "index": 0, "modul": [0, 6, 11], "search": 0, "page": 0, "comput": [1, 2, 3, 5, 6, 7, 9, 10, 11], "computeerror": [1, 2], "basic": [1, 6], "class": [1, 2, 3, 5, 6, 7, 9, 10, 11], "configloadererror": [1, 2], "someth": 1, "went": 1, "wrong": [1, 7], "when": [1, 5], "load": 1, "configur": [1, 2, 5, 7], "guestagentcommandnotsupportederror": [1, 2, 3], "guest": [1, 3, 5], "agent": [1, 3, 5], "command": [1, 3], "i": [1, 2, 3, 5, 7, 11], "support": [1, 3], "blacklist": 1, "guestagenterror": [1, 2], "wring": 1, "qemu": [1, 3, 7], "call": [1, 2, 5], "guestagenttimeoutexceedederror": [1, 2], "msg": [1, 11], "int": [1, 3, 5, 6, 7, 9, 10, 11], "timeout": [1, 3], "exceed": 1, "guestagentunavailableerror": [1, 2], "connect": [1, 5, 7], "unavail": [1, 5], "instanceerror": [1, 2], "while": 1, "interact": [1, 3], "domain": [1, 3, 5, 7], "instancenotfounderror": [1, 2], "str": [1, 3, 5, 6, 7, 9, 10, 11], "virtual": [1, 7], "machin": [1, 2, 5, 6, 7], "contain": 1, "found": 1, "node": [1, 2, 7], "sessionerror": [1, 2], "libvirtd": 1, "storagepoolerror": [1, 2], "oper": [1, 2], "storag": [1, 2, 5, 6, 7, 9, 10], "pool": [1, 2, 7, 8, 10], "storagepoolnotfounderror": [1, 2], "volumenotfounderror": [1, 2], "volum": [1, 2, 5, 6, 7, 8, 9], "The": 2, "allow": [2, 6], "you": [2, 5], "perform": [2, 5], "action": [2, 5], "programmat": 2, "below": 2, "an": 2, "exampl": [2, 3], "chang": [2, 5], "paramet": [2, 3, 5, 7, 9, 10], "launch": 2, "myinstanc": 2, "import": 2, "log": 2, "from": [2, 5, 7, 10], "session": 2, "basicconfig": 2, "level": 2, "debug": 2, "get_inst": [2, 7], "set_vcpu": [2, 5], "4": [2, 5, 7], "start": [2, 5, 6, 11], "set_autostart": [2, 5], "enabl": [2, 5], "true": [2, 3, 5], "context": [2, 7], "provid": 2, "abstract": 2, "over": 2, "libvirt": [2, 3, 5, 7, 10], "virconnect": [2, 5, 7], "return": [2, 3, 5, 7, 9, 10], "object": [2, 3, 5, 6, 7, 10], "other": 2, "present": 2, "ar": 2, "repres": 2, "These": 2, "directli": 2, "method": [2, 5], "hypervisor": [2, 5, 7], "file": 2, "variou": 2, "describ": 2, "special": 2, "dataclass": [2, 10], "store": [2, 5, 7], "its": 2, "properti": 2, "can": 2, "xml": [2, 5, 9, 10], "config": [2, 5, 6, 7, 9, 10], "us": [2, 3, 5], "to_xml": [2, 5, 10], "For": [2, 3, 7], "volumeconfig": [2, 9, 10], "pydant": 2, "model": [2, 6], "valid": [2, 11], "input": [2, 9], "data": [2, 3, 5, 10, 11], "volumeschema": [2, 6, 7], "capabl": [2, 7], "arch": [2, 6, 7], "cpu_featur": [2, 7], "cpu_model": [2, 7], "cpu_vendor": [2, 7], "emul": [2, 5, 6, 7], "max_vcpu": [2, 6, 7], "usable_cpu": [2, 7], "virt_typ": [2, 7], "nodeinfo": [2, 7], "core": [2, 6, 7], "cpu": [2, 6, 7], "memori": [2, 5, 6, 7], "mhz": [2, 7], "socket": [2, 6, 7], "thread": [2, 6, 7], "__init__": [2, 3, 5, 7, 9, 10], "close": [2, 7], "create_inst": [2, 7], "get_cap": [2, 7], "get_node_info": [2, 7], "get_storage_pool": [2, 7], "list_inst": [2, 7], "list_storage_pool": [2, 7], "attach_devic": [2, 5], "delet": [2, 5, 10], "delete_ssh_kei": [2, 5], "detach_devic": [2, 5], "detach_disk": [2, 5], "dump_xml": [2, 5, 9, 10], "get_disk": [2, 5], "get_info": [2, 5], "get_max_memori": [2, 5], "get_max_vcpu": [2, 5], "get_ssh_kei": [2, 5], "get_statu": [2, 5], "is_autostart": [2, 5], "is_run": [2, 5], "paus": [2, 5], "power_reset": [2, 5], "reboot": [2, 5], "reset": [2, 5], "resize_disk": [2, 5], "resum": [2, 5], "set_memori": [2, 5], "set_ssh_kei": [2, 5], "set_user_password": [2, 5], "shutdown": [2, 5], "instanceconfig": [2, 5], "instanceinfo": [2, 5], "cputim": [2, 5], "max_memori": [2, 5, 6, 7], "nproc": [2, 5], "state": [2, 5], "guest_ag": [2, 4, 5], "guestag": [2, 3, 5], "execut": [2, 3, 5], "get_supported_command": [2, 3], "guest_exec": [2, 3], "guest_exec_statu": [2, 3], "is_avail": [2, 3], "raise_for_command": [2, 3], "guestexecoutput": [2, 3], "exitcod": [2, 3], "exit": [2, 3], "stderr": [2, 3], "stdout": [2, 3], "schema": [2, 4, 5], "bootoptionsschema": [2, 6, 7], "cpuemulationmod": [2, 6], "cpufeaturesschema": [2, 6], "cpuschema": [2, 6, 7], "cputopologyschema": [2, 6], "entitymodel": [2, 6], "instanceschema": [2, 5, 6], "networkinterfaceschema": [2, 6, 7], "volumecapacityschema": [2, 6], "volumetyp": [2, 6], "storagepool": [2, 7, 9], "clone_volum": [2, 9], "create_volum": [2, 9], "get_usage_info": [2, 9], "get_volum": [2, 9], "list_volum": [2, 9], "refresh": [2, 9], "storagepoolusageinfo": [2, 9], "alloc": [2, 9], "avail": [2, 3, 9], "capac": [2, 5, 6, 9, 10], "diskconfig": [2, 5, 10], "clone": [2, 10], "resiz": [2, 5, 10], "util": 2, "unit": [2, 5, 6, 7, 10], "dataunit": [2, 5, 6, 10, 11], "invaliddatauniterror": [2, 11], "to_byt": [2, 11], "id": 2, "random_mac": [2, 11], "except": [2, 3, 11], "virdomain": [3, 5], "60": 3, "initialis": [3, 5, 7, 10], "dict": [3, 7], "see": [3, 5, 7, 11], "http": [3, 5, 7], "project": 3, "gitlab": 3, "io": 3, "interop": 3, "ga": 3, "ref": 3, "html": [3, 5, 7], "output": [3, 9], "type": [3, 6, 11], "set": [3, 5, 6, 7], "path": [3, 6, 7, 10], "arg": 3, "list": [3, 5, 6, 7, 9], "none": [3, 5, 6, 7, 9, 10, 11], "env": [3, 7], "stdin": 3, "capture_output": 3, "bool": [3, 5, 6, 10], "fals": [3, 5, 6, 10], "decode_output": 3, "poll": 3, "exec": 3, "ot": 3, "argument": [3, 5], "pass": 3, "environ": 3, "variabl": [3, 5, 7], "lang": 3, "c": 3, "term": 3, "xterm": 3, "captur": 3, "base64_decod": 3, "decod": 3, "affect": [3, 5], "onli": 3, "self": 3, "poll_interv": 3, "constant": 3, "pid": 3, "float": 3, "0": [3, 5, 7, 9], "3": [3, 5, 7], "statu": 3, "If": [3, 5], "time": 3, "between": 3, "attempt": 3, "obtain": 3, "ping": 3, "unreach": 3, "rais": 3, "requir": [3, 6], "alia": [3, 5, 7, 9], "field": [3, 5, 6, 7, 9], "number": [3, 5, 7, 9], "1": [3, 5, 6, 7, 9, 11], "2": [3, 5, 7, 9], "name": [5, 6, 7, 9, 10, 11], "devic": 5, "entityconfig": 5, "live": 5, "attach": [5, 10], "descript": [5, 6, 7, 9, 10], "e": [5, 7], "g": [5, 7], "run": 5, "undefin": 5, "user": 5, "ssh_kei": 5, "remov": 5, "ssh": 5, "kei": 5, "specif": 5, "usernam": 5, "public": 5, "dettach": 5, "detach": [5, 10], "disk": [5, 7, 10], "target": [5, 6, 10], "There": 5, "attach_disk": 5, "vda": 5, "sda": 5, "etc": [5, 7], "thi": 5, "mai": 5, "match": 5, "insid": 5, "o": 5, "inact": 5, "info": [5, 7, 9], "maximum": [5, 7], "valu": [5, 6, 11], "kib": 5, "vcpu": [5, 6, 7], "shutoff": 5, "refer": 5, "org": [5, 7], "virdomainst": 5, "autostart": 5, "els": 5, "By": 5, "analogi": 5, "real": 5, "hardwar": 5, "normal": 5, "server": 5, "turn": 5, "off": 5, "power": 5, "suppli": 5, "again": 5, "applic": 5, "case": 5, "where": 5, "ha": 5, "been": 5, "need": 5, "restart": 5, "appli": 5, "new": [5, 7, 10], "send": 5, "acpi": 5, "signal": 5, "ignor": 5, "copypast": 5, "doc": [5, 7], "immedi": 5, "without": 5, "ani": [5, 7], "button": 5, "all": [5, 7], "rst": 5, "line": 5, "reiniti": 5, "intern": [5, 10], "note": [5, 7], "risk": 5, "loss": 5, "caus": 5, "block": 5, "flag": 5, "unset": 5, "current": 5, "boot": [5, 6, 7], "mebibyt": 5, "add": 5, "password": 5, "encrypt": 5, "alreadi": 5, "right": 5, "depend": 5, "nvcpu": 5, "nb": 5, "befor": 5, "finish": 5, "fail": 5, "process": 5, "soft": 5, "choosen": 5, "usual": 5, "hang": 5, "hard": 5, "simular": 5, "unplug": 5, "sigterm": 5, "destroi": 5, "gracefulli": 5, "unsaf": 5, "forc": 5, "sigkil": 5, "high": 5, "corrupt": 5, "defin": 5, "builder": [5, 10], "virdomaininfo": 5, "relat": 6, "order": 6, "tupl": 6, "qualnam": [6, 11], "boundari": [6, 11], "mode": 6, "enumer": [6, 11], "disabl": 6, "featur": 6, "emulation_mod": 6, "vendor": 6, "topologi": 6, "di": 6, "entiti": 6, "do": 6, "extra": 6, "titl": [6, 7], "network_interfac": [6, 7], "imag": [6, 7], "sourc": [6, 7, 10], "mac": [6, 11], "network": [6, 7], "inerfac": 6, "is_readonli": 6, "is_system": 6, "7": 7, "6": 7, "5": 7, "8": 7, "host": 7, "virnodeinfo": 7, "actual": 7, "mib": 7, "uri": 7, "images_pool": 7, "taken": 7, "volumes_pool": 7, "daemon": 7, "kwarg": 7, "creat": [7, 9, 10], "human": 7, "some": 7, "inform": 7, "about": [7, 9], "architectur": 7, "system": 7, "more": 7, "interfac": 7, "virt": 7, "get": 7, "strage": 7, "virstoragepool": [9, 10], "manipul": [9, 10], "initislis": 9, "src": 9, "dst": 9, "make": [9, 10], "copi": [9, 10], "vol_conf": [9, 10], "string": [9, 10], "usag": 9, "lookup": 9, "disk_typ": 10, "pathlib": 10, "readonli": 10, "gener": 10, "vol": 10, "virstoragevol": 10, "same": 10, "volumeinfo": 10, "vol_info": 10, "convert": [10, 11], "byte": [10, 11], "tool": 11, "random": 11, "identif": 11, "retrun": 11, "address": 11}, "objects": {"compute": [[1, 0, 0, "-", "exceptions"], [7, 0, 0, "-", "session"]], "compute.exceptions": [[1, 1, 1, "", "ComputeError"], [1, 1, 1, "", "ConfigLoaderError"], [1, 1, 1, "", "GuestAgentCommandNotSupportedError"], [1, 1, 1, "", "GuestAgentError"], [1, 1, 1, "", "GuestAgentTimeoutExceededError"], [1, 1, 1, "", "GuestAgentUnavailableError"], [1, 1, 1, "", "InstanceError"], [1, 1, 1, "", "InstanceNotFoundError"], [1, 1, 1, "", "SessionError"], [1, 1, 1, "", "StoragePoolError"], [1, 1, 1, "", "StoragePoolNotFoundError"], [1, 1, 1, "", "VolumeNotFoundError"]], "compute.instance": [[3, 0, 0, "-", "guest_agent"], [5, 0, 0, "-", "instance"], [6, 0, 0, "-", "schemas"]], "compute.instance.guest_agent": [[3, 2, 1, "", "GuestAgent"], [3, 2, 1, "", "GuestExecOutput"]], "compute.instance.guest_agent.GuestAgent": [[3, 3, 1, "", "__init__"], [3, 3, 1, "", "execute"], [3, 3, 1, "", "get_supported_commands"], [3, 3, 1, "", "guest_exec"], [3, 3, 1, "", "guest_exec_status"], [3, 3, 1, "", "is_available"], [3, 3, 1, "", "raise_for_commands"]], "compute.instance.guest_agent.GuestExecOutput": [[3, 4, 1, "", "exitcode"], [3, 4, 1, "", "exited"], [3, 4, 1, "", "stderr"], [3, 4, 1, "", "stdout"]], "compute.instance.instance": [[5, 2, 1, "", "Instance"], [5, 2, 1, "", "InstanceConfig"], [5, 2, 1, "", "InstanceInfo"]], "compute.instance.instance.Instance": [[5, 3, 1, "", "__init__"], [5, 3, 1, "", "attach_device"], [5, 3, 1, "", "delete"], [5, 3, 1, "", "delete_ssh_keys"], [5, 3, 1, "", "detach_device"], [5, 3, 1, "", "detach_disk"], [5, 3, 1, "", "dump_xml"], [5, 3, 1, "", "get_disks"], [5, 3, 1, "", "get_info"], [5, 3, 1, "", "get_max_memory"], [5, 3, 1, "", "get_max_vcpus"], [5, 3, 1, "", "get_ssh_keys"], [5, 3, 1, "", "get_status"], [5, 3, 1, "", "is_autostart"], [5, 3, 1, "", "is_running"], [5, 3, 1, "", "pause"], [5, 3, 1, "", "power_reset"], [5, 3, 1, "", "reboot"], [5, 3, 1, "", "reset"], [5, 3, 1, "", "resize_disk"], [5, 3, 1, "", "resume"], [5, 3, 1, "", "set_autostart"], [5, 3, 1, "", "set_memory"], [5, 3, 1, "", "set_ssh_keys"], [5, 3, 1, "", "set_user_password"], [5, 3, 1, "", "set_vcpus"], [5, 3, 1, "", "shutdown"], [5, 3, 1, "", "start"]], "compute.instance.instance.InstanceConfig": [[5, 3, 1, "", "__init__"], [5, 3, 1, "", "to_xml"]], "compute.instance.instance.InstanceInfo": [[5, 4, 1, "", "cputime"], [5, 4, 1, "", "max_memory"], [5, 4, 1, "", "memory"], [5, 4, 1, "", "nproc"], [5, 4, 1, "", "state"]], "compute.instance.schemas": [[6, 2, 1, "", "BootOptionsSchema"], [6, 2, 1, "", "CPUEmulationMode"], [6, 2, 1, "", "CPUFeaturesSchema"], [6, 2, 1, "", "CPUSchema"], [6, 2, 1, "", "CPUTopologySchema"], [6, 2, 1, "", "EntityModel"], [6, 2, 1, "", "InstanceSchema"], [6, 2, 1, "", "NetworkInterfaceSchema"], [6, 2, 1, "", "VolumeCapacitySchema"], [6, 2, 1, "", "VolumeSchema"], [6, 2, 1, "", "VolumeType"]], "compute.instance.schemas.EntityModel": [[6, 2, 1, "", "Config"]], "compute.session": [[7, 2, 1, "", "Capabilities"], [7, 2, 1, "", "NodeInfo"], [7, 2, 1, "", "Session"]], "compute.session.Capabilities": [[7, 4, 1, "", "arch"], [7, 4, 1, "", "cpu_features"], [7, 4, 1, "", "cpu_model"], [7, 4, 1, "", "cpu_vendor"], [7, 4, 1, "", "emulator"], [7, 4, 1, "", "machine"], [7, 4, 1, "", "max_vcpus"], [7, 4, 1, "", "usable_cpus"], [7, 4, 1, "", "virt_type"]], "compute.session.NodeInfo": [[7, 4, 1, "", "arch"], [7, 4, 1, "", "cores"], [7, 4, 1, "", "cpus"], [7, 4, 1, "", "memory"], [7, 4, 1, "", "mhz"], [7, 4, 1, "", "nodes"], [7, 4, 1, "", "sockets"], [7, 4, 1, "", "threads"]], "compute.session.Session": [[7, 3, 1, "", "__init__"], [7, 3, 1, "", "close"], [7, 3, 1, "", "create_instance"], [7, 3, 1, "", "get_capabilities"], [7, 3, 1, "", "get_instance"], [7, 3, 1, "", "get_node_info"], [7, 3, 1, "", "get_storage_pool"], [7, 3, 1, "", "list_instances"], [7, 3, 1, "", "list_storage_pools"]], "compute.storage": [[9, 0, 0, "-", "pool"], [10, 0, 0, "-", "volume"]], "compute.storage.pool": [[9, 2, 1, "", "StoragePool"], [9, 2, 1, "", "StoragePoolUsageInfo"]], "compute.storage.pool.StoragePool": [[9, 3, 1, "", "__init__"], [9, 3, 1, "", "clone_volume"], [9, 3, 1, "", "create_volume"], [9, 3, 1, "", "dump_xml"], [9, 3, 1, "", "get_usage_info"], [9, 3, 1, "", "get_volume"], [9, 3, 1, "", "list_volumes"], [9, 3, 1, "", "refresh"]], "compute.storage.pool.StoragePoolUsageInfo": [[9, 4, 1, "", "allocation"], [9, 4, 1, "", "available"], [9, 4, 1, "", "capacity"]], "compute.storage.volume": [[10, 2, 1, "", "DiskConfig"], [10, 2, 1, "", "Volume"], [10, 2, 1, "", "VolumeConfig"]], "compute.storage.volume.DiskConfig": [[10, 3, 1, "", "__init__"], [10, 3, 1, "", "to_xml"]], "compute.storage.volume.Volume": [[10, 3, 1, "", "__init__"], [10, 3, 1, "", "clone"], [10, 3, 1, "", "delete"], [10, 3, 1, "", "dump_xml"], [10, 3, 1, "", "resize"]], "compute.storage.volume.VolumeConfig": [[10, 3, 1, "", "__init__"], [10, 3, 1, "", "to_xml"]], "compute.utils": [[11, 0, 0, "-", "ids"], [11, 0, 0, "-", "units"]], "compute.utils.ids": [[11, 5, 1, "", "random_mac"]], "compute.utils.units": [[11, 2, 1, "", "DataUnit"], [11, 1, 1, "", "InvalidDataUnitError"], [11, 5, 1, "", "to_bytes"]]}, "objtypes": {"0": "py:module", "1": "py:exception", "2": "py:class", "3": "py:method", "4": "py:attribute", "5": "py:function"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "exception", "Python exception"], "2": ["py", "class", "Python class"], "3": ["py", "method", "Python method"], "4": ["py", "attribute", "Python attribute"], "5": ["py", "function", "Python function"]}, "titleterms": {"comput": 0, "indic": 0, "tabl": 0, "except": 1, "python": 2, "api": 2, "entiti": 2, "represent": 2, "modul": 2, "document": 2, "guest_ag": 3, "instanc": [4, 5], "content": [4, 8], "schema": 6, "session": 7, "storag": 8, "pool": 9, "volum": 10, "util": 11, "unit": 11, "id": 11}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 8, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 57}, "alltitles": {"Compute": [[0, "compute"]], "Indices and tables": [[0, "indices-and-tables"]], "exceptions": [[1, "module-compute.exceptions"]], "Python API": [[2, "python-api"]], "Entity representation": [[2, "entity-representation"]], "Modules documentation": [[2, "modules-documentation"]], "guest_agent": [[3, "module-compute.instance.guest_agent"]], "instance": [[4, "instance"], [5, "module-compute.instance.instance"]], "Contents:": [[4, null], [8, null]], "schemas": [[6, "module-compute.instance.schemas"]], "session": [[7, "module-compute.session"]], "storage": [[8, "storage"]], "pool": [[9, "module-compute.storage.pool"]], "volume": [[10, "module-compute.storage.volume"]], "utils": [[11, "utils"]], "utils.units": [[11, "module-compute.utils.units"]], "utils.ids": [[11, "module-compute.utils.ids"]]}, "indexentries": {"computeerror": [[1, "compute.exceptions.ComputeError"]], "configloadererror": [[1, "compute.exceptions.ConfigLoaderError"]], "guestagentcommandnotsupportederror": [[1, "compute.exceptions.GuestAgentCommandNotSupportedError"]], "guestagenterror": [[1, "compute.exceptions.GuestAgentError"]], "guestagenttimeoutexceedederror": [[1, "compute.exceptions.GuestAgentTimeoutExceededError"]], "guestagentunavailableerror": [[1, "compute.exceptions.GuestAgentUnavailableError"]], "instanceerror": [[1, "compute.exceptions.InstanceError"]], "instancenotfounderror": [[1, "compute.exceptions.InstanceNotFoundError"]], "sessionerror": [[1, "compute.exceptions.SessionError"]], "storagepoolerror": [[1, "compute.exceptions.StoragePoolError"]], "storagepoolnotfounderror": [[1, "compute.exceptions.StoragePoolNotFoundError"]], "volumenotfounderror": [[1, "compute.exceptions.VolumeNotFoundError"]], "compute.exceptions": [[1, "module-compute.exceptions"]], "module": [[1, "module-compute.exceptions"], [3, "module-compute.instance.guest_agent"], [5, "module-compute.instance.instance"], [6, "module-compute.instance.schemas"], [7, "module-compute.session"], [9, "module-compute.storage.pool"], [10, "module-compute.storage.volume"], [11, "module-compute.utils.ids"], [11, "module-compute.utils.units"]], "guestagent (class in compute.instance.guest_agent)": [[3, "compute.instance.guest_agent.GuestAgent"]], "guestexecoutput (class in compute.instance.guest_agent)": [[3, "compute.instance.guest_agent.GuestExecOutput"]], "__init__() (compute.instance.guest_agent.guestagent method)": [[3, "compute.instance.guest_agent.GuestAgent.__init__"]], "compute.instance.guest_agent": [[3, "module-compute.instance.guest_agent"]], "execute() (compute.instance.guest_agent.guestagent method)": [[3, "compute.instance.guest_agent.GuestAgent.execute"]], "exitcode (compute.instance.guest_agent.guestexecoutput attribute)": [[3, "compute.instance.guest_agent.GuestExecOutput.exitcode"]], "exited (compute.instance.guest_agent.guestexecoutput attribute)": [[3, "compute.instance.guest_agent.GuestExecOutput.exited"]], "get_supported_commands() (compute.instance.guest_agent.guestagent method)": [[3, "compute.instance.guest_agent.GuestAgent.get_supported_commands"]], "guest_exec() (compute.instance.guest_agent.guestagent method)": [[3, "compute.instance.guest_agent.GuestAgent.guest_exec"]], "guest_exec_status() (compute.instance.guest_agent.guestagent method)": [[3, "compute.instance.guest_agent.GuestAgent.guest_exec_status"]], "is_available() (compute.instance.guest_agent.guestagent method)": [[3, "compute.instance.guest_agent.GuestAgent.is_available"]], "raise_for_commands() (compute.instance.guest_agent.guestagent method)": [[3, "compute.instance.guest_agent.GuestAgent.raise_for_commands"]], "stderr (compute.instance.guest_agent.guestexecoutput attribute)": [[3, "compute.instance.guest_agent.GuestExecOutput.stderr"]], "stdout (compute.instance.guest_agent.guestexecoutput attribute)": [[3, "compute.instance.guest_agent.GuestExecOutput.stdout"]], "instance (class in compute.instance.instance)": [[5, "compute.instance.instance.Instance"]], "instanceconfig (class in compute.instance.instance)": [[5, "compute.instance.instance.InstanceConfig"]], "instanceinfo (class in compute.instance.instance)": [[5, "compute.instance.instance.InstanceInfo"]], "__init__() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.__init__"]], "__init__() (compute.instance.instance.instanceconfig method)": [[5, "compute.instance.instance.InstanceConfig.__init__"]], "attach_device() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.attach_device"]], "compute.instance.instance": [[5, "module-compute.instance.instance"]], "cputime (compute.instance.instance.instanceinfo attribute)": [[5, "compute.instance.instance.InstanceInfo.cputime"]], "delete() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.delete"]], "delete_ssh_keys() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.delete_ssh_keys"]], "detach_device() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.detach_device"]], "detach_disk() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.detach_disk"]], "dump_xml() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.dump_xml"]], "get_disks() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.get_disks"]], "get_info() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.get_info"]], "get_max_memory() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.get_max_memory"]], "get_max_vcpus() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.get_max_vcpus"]], "get_ssh_keys() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.get_ssh_keys"]], "get_status() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.get_status"]], "is_autostart() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.is_autostart"]], "is_running() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.is_running"]], "max_memory (compute.instance.instance.instanceinfo attribute)": [[5, "compute.instance.instance.InstanceInfo.max_memory"]], "memory (compute.instance.instance.instanceinfo attribute)": [[5, "compute.instance.instance.InstanceInfo.memory"]], "nproc (compute.instance.instance.instanceinfo attribute)": [[5, "compute.instance.instance.InstanceInfo.nproc"]], "pause() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.pause"]], "power_reset() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.power_reset"]], "reboot() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.reboot"]], "reset() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.reset"]], "resize_disk() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.resize_disk"]], "resume() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.resume"]], "set_autostart() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.set_autostart"]], "set_memory() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.set_memory"]], "set_ssh_keys() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.set_ssh_keys"]], "set_user_password() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.set_user_password"]], "set_vcpus() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.set_vcpus"]], "shutdown() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.shutdown"]], "start() (compute.instance.instance.instance method)": [[5, "compute.instance.instance.Instance.start"]], "state (compute.instance.instance.instanceinfo attribute)": [[5, "compute.instance.instance.InstanceInfo.state"]], "to_xml() (compute.instance.instance.instanceconfig method)": [[5, "compute.instance.instance.InstanceConfig.to_xml"]], "bootoptionsschema (class in compute.instance.schemas)": [[6, "compute.instance.schemas.BootOptionsSchema"]], "cpuemulationmode (class in compute.instance.schemas)": [[6, "compute.instance.schemas.CPUEmulationMode"]], "cpufeaturesschema (class in compute.instance.schemas)": [[6, "compute.instance.schemas.CPUFeaturesSchema"]], "cpuschema (class in compute.instance.schemas)": [[6, "compute.instance.schemas.CPUSchema"]], "cputopologyschema (class in compute.instance.schemas)": [[6, "compute.instance.schemas.CPUTopologySchema"]], "entitymodel (class in compute.instance.schemas)": [[6, "compute.instance.schemas.EntityModel"]], "entitymodel.config (class in compute.instance.schemas)": [[6, "compute.instance.schemas.EntityModel.Config"]], "instanceschema (class in compute.instance.schemas)": [[6, "compute.instance.schemas.InstanceSchema"]], "networkinterfaceschema (class in compute.instance.schemas)": [[6, "compute.instance.schemas.NetworkInterfaceSchema"]], "volumecapacityschema (class in compute.instance.schemas)": [[6, "compute.instance.schemas.VolumeCapacitySchema"]], "volumeschema (class in compute.instance.schemas)": [[6, "compute.instance.schemas.VolumeSchema"]], "volumetype (class in compute.instance.schemas)": [[6, "compute.instance.schemas.VolumeType"]], "compute.instance.schemas": [[6, "module-compute.instance.schemas"]], "capabilities (class in compute.session)": [[7, "compute.session.Capabilities"]], "nodeinfo (class in compute.session)": [[7, "compute.session.NodeInfo"]], "session (class in compute.session)": [[7, "compute.session.Session"]], "__init__() (compute.session.session method)": [[7, "compute.session.Session.__init__"]], "arch (compute.session.capabilities attribute)": [[7, "compute.session.Capabilities.arch"]], "arch (compute.session.nodeinfo attribute)": [[7, "compute.session.NodeInfo.arch"]], "close() (compute.session.session method)": [[7, "compute.session.Session.close"]], "compute.session": [[7, "module-compute.session"]], "cores (compute.session.nodeinfo attribute)": [[7, "compute.session.NodeInfo.cores"]], "cpu_features (compute.session.capabilities attribute)": [[7, "compute.session.Capabilities.cpu_features"]], "cpu_model (compute.session.capabilities attribute)": [[7, "compute.session.Capabilities.cpu_model"]], "cpu_vendor (compute.session.capabilities attribute)": [[7, "compute.session.Capabilities.cpu_vendor"]], "cpus (compute.session.nodeinfo attribute)": [[7, "compute.session.NodeInfo.cpus"]], "create_instance() (compute.session.session method)": [[7, "compute.session.Session.create_instance"]], "emulator (compute.session.capabilities attribute)": [[7, "compute.session.Capabilities.emulator"]], "get_capabilities() (compute.session.session method)": [[7, "compute.session.Session.get_capabilities"]], "get_instance() (compute.session.session method)": [[7, "compute.session.Session.get_instance"]], "get_node_info() (compute.session.session method)": [[7, "compute.session.Session.get_node_info"]], "get_storage_pool() (compute.session.session method)": [[7, "compute.session.Session.get_storage_pool"]], "list_instances() (compute.session.session method)": [[7, "compute.session.Session.list_instances"]], "list_storage_pools() (compute.session.session method)": [[7, "compute.session.Session.list_storage_pools"]], "machine (compute.session.capabilities attribute)": [[7, "compute.session.Capabilities.machine"]], "max_vcpus (compute.session.capabilities attribute)": [[7, "compute.session.Capabilities.max_vcpus"]], "memory (compute.session.nodeinfo attribute)": [[7, "compute.session.NodeInfo.memory"]], "mhz (compute.session.nodeinfo attribute)": [[7, "compute.session.NodeInfo.mhz"]], "nodes (compute.session.nodeinfo attribute)": [[7, "compute.session.NodeInfo.nodes"]], "sockets (compute.session.nodeinfo attribute)": [[7, "compute.session.NodeInfo.sockets"]], "threads (compute.session.nodeinfo attribute)": [[7, "compute.session.NodeInfo.threads"]], "usable_cpus (compute.session.capabilities attribute)": [[7, "compute.session.Capabilities.usable_cpus"]], "virt_type (compute.session.capabilities attribute)": [[7, "compute.session.Capabilities.virt_type"]], "storagepool (class in compute.storage.pool)": [[9, "compute.storage.pool.StoragePool"]], "storagepoolusageinfo (class in compute.storage.pool)": [[9, "compute.storage.pool.StoragePoolUsageInfo"]], "__init__() (compute.storage.pool.storagepool method)": [[9, "compute.storage.pool.StoragePool.__init__"]], "allocation (compute.storage.pool.storagepoolusageinfo attribute)": [[9, "compute.storage.pool.StoragePoolUsageInfo.allocation"]], "available (compute.storage.pool.storagepoolusageinfo attribute)": [[9, "compute.storage.pool.StoragePoolUsageInfo.available"]], "capacity (compute.storage.pool.storagepoolusageinfo attribute)": [[9, "compute.storage.pool.StoragePoolUsageInfo.capacity"]], "clone_volume() (compute.storage.pool.storagepool method)": [[9, "compute.storage.pool.StoragePool.clone_volume"]], "compute.storage.pool": [[9, "module-compute.storage.pool"]], "create_volume() (compute.storage.pool.storagepool method)": [[9, "compute.storage.pool.StoragePool.create_volume"]], "dump_xml() (compute.storage.pool.storagepool method)": [[9, "compute.storage.pool.StoragePool.dump_xml"]], "get_usage_info() (compute.storage.pool.storagepool method)": [[9, "compute.storage.pool.StoragePool.get_usage_info"]], "get_volume() (compute.storage.pool.storagepool method)": [[9, "compute.storage.pool.StoragePool.get_volume"]], "list_volumes() (compute.storage.pool.storagepool method)": [[9, "compute.storage.pool.StoragePool.list_volumes"]], "refresh() (compute.storage.pool.storagepool method)": [[9, "compute.storage.pool.StoragePool.refresh"]], "diskconfig (class in compute.storage.volume)": [[10, "compute.storage.volume.DiskConfig"]], "volume (class in compute.storage.volume)": [[10, "compute.storage.volume.Volume"]], "volumeconfig (class in compute.storage.volume)": [[10, "compute.storage.volume.VolumeConfig"]], "__init__() (compute.storage.volume.diskconfig method)": [[10, "compute.storage.volume.DiskConfig.__init__"]], "__init__() (compute.storage.volume.volume method)": [[10, "compute.storage.volume.Volume.__init__"]], "__init__() (compute.storage.volume.volumeconfig method)": [[10, "compute.storage.volume.VolumeConfig.__init__"]], "clone() (compute.storage.volume.volume method)": [[10, "compute.storage.volume.Volume.clone"]], "compute.storage.volume": [[10, "module-compute.storage.volume"]], "delete() (compute.storage.volume.volume method)": [[10, "compute.storage.volume.Volume.delete"]], "dump_xml() (compute.storage.volume.volume method)": [[10, "compute.storage.volume.Volume.dump_xml"]], "resize() (compute.storage.volume.volume method)": [[10, "compute.storage.volume.Volume.resize"]], "to_xml() (compute.storage.volume.diskconfig method)": [[10, "compute.storage.volume.DiskConfig.to_xml"]], "to_xml() (compute.storage.volume.volumeconfig method)": [[10, "compute.storage.volume.VolumeConfig.to_xml"]], "dataunit (class in compute.utils.units)": [[11, "compute.utils.units.DataUnit"]], "invaliddatauniterror": [[11, "compute.utils.units.InvalidDataUnitError"]], "compute.utils.ids": [[11, "module-compute.utils.ids"]], "compute.utils.units": [[11, "module-compute.utils.units"]], "random_mac() (in module compute.utils.ids)": [[11, "compute.utils.ids.random_mac"]], "to_bytes() (in module compute.utils.units)": [[11, "compute.utils.units.to_bytes"]]}}) \ No newline at end of file diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute.bash-completion b/packaging/build/compute-0.1.0.dev1/debian/compute.bash-completion deleted file mode 100644 index a0dcdf2..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute.bash-completion +++ /dev/null @@ -1,93 +0,0 @@ -# compute bash completion script - -_compute_root_cmd=" - --version - --verbose - --connect - --log-level - init - exec - ls - start - shutdown - reboot - reset - powrst - pause - resume - status - setvcpus - setmem - setpasswd" -_compute_init_opts="" -_compute_exec_opts=" - --timeout - --executable - --env - --no-join-args" -_compute_ls_opts="" -_compute_start_opts="" -_compute_shutdown_opts="--method" -_compute_reboot_opts="" -_compute_reset_opts="" -_compute_powrst_opts="" -_compute_pause_opts="" -_compute_resume_opts="" -_compute_status_opts="" -_compute_setvcpus_opts="" -_compute_setmem_opts="" -_compute_setpasswd_opts="--encrypted" - -_compute_complete_instances() -{ - for file in /etc/libvirt/qemu/*.xml; do - nodir="${file##*/}" - printf '%s ' "${nodir//\.xml}" - done -} - -_compute_compreply() -{ - if [[ "$current" = [a-z]* ]]; then - _compute_compwords="$(_compute_complete_instances)" - else - _compute_compwords="$*" - fi - COMPREPLY=($(compgen -W "$_compute_compwords" -- "$current")) -} - -_compute_complete() -{ - local current previous nshift - current="${COMP_WORDS[COMP_CWORD]}" - case "$COMP_CWORD" in - 1) COMPREPLY=($(compgen -W "$_compute_root_cmd" -- "$current")) - ;; - 2|3|4|5) - nshift=$((COMP_CWORD-1)) - previous="${COMP_WORDS[COMP_CWORD-nshift]}" - case "$previous" in - init) COMPREPLY=($(compgen -f -- "$current"));; - exec) _compute_compreply "$_compute_exec_opts";; - ls) COMPREPLY=($(compgen -W "$_compute_ls_opts" -- "$current"));; - start) _compute_compreply "$_compute_start_opts";; - shutdown) _compute_compreply "$_compute_shutdown_opts";; - reboot) _compute_compreply "$_compute_reboot_opts";; - reset) _compute_compreply "$_compute_reset_opts";; - powrst) _compute_compreply "$_compute_powrst_opts";; - pause) _compute_compreply "$_compute_pause_opts";; - resume) _compute_compreply "$_compute_resume_opts";; - status) _compute_compreply "$_compute_status_opts";; - setvcpus) _compute_compreply "$_compute_setvcpus_opts";; - setmem) _compute_compreply "$_compute_setmem_opts";; - setpasswd) _compute_compreply "$_compute_setpasswd_opts";; - *) COMPREPLY=() - esac - ;; - *) COMPREPLY=($(compgen -W "$_compute_compwords" -- "$current")) - esac -} - -complete -F _compute_complete compute - -# vim: ft=bash diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute.debhelper.log b/packaging/build/compute-0.1.0.dev1/debian/compute.debhelper.log deleted file mode 100644 index 8dc2028..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute.debhelper.log +++ /dev/null @@ -1 +0,0 @@ -dh_sphinxdoc diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute.postinst.debhelper b/packaging/build/compute-0.1.0.dev1/debian/compute.postinst.debhelper deleted file mode 100644 index 2545e7a..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute.postinst.debhelper +++ /dev/null @@ -1,10 +0,0 @@ - -# Automatically added by dh_python3 -if command -v py3compile >/dev/null 2>&1; then - py3compile -p compute -fi -if command -v pypy3compile >/dev/null 2>&1; then - pypy3compile -p compute || true -fi - -# End automatically added section diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute.prerm.debhelper b/packaging/build/compute-0.1.0.dev1/debian/compute.prerm.debhelper deleted file mode 100644 index 062ac2f..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute.prerm.debhelper +++ /dev/null @@ -1,10 +0,0 @@ - -# Automatically added by dh_python3 -if command -v py3clean >/dev/null 2>&1; then - py3clean -p compute -else - dpkg -L compute | sed -En -e '/^(.*)\/(.+)\.py$/s,,rm "\1/__pycache__/\2".*,e' - find /usr/lib/python3/dist-packages/ -type d -name __pycache__ -empty -print0 | xargs --null --no-run-if-empty rmdir -fi - -# End automatically added section diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute.substvars b/packaging/build/compute-0.1.0.dev1/debian/compute.substvars deleted file mode 100644 index 6561153..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute.substvars +++ /dev/null @@ -1,3 +0,0 @@ -python3:Depends=python3-libvirt, python3-lxml, python3-pydantic, python3-yaml, python3:any -misc:Depends= -misc:Pre-Depends= diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/DEBIAN/control b/packaging/build/compute-0.1.0.dev1/debian/compute/DEBIAN/control deleted file mode 100644 index 906243f..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/DEBIAN/control +++ /dev/null @@ -1,12 +0,0 @@ -Package: compute -Version: 0.1.0.dev1-1 -Architecture: all -Maintainer: ge -Installed-Size: 118 -Depends: python3-libvirt, python3-lxml, python3-pydantic, python3-yaml, python3:any, qemu-system, qemu-utils, libvirt-daemon-system, libvirt-clients -Recommends: dnsmasq -Suggests: compute-doc -Section: admin -Priority: optional -Homepage: https://git.lulzette.ru/hstack/compute -Description: Compute instances management library and tools (Python 3) diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/DEBIAN/md5sums b/packaging/build/compute-0.1.0.dev1/debian/compute/DEBIAN/md5sums deleted file mode 100644 index 28d1b77..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/DEBIAN/md5sums +++ /dev/null @@ -1,27 +0,0 @@ -e21aa7b0b8fd557e047296cdf5ced826 usr/bin/compute -f9bc2efd4317ac0a92b8c7d283b947b8 usr/lib/python3/dist-packages/compute-0.1.0.dev1.dist-info/METADATA -db790365fd79ce4e960409f8cfc71dae usr/lib/python3/dist-packages/compute-0.1.0.dev1.dist-info/RECORD -b65598d0aa0cfe0f390246499e741adb usr/lib/python3/dist-packages/compute-0.1.0.dev1.dist-info/WHEEL -d6561300b96471e4e471ea1615006527 usr/lib/python3/dist-packages/compute-0.1.0.dev1.dist-info/entry_points.txt -9c54095f8462231dc4be8f87fadee594 usr/lib/python3/dist-packages/compute/__init__.py -a1b4018266bd8295c5e829c45948f642 usr/lib/python3/dist-packages/compute/__main__.py -d41d8cd98f00b204e9800998ecf8427e usr/lib/python3/dist-packages/compute/cli/__init__.py -8c13534e878816096e129b15462d0840 usr/lib/python3/dist-packages/compute/cli/control.py -1c4b0023246c9cd9d37e2addc255d7f9 usr/lib/python3/dist-packages/compute/common.py -665c006c01d16e64323037b0089cacef usr/lib/python3/dist-packages/compute/exceptions.py -1ff1400c5f71bd3a55ce2521258b5bd2 usr/lib/python3/dist-packages/compute/instance/__init__.py -82ec67ce83d65b991a8aba5e70f30e76 usr/lib/python3/dist-packages/compute/instance/guest_agent.py -135f6785552229c6fac04ab1d7c3113b usr/lib/python3/dist-packages/compute/instance/instance.py -00df3cb0195a2b97f1972f020bdbb243 usr/lib/python3/dist-packages/compute/instance/schemas.py -1d557cf313b52726a3591bd2e59c3c9b usr/lib/python3/dist-packages/compute/session.py -0a98a65c1a665afb4e4ed9cb3aef38f5 usr/lib/python3/dist-packages/compute/storage/__init__.py -ecf7a8e68c733d8e5b241ca33ae7cae0 usr/lib/python3/dist-packages/compute/storage/pool.py -c4a6cb9dbccfaa9217c2dbc4a833e8c9 usr/lib/python3/dist-packages/compute/storage/volume.py -d41d8cd98f00b204e9800998ecf8427e usr/lib/python3/dist-packages/compute/utils/__init__.py -e7797202c176137f38a6652cf45170a2 usr/lib/python3/dist-packages/compute/utils/config_loader.py -6c36830706d7d714d9b3c1d23dcccf14 usr/lib/python3/dist-packages/compute/utils/ids.py -964156c54ebe27ba2b14313f8f9f9754 usr/lib/python3/dist-packages/compute/utils/units.py -1fd80db613384b8d5782cf8c5843eb94 usr/share/bash-completion/completions/compute -672a4b3f13e2a14e4040c7a513ed60ba usr/share/doc/compute/README.md -6845278a102bd147f30f770ed1134ce5 usr/share/doc/compute/changelog.Debian.gz -fb1a6c11d7a8fa5f238617c20b13b6a1 usr/share/doc/compute/copyright diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/DEBIAN/postinst b/packaging/build/compute-0.1.0.dev1/debian/compute/DEBIAN/postinst deleted file mode 100755 index cebdb00..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/DEBIAN/postinst +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -set -e - -# Automatically added by dh_python3 -if command -v py3compile >/dev/null 2>&1; then - py3compile -p compute -fi -if command -v pypy3compile >/dev/null 2>&1; then - pypy3compile -p compute || true -fi - -# End automatically added section diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/DEBIAN/prerm b/packaging/build/compute-0.1.0.dev1/debian/compute/DEBIAN/prerm deleted file mode 100755 index d867122..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/DEBIAN/prerm +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -set -e - -# Automatically added by dh_python3 -if command -v py3clean >/dev/null 2>&1; then - py3clean -p compute -else - dpkg -L compute | sed -En -e '/^(.*)\/(.+)\.py$/s,,rm "\1/__pycache__/\2".*,e' - find /usr/lib/python3/dist-packages/ -type d -name __pycache__ -empty -print0 | xargs --null --no-run-if-empty rmdir -fi - -# End automatically added section diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/bin/compute b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/bin/compute deleted file mode 100755 index 56e33f2..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/bin/compute +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/python3 -# -*- coding: utf-8 -*- -import re -import sys -from compute.cli.control import cli -if __name__ == "__main__": - sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) - sys.exit(cli()) diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute-0.1.0.dev1.dist-info/METADATA b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute-0.1.0.dev1.dist-info/METADATA deleted file mode 100644 index f4c22ad..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute-0.1.0.dev1.dist-info/METADATA +++ /dev/null @@ -1,81 +0,0 @@ -Metadata-Version: 2.1 -Name: compute -Version: 0.1.0.dev1 -Summary: Compute instances management library and tools -Author: ge -Author-email: ge@nixhacks.net -Requires-Python: >=3.11,<4.0 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.11 -Requires-Dist: libvirt-python (==9.0.0) -Requires-Dist: lxml (>=4.9.2,<5.0.0) -Requires-Dist: pydantic (==1.10.4) -Requires-Dist: pyyaml (>=6.0.1,<7.0.0) -Description-Content-Type: text/markdown - -# Compute - -Compute instances management library and tools. - -## Docs - -Run `make serve-docs`. See [Development](#development) below. - -## Roadmap - -- [x] Create instances -- [ ] CDROM -- [ ] cloud-init for provisioning instances -- [x] Instance power management -- [x] Instance pause and resume -- [x] vCPU hotplug -- [x] Memory hotplug -- [x] Hot disk resize [not tested] -- [ ] CPU topology customization -- [x] CPU customization (emulation mode, model, vendor, features) -- [ ] BIOS/UEFI settings -- [x] Device attaching -- [x] Device detaching -- [ ] GPU passthrough -- [ ] CPU guarantied resource percent support -- [x] QEMU Guest Agent management -- [ ] Instance resources usage stats -- [ ] SSH-keys management -- [x] Setting user passwords in guest -- [x] QCOW2 disks support -- [ ] ZVOL support -- [ ] Network disks support -- [ ] Images service integration (Images service is not implemented yet) -- [ ] Manage storage pools -- [ ] Idempotency -- [ ] CLI [in progress] -- [ ] HTTP API -- [ ] Instance migrations -- [ ] Instance snapshots -- [ ] Instance backups -- [ ] LXC - -## Development - -Python 3.11+ is required. - -Install [poetry](https://python-poetry.org/), clone this repository and run: - -``` -poetry install --with dev --with docs -``` - -# Build Debian package - -Install Docker first, then run: - -``` -make build-deb -``` - -`compute` and `compute-doc` packages will built. See packaging/build directory. Packages can be installed via `dpkg` or `apt-get`: - -``` -apt-get install ./compute*.deb -``` - diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute-0.1.0.dev1.dist-info/RECORD b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute-0.1.0.dev1.dist-info/RECORD deleted file mode 100644 index 5f97163..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute-0.1.0.dev1.dist-info/RECORD +++ /dev/null @@ -1,23 +0,0 @@ -../scripts/compute,sha256=b-Gj6H6ssfbGalpouUMSX5pmsjqDnN9xMdTwnU-UfZY,216 -compute/__init__.py,sha256=x4zp_CoVPKgDT6AqhometspAyinGxJUXO48duJ5aHUM,873 -compute/__main__.py,sha256=zJyKJul6pCbguFPtVLZBoAuZl9RXibn4CCMn46jIgUQ,745 -compute/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -compute/cli/control.py,sha256=83wnR21pHOPyyk1i1n_YBIDz6dCFB6hmuIFguIk68rs,14634 -compute/common.py,sha256=G1qwC1EybG5LEJtyoux9ymiqB2ZOsgKXlCpbuhHv55Y,948 -compute/exceptions.py,sha256=Ga59L55qSAPeyDfjANPuMh4yVSRWHDYi9xqq5o4_7-0,2452 -compute/instance/__init__.py,sha256=kHN8jVamyrBZYZgi62tPtJ7rS73gUPhfswLalmPA5Zs,772 -compute/instance/guest_agent.py,sha256=fq89kQbcV5X5eFCsMmujRuwTOSghWO4ZhAjvxyUu84M,7018 -compute/instance/instance.py,sha256=WP6oTJfdAf6QlefwVLqdC8J6XoKHum6nZhwwHOEtjNk,23297 -compute/instance/schemas.py,sha256=B51ytPlxhnx0MrkR2WYhd49RaRT7Is7NsIM9OrMUpvI,4288 -compute/session.py,sha256=znYOIzoiCbSG62k-ViaXti_lOnw88wD8Syp3nCXAJ28,10050 -compute/storage/__init__.py,sha256=zNaVjZ2925DxrVUFWwVRsGU6bSYbF46sb4L6NsaiKbw,736 -compute/storage/pool.py,sha256=9z99bBDbb4ATGpfMkEWpxAO4fEQHNVOxxf0iUln9cN0,4197 -compute/storage/volume.py,sha256=_TbK9Y4d3NAeknPUiuhldAT3ZaN1sZgjy4QzC-Sw4Io,4110 -compute/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -compute/utils/config_loader.py,sha256=ul1J3sZg0D9R0HbOz5Pg9JmL4nFaMahAzQEdGaWFABU,1989 -compute/utils/ids.py,sha256=fg6Xsg4OMM-BIaU3DPu0L91ICwx-L3qNoELEwQZz2s0,1007 -compute/utils/units.py,sha256=UkwD0zQ-rlpSpkbfezCcvJx4D8iZlI9M-oXXvdVEvy0,1549 -compute-0.1.0.dev1.dist-info/METADATA,sha256=tbX8xp92Jwqf44sOwPB-HqKHLezab5dU9DrQDYFitDQ,1944 -compute-0.1.0.dev1.dist-info/WHEEL,sha256=vVCvjcmxuUltf8cYhJ0sJMRDLr1XsPuxEId8YDzbyCY,88 -compute-0.1.0.dev1.dist-info/entry_points.txt,sha256=xHhg-Fo9Z5gJnIahbG8pVIGNDqlH5Eordn8hnXUwscw,51 -compute-0.1.0.dev1.dist-info/RECORD,, diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute-0.1.0.dev1.dist-info/WHEEL b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute-0.1.0.dev1.dist-info/WHEEL deleted file mode 100644 index 4ba7671..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute-0.1.0.dev1.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: poetry-core 1.4.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute-0.1.0.dev1.dist-info/entry_points.txt b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute-0.1.0.dev1.dist-info/entry_points.txt deleted file mode 100644 index 4130f9f..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute-0.1.0.dev1.dist-info/entry_points.txt +++ /dev/null @@ -1,3 +0,0 @@ -[console_scripts] -compute=compute.cli.control:cli - diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/__init__.py b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/__init__.py deleted file mode 100644 index ffe06d7..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Compute instances management library.""" - -__version__ = '0.1.0-dev1' - -from .instance import Instance, InstanceConfig, InstanceSchema -from .session import Session -from .storage import StoragePool, Volume, VolumeConfig diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/__main__.py b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/__main__.py deleted file mode 100644 index 4995fbd..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/__main__.py +++ /dev/null @@ -1,21 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Command line interface for compute module.""" - -from compute.cli import main - - -main.cli() diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/cli/__init__.py b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/cli/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/cli/control.py b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/cli/control.py deleted file mode 100644 index f5a5b91..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/cli/control.py +++ /dev/null @@ -1,501 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Command line interface.""" - -import argparse -import io -import logging -import os -import shlex -import sys -from collections import UserDict -from typing import Any -from uuid import uuid4 - -import libvirt -import yaml -from pydantic import ValidationError - -from compute import __version__ -from compute.exceptions import ComputeError, GuestAgentTimeoutExceededError -from compute.instance import GuestAgent -from compute.session import Session -from compute.utils import ids - - -log = logging.getLogger(__name__) -log_levels = [lv.lower() for lv in logging.getLevelNamesMapping()] - -libvirt.registerErrorHandler( - lambda userdata, err: None, # noqa: ARG005 - ctx=None, -) - - -class Table: - """Minimalistic text table constructor.""" - - def __init__(self, whitespace: str | None = None): - """Initialise Table.""" - self.whitespace = whitespace or '\t' - self.header = [] - self.rows = [] - self.table = '' - - def add_row(self, row: list) -> None: - """Add table row.""" - self.rows.append([str(col) for col in row]) - - def add_rows(self, rows: list[list]) -> None: - """Add multiple rows.""" - for row in rows: - self.add_row(row) - - def __str__(self) -> str: - """Build table and return.""" - widths = [max(map(len, col)) for col in zip(*self.rows, strict=True)] - self.rows.insert(0, [str(h).upper() for h in self.header]) - for row in self.rows: - self.table += self.whitespace.join( - ( - val.ljust(width) - for val, width in zip(row, widths, strict=True) - ) - ) - self.table += '\n' - return self.table.strip() - - -def _list_instances(session: Session) -> None: - table = Table() - table.header = ['NAME', 'STATE'] - for instance in session.list_instances(): - table.add_row( - [ - instance.name, - instance.get_status(), - ] - ) - print(table) - sys.exit() - - -def _exec_guest_agent_command( - session: Session, args: argparse.Namespace -) -> None: - instance = session.get_instance(args.instance) - ga = GuestAgent(instance.domain, timeout=args.timeout) - arguments = args.arguments.copy() - if len(arguments) > 1 and not args.no_join_args: - arguments = [shlex.join(arguments)] - if not args.no_join_args: - arguments.insert(0, '-c') - stdin = None - if not sys.stdin.isatty(): - stdin = sys.stdin.read() - try: - output = ga.guest_exec( - path=args.executable, - args=arguments, - env=args.env, - stdin=stdin, - capture_output=True, - decode_output=True, - poll=True, - ) - except GuestAgentTimeoutExceededError as e: - sys.exit( - f'{e}. NOTE: command may still running in guest, ' - f'PID={ga.last_pid}' - ) - if output.stderr: - print(output.stderr.strip(), file=sys.stderr) - if output.stdout: - print(output.stdout.strip(), file=sys.stdout) - sys.exit(output.exitcode) - - -class _NotPresent: - """ - Type for representing non-existent dictionary keys. - - See :class:`_FillableDict`. - """ - - -class _FillableDict(UserDict): - """Use :method:`fill` to add key if not present.""" - - def __init__(self, data: dict): - self.data = data - - def fill(self, key: str, value: Any) -> None: # noqa: ANN401 - if self.data.get(key, _NotPresent) is _NotPresent: - self.data[key] = value - - -def _merge_dicts(a: dict, b: dict, path: list[str] | None = None) -> dict: - """Merge `b` into `a`. Return modified `a`.""" - if path is None: - path = [] - for key in b: - if key in a: - if isinstance(a[key], dict) and isinstance(b[key], dict): - _merge_dicts(a[key], b[key], [path + str(key)]) - elif a[key] == b[key]: - pass # same leaf value - else: - a[key] = b[key] # replace existing key's values - else: - a[key] = b[key] - return a - - -def _create_instance(session: Session, file: io.TextIOWrapper) -> None: - try: - data = _FillableDict(yaml.load(file.read(), Loader=yaml.SafeLoader)) - log.debug('Read from file: %s', data) - except yaml.YAMLError as e: - sys.exit(f'error: cannot parse YAML: {e}') - - capabilities = session.get_capabilities() - node_info = session.get_node_info() - - data.fill('name', uuid4().hex) - data.fill('title', None) - data.fill('description', None) - data.fill('arch', capabilities.arch) - data.fill('machine', capabilities.machine) - data.fill('emulator', capabilities.emulator) - data.fill('max_vcpus', node_info.cpus) - data.fill('max_memory', node_info.memory) - data.fill('cpu', {}) - cpu = { - 'emulation_mode': 'host-passthrough', - 'model': None, - 'vendor': None, - 'topology': None, - 'features': None, - } - data['cpu'] = _merge_dicts(data['cpu'], cpu) - data.fill( - 'network_interfaces', - [{'source': 'default', 'mac': ids.random_mac()}], - ) - data.fill('boot', {'order': ['cdrom', 'hd']}) - - try: - log.debug('Input data: %s', data) - session.create_instance(**data) - except ValidationError as e: - for error in e.errors(): - fields = '.'.join([str(lc) for lc in error['loc']]) - print( - f"validation error: {fields}: {error['msg']}", - file=sys.stderr, - ) - sys.exit() - - -def _shutdown_instance(session: Session, args: argparse.Namespace) -> None: - instance = session.get_instance(args.instance) - if args.soft: - method = 'SOFT' - elif args.hard: - method = 'HARD' - elif args.unsafe: - method = 'UNSAFE' - else: - method = 'NORMAL' - instance.shutdown(method) - - -def main(session: Session, args: argparse.Namespace) -> None: - """Perform actions.""" - match args.command: - case 'init': - _create_instance(session, args.file) - case 'exec': - _exec_guest_agent_command(session, args) - case 'ls': - _list_instances(session) - case 'start': - instance = session.get_instance(args.instance) - instance.start() - case 'shutdown': - _shutdown_instance(session, args) - case 'reboot': - instance = session.get_instance(args.instance) - instance.reboot() - case 'reset': - instance = session.get_instance(args.instance) - instance.reset() - case 'powrst': - instance = session.get_instance(args.instance) - instance.power_reset() - case 'pause': - instance = session.get_instance(args.instance) - instance.pause() - case 'resume': - instance = session.get_instance(args.instance) - instance.resume() - case 'status': - instance = session.get_instance(args.instance) - print(instance.status) - case 'setvcpus': - instance = session.get_instance(args.instance) - instance.set_vcpus(args.nvcpus, live=True) - case 'setmem': - instance = session.get_instance(args.instance) - instance.set_memory(args.memory, live=True) - case 'setpass': - instance = session.get_instance(args.instance) - instance.set_user_password( - args.username, - args.password, - encrypted=args.encrypted, - ) - - -def cli() -> None: # noqa: PLR0915 - """Return command line arguments parser.""" - root = argparse.ArgumentParser( - prog='compute', - description='manage compute instances', - formatter_class=argparse.RawTextHelpFormatter, - ) - root.add_argument( - '-v', - '--verbose', - action='store_true', - default=False, - help='enable verbose mode', - ) - root.add_argument( - '-c', - '--connect', - metavar='URI', - help='libvirt connection URI', - ) - root.add_argument( - '-l', - '--log-level', - type=str.lower, - metavar='LEVEL', - choices=log_levels, - help='log level', - ) - root.add_argument( - '-V', - '--version', - action='version', - version=__version__, - ) - subparsers = root.add_subparsers(dest='command', metavar='COMMAND') - - # init command - init = subparsers.add_parser( - 'init', help='initialise instance using YAML config file' - ) - init.add_argument( - 'file', - type=argparse.FileType('r', encoding='UTF-8'), - nargs='?', - default='instance.yaml', - help='instance config [default: instance.yaml]', - ) - - # exec subcommand - execute = subparsers.add_parser( - 'exec', - help='execute command in guest via guest agent', - description=( - 'NOTE: any argument after instance name will be passed into ' - 'guest as shell command.' - ), - ) - execute.add_argument('instance') - execute.add_argument('arguments', nargs=argparse.REMAINDER) - execute.add_argument( - '-t', - '--timeout', - type=int, - default=60, - help=( - 'waiting time in seconds for a command to be executed ' - 'in guest [default: 60]' - ), - ) - execute.add_argument( - '-x', - '--executable', - default='/bin/sh', - help='path to executable in guest [default: /bin/sh]', - ) - execute.add_argument( - '-e', - '--env', - type=str, - nargs='?', - action='append', - help='environment variables to pass to executable in guest', - ) - execute.add_argument( - '-n', - '--no-join-args', - action='store_true', - default=False, - help=( - "do not join arguments list and add '-c' option, suitable " - 'for non-shell executables and other specific cases.' - ), - ) - - # ls subcommand - listall = subparsers.add_parser('ls', help='list instances') - listall.add_argument( - '-a', - '--all', - action='store_true', - default=False, - help='list all instances including inactive', - ) - - # start subcommand - start = subparsers.add_parser('start', help='start instance') - start.add_argument('instance') - - # shutdown subcommand - shutdown = subparsers.add_parser('shutdown', help='shutdown instance') - shutdown.add_argument('instance') - shutdown_opts = shutdown.add_mutually_exclusive_group() - shutdown_opts.add_argument( - '-s', - '--soft', - action='store_true', - help='normal guest OS shutdown, guest agent is used', - ) - shutdown_opts.add_argument( - '-n', - '--normal', - action='store_true', - help='shutdown with hypervisor selected method [default]', - ) - shutdown_opts.add_argument( - '-H', - '--hard', - action='store_true', - help=( - "gracefully destroy instance, it's like long " - 'pressing the power button' - ), - ) - shutdown_opts.add_argument( - '-u', - '--unsafe', - action='store_true', - help=( - 'destroy instance, this is similar to a power outage ' - 'and may result in data loss or corruption' - ), - ) - - # reboot subcommand - reboot = subparsers.add_parser('reboot', help='reboot instance') - reboot.add_argument('instance') - - # reset subcommand - reset = subparsers.add_parser('reset', help='reset instance') - reset.add_argument('instance') - - # powrst subcommand - powrst = subparsers.add_parser('powrst', help='power reset instance') - powrst.add_argument('instance') - - # pause subcommand - pause = subparsers.add_parser('pause', help='pause instance') - pause.add_argument('instance') - - # resume subcommand - resume = subparsers.add_parser('resume', help='resume paused instance') - resume.add_argument('instance') - - # status subcommand - status = subparsers.add_parser('status', help='display instance status') - status.add_argument('instance') - - # setvcpus subcommand - setvcpus = subparsers.add_parser('setvcpus', help='set vCPU number') - setvcpus.add_argument('instance') - setvcpus.add_argument('nvcpus', type=int) - - # setmem subcommand - setmem = subparsers.add_parser('setmem', help='set memory size') - setmem.add_argument('instance') - setmem.add_argument('memory', type=int, help='memory in MiB') - - # setpass subcommand - setpass = subparsers.add_parser( - 'setpass', - help='set user password in guest', - ) - setpass.add_argument('instance') - setpass.add_argument('username') - setpass.add_argument('password') - setpass.add_argument( - '-e', - '--encrypted', - action='store_true', - default=False, - help='set it if password is already encrypted', - ) - - args = root.parse_args() - if args.command is None: - root.print_help() - sys.exit() - - log_level = args.log_level or os.getenv('CMP_LOG') - - if isinstance(log_level, str) and log_level.lower() in log_levels: - logging.basicConfig( - level=logging.getLevelNamesMapping()[log_level.upper()] - ) - - log.debug('CLI started with args: %s', args) - - connect_uri = ( - args.connect - or os.getenv('CMP_LIBVIRT_URI') - or os.getenv('LIBVIRT_DEFAULT_URI') - or 'qemu:///system' - ) - - try: - with Session(connect_uri) as session: - main(session, args) - except ComputeError as e: - sys.exit(f'error: {e}') - except KeyboardInterrupt: - sys.exit() - except SystemExit as e: - sys.exit(e) - except Exception as e: # noqa: BLE001 - sys.exit(f'unexpected error {type(e)}: {e}') - - -if __name__ == '__main__': - cli() diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/common.py b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/common.py deleted file mode 100644 index 34a339a..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/common.py +++ /dev/null @@ -1,30 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Common symbols.""" - -from abc import ABC, abstractmethod - - -class EntityConfig(ABC): - """An abstract entity XML config builder class.""" - - @abstractmethod - def to_xml(self) -> str: - """Return device XML config.""" - raise NotImplementedError - - -DeviceConfig = EntityConfig diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/exceptions.py b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/exceptions.py deleted file mode 100644 index 1eef8de..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/exceptions.py +++ /dev/null @@ -1,80 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Exceptions.""" - - -class ComputeError(Exception): - """Basic exception class.""" - - -class ConfigLoaderError(ComputeError): - """Something went wrong when loading configuration.""" - - -class SessionError(ComputeError): - """Something went wrong while connecting to libvirtd.""" - - -class GuestAgentError(ComputeError): - """Something went wring when QEMU Guest Agent call.""" - - -class GuestAgentUnavailableError(GuestAgentError): - """Guest agent is not connected or is unavailable.""" - - -class GuestAgentTimeoutExceededError(GuestAgentError): - """QEMU timeout exceeded.""" - - def __init__(self, msg: int): - """Initialise GuestAgentTimeoutExceededError.""" - super().__init__(f'QEMU timeout ({msg} sec) exceeded') - - -class GuestAgentCommandNotSupportedError(GuestAgentError): - """Guest agent command is not supported or blacklisted on guest.""" - - -class StoragePoolError(ComputeError): - """Something went wrong when operating with storage pool.""" - - -class StoragePoolNotFoundError(StoragePoolError): - """Storage pool not found.""" - - def __init__(self, msg: str): - """Initialise StoragePoolNotFoundError.""" - super().__init__(f"storage pool named '{msg}' not found") - - -class VolumeNotFoundError(StoragePoolError): - """Storage volume not found.""" - - def __init__(self, msg: str): - """Initialise VolumeNotFoundError.""" - super().__init__(f"storage volume '{msg}' not found") - - -class InstanceError(ComputeError): - """Something went wrong while interacting with the domain.""" - - -class InstanceNotFoundError(InstanceError): - """Virtual machine or container not found on compute node.""" - - def __init__(self, msg: str): - """Initialise InstanceNotFoundError.""" - super().__init__(f"compute instance '{msg}' not found") diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/instance/__init__.py b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/instance/__init__.py deleted file mode 100644 index 6e2b150..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/instance/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -from .guest_agent import GuestAgent -from .instance import Instance, InstanceConfig -from .schemas import InstanceSchema diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/instance/guest_agent.py b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/instance/guest_agent.py deleted file mode 100644 index 4381591..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/instance/guest_agent.py +++ /dev/null @@ -1,208 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Interacting with the QEMU Guest Agent.""" - -import json -import logging -from base64 import b64decode, standard_b64encode -from time import sleep, time -from typing import NamedTuple - -import libvirt -import libvirt_qemu - -from compute.exceptions import ( - GuestAgentCommandNotSupportedError, - GuestAgentError, - GuestAgentTimeoutExceededError, - GuestAgentUnavailableError, -) - - -log = logging.getLogger(__name__) - - -class GuestExecOutput(NamedTuple): - """QEMU guest-exec command output.""" - - exited: bool | None = None - exitcode: int | None = None - stdout: str | None = None - stderr: str | None = None - - -class GuestAgent: - """Class for interacting with QEMU guest agent.""" - - def __init__(self, domain: libvirt.virDomain, timeout: int = 60): - """ - Initialise GuestAgent. - - :param domain: Libvirt domain object - :param timeout: QEMU timeout - """ - self.domain = domain - self.timeout = timeout - self.flags = libvirt_qemu.VIR_DOMAIN_QEMU_MONITOR_COMMAND_DEFAULT - self.last_pid = None - - def execute(self, command: dict) -> dict: - """ - Execute QEMU guest agent command. - - See: https://qemu-project.gitlab.io/qemu/interop/qemu-ga-ref.html - - :param command: QEMU guest agent command as dict - :return: Command output - :rtype: dict - """ - log.debug(command) - try: - output = libvirt_qemu.qemuAgentCommand( - self.domain, json.dumps(command), self.timeout, self.flags - ) - return json.loads(output) - except libvirt.libvirtError as e: - if e.get_error_code() == libvirt.VIR_ERR_AGENT_UNRESPONSIVE: - raise GuestAgentUnavailableError(e) from e - raise GuestAgentError(e) from e - - def is_available(self) -> bool: - """ - Execute guest-ping. - - :return: True or False if guest agent is unreachable. - :rtype: bool - """ - try: - if self.execute({'execute': 'guest-ping', 'arguments': {}}): - return True - except GuestAgentError: - return False - - def get_supported_commands(self) -> set[str]: - """Return set of supported guest agent commands.""" - output = self.execute({'execute': 'guest-info', 'arguments': {}}) - return { - cmd['name'] - for cmd in output['return']['supported_commands'] - if cmd['enabled'] is True - } - - def raise_for_commands(self, commands: list[str]) -> None: - """ - Raise exception if QEMU GA command is not available. - - :param commands: List of required commands - :raise: GuestAgentCommandNotSupportedError - """ - supported = self.get_supported_commands() - for command in commands: - if command not in supported: - raise GuestAgentCommandNotSupportedError(command) - - def guest_exec( # noqa: PLR0913 - self, - path: str, - args: list[str] | None = None, - env: list[str] | None = None, - stdin: str | None = None, - *, - capture_output: bool = False, - decode_output: bool = False, - poll: bool = False, - ) -> GuestExecOutput: - """ - Execute qemu-exec command and return output. - - :param path: Path ot executable on guest. - :param arg: List of arguments to pass to executable. - :param env: List of environment variables to pass to executable. - For example: ``['LANG=C', 'TERM=xterm']`` - :param stdin: Data to pass to executable STDIN. - :param capture_output: Capture command output. - :param decode_output: Use base64_decode() to decode command output. - Affects only if `capture_output` is True. - :param poll: Poll command output. Uses `self.timeout` and - POLL_INTERVAL constant. - :return: Command output - :rtype: GuestExecOutput - """ - self.raise_for_commands(['guest-exec', 'guest-exec-status']) - command = { - 'execute': 'guest-exec', - 'arguments': { - 'path': path, - **({'arg': args} if args else {}), - **({'env': env} if env else {}), - **( - { - 'input-data': standard_b64encode( - stdin.encode('utf-8') - ).decode('utf-8') - } - if stdin - else {} - ), - 'capture-output': capture_output, - }, - } - output = self.execute(command) - self.last_pid = pid = output['return']['pid'] - command_status = self.guest_exec_status(pid, poll=poll)['return'] - exited = command_status['exited'] - exitcode = command_status['exitcode'] - stdout = command_status.get('out-data', None) - stderr = command_status.get('err-data', None) - if decode_output: - stdout = b64decode(stdout or '').decode('utf-8') - stderr = b64decode(stderr or '').decode('utf-8') - return GuestExecOutput(exited, exitcode, stdout, stderr) - - def guest_exec_status( - self, pid: int, *, poll: bool = False, poll_interval: float = 0.3 - ) -> dict: - """ - Execute guest-exec-status and return output. - - :param pid: PID in guest. - :param poll: If True poll command status. - :param poll_interval: Time between attempts to obtain command status. - :return: Command output - :rtype: dict - """ - self.raise_for_commands(['guest-exec-status']) - command = { - 'execute': 'guest-exec-status', - 'arguments': {'pid': pid}, - } - if not poll: - return self.execute(command) - start_time = time() - while True: - command_status = self.execute(command) - if command_status['return']['exited']: - break - sleep(poll_interval) - now = time() - if now - start_time > self.timeout: - raise GuestAgentTimeoutExceededError(self.timeout) - log.debug( - 'Polling command pid=%s finished, time taken: %s seconds', - pid, - int(time() - start_time), - ) - return command_status diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/instance/instance.py b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/instance/instance.py deleted file mode 100644 index 5b806e6..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/instance/instance.py +++ /dev/null @@ -1,675 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Manage compute instances.""" - -__all__ = ['Instance', 'InstanceConfig', 'InstanceInfo'] - -import logging -from typing import NamedTuple - -import libvirt -from lxml import etree -from lxml.builder import E - -from compute.common import DeviceConfig, EntityConfig -from compute.exceptions import ( - GuestAgentCommandNotSupportedError, - InstanceError, -) -from compute.storage import DiskConfig -from compute.utils import units - -from .guest_agent import GuestAgent -from .schemas import ( - CPUEmulationMode, - CPUSchema, - InstanceSchema, - NetworkInterfaceSchema, -) - - -log = logging.getLogger(__name__) - - -class InstanceConfig(EntityConfig): - """Compute instance XML config builder.""" - - def __init__(self, schema: InstanceSchema): - """ - Initialise InstanceConfig. - - :param schema: InstanceSchema object - """ - self.name = schema.name - self.title = schema.title - self.description = schema.description - self.memory = schema.memory - self.max_memory = schema.max_memory - self.vcpus = schema.vcpus - self.max_vcpus = schema.max_vcpus - self.cpu = schema.cpu - self.machine = schema.machine - self.emulator = schema.emulator - self.arch = schema.arch - self.boot = schema.boot - self.network_interfaces = schema.network_interfaces - - def _gen_cpu_xml(self, cpu: CPUSchema) -> etree.Element: - options = { - 'mode': cpu.emulation_mode, - 'match': 'exact', - 'check': 'partial', - } - if cpu.emulation_mode == CPUEmulationMode.HOST_PASSTHROUGH: - options['check'] = 'none' - options['migratable'] = 'on' - xml = E.cpu(**options) - if cpu.model: - xml.append(E.model(cpu.model, fallback='forbid')) - if cpu.vendor: - xml.append(E.vendor(cpu.vendor)) - if cpu.topology: - xml.append( - E.topology( - sockets=str(cpu.topology.sockets), - dies=str(cpu.topology.dies), - cores=str(cpu.topology.cores), - threads=str(cpu.topology.threads), - ) - ) - if cpu.features: - for feature in cpu.features.require: - xml.append(E.feature(policy='require', name=feature)) - for feature in cpu.features.disable: - xml.append(E.feature(policy='disable', name=feature)) - return xml - - def _gen_vcpus_xml(self, vcpus: int, max_vcpus: int) -> etree.Element: - xml = E.vcpus() - xml.append(E.vcpu(id='0', enabled='yes', hotpluggable='no', order='1')) - for i in range(max_vcpus - 1): - enabled = 'yes' if (i + 2) <= vcpus else 'no' - xml.append( - E.vcpu( - id=str(i + 1), - enabled=enabled, - hotpluggable='yes', - order=str(i + 2), - ) - ) - return xml - - def _gen_network_interface_xml( - self, interface: NetworkInterfaceSchema - ) -> etree.Element: - return E.interface( - E.source(network=interface.source), - E.mac(address=interface.mac), - type='network', - ) - - def to_xml(self) -> str: - """Return XML config for libvirt.""" - xml = E.domain(type='kvm') - xml.append(E.name(self.name)) - if self.title: - xml.append(E.title(self.title)) - if self.description: - xml.append(E.description(self.description)) - xml.append(E.metadata()) - xml.append(E.memory(str(self.max_memory * 1024), unit='KiB')) - xml.append(E.currentMemory(str(self.memory * 1024), unit='KiB')) - xml.append( - E.vcpu( - str(self.max_vcpus), - placement='static', - current=str(self.vcpus), - ) - ) - xml.append(self._gen_cpu_xml(self.cpu)) - os = E.os(E.type('hvm', machine=self.machine, arch=self.arch)) - for dev in self.boot.order: - os.append(E.boot(dev=dev)) - xml.append(os) - xml.append(E.features(E.acpi(), E.apic())) - xml.append(E.on_poweroff('destroy')) - xml.append(E.on_reboot('restart')) - xml.append(E.on_crash('restart')) - xml.append( - E.pm( - E('suspend-to-mem', enabled='no'), - E('suspend-to-disk', enabled='no'), - ) - ) - devices = E.devices() - devices.append(E.emulator(str(self.emulator))) - for interface in self.network_interfaces: - devices.append(self._gen_network_interface_xml(interface)) - devices.append(E.graphics(type='vnc', port='-1', autoport='yes')) - devices.append(E.input(type='tablet', bus='usb')) - devices.append( - E.channel( - E.source(mode='bind'), - E.target(type='virtio', name='org.qemu.guest_agent.0'), - E.address( - type='virtio-serial', controller='0', bus='0', port='1' - ), - type='unix', - ) - ) - devices.append( - E.console(E.target(type='serial', port='0'), type='pty') - ) - devices.append( - E.video( - E.model(type='vga', vram='16384', heads='1', primary='yes') - ) - ) - xml.append(devices) - return etree.tostring(xml, encoding='unicode', pretty_print=True) - - -class InstanceInfo(NamedTuple): - """ - Store compute instance info. - - Reference: - https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainInfo - """ - - state: str - max_memory: int - memory: int - nproc: int - cputime: int - - -class Instance: - """Manage compute instances.""" - - def __init__(self, domain: libvirt.virDomain): - """ - Initialise Instance. - - :ivar libvirt.virDomain domain: domain object - :ivar libvirt.virConnect connection: connection object - :ivar str name: domain name - :ivar GuestAgent guest_agent: :class:`GuestAgent` object - - :param domain: libvirt domain object - """ - self.domain = domain - self.connection = domain.connect() - self.name = domain.name() - self.guest_agent = GuestAgent(domain) - - def _expand_instance_state(self, state: int) -> str: - states = { - libvirt.VIR_DOMAIN_NOSTATE: 'nostate', - libvirt.VIR_DOMAIN_RUNNING: 'running', - libvirt.VIR_DOMAIN_BLOCKED: 'blocked', - libvirt.VIR_DOMAIN_PAUSED: 'paused', - libvirt.VIR_DOMAIN_SHUTDOWN: 'shutdown', - libvirt.VIR_DOMAIN_SHUTOFF: 'shutoff', - libvirt.VIR_DOMAIN_CRASHED: 'crashed', - libvirt.VIR_DOMAIN_PMSUSPENDED: 'pmsuspended', - } - return states[state] - - def get_info(self) -> InstanceInfo: - """Return instance info.""" - info = self.domain.info() - return InstanceInfo( - state=self._expand_instance_state(info[0]), - max_memory=info[1], - memory=info[2], - nproc=info[3], - cputime=info[4], - ) - - def get_status(self) -> str: - """ - Return instance state: 'running', 'shutoff', etc. - - Reference: - https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainState - """ - try: - state, _ = self.domain.state() - except libvirt.libvirtError as e: - raise InstanceError( - 'Cannot fetch status of ' f'instance={self.name}: {e}' - ) from e - return self._expand_instance_state(state) - - def is_running(self) -> bool: - """Return True if instance is running, else return False.""" - if self.domain.isActive() != 1: - # 0 - is inactive, -1 - is error - return False - return True - - def is_autostart(self) -> bool: - """Return True if instance autostart is enabled, else return False.""" - try: - return bool(self.domain.autostart()) - except libvirt.libvirtError as e: - raise InstanceError( - f'Cannot get autostart status for ' - f'instance={self.name}: {e}' - ) from e - - def get_max_memory(self) -> int: - """Maximum memory value for domain in KiB.""" - return self.domain.maxMemory() - - def get_max_vcpus(self) -> int: - """Maximum vCPUs number for domain.""" - return self.domain.maxVcpus() - - def start(self) -> None: - """Start defined instance.""" - log.info('Starting instnce=%s', self.name) - if self.is_running(): - log.warning( - 'Already started, nothing to do instance=%s', self.name - ) - return - try: - self.domain.create() - except libvirt.libvirtError as e: - raise InstanceError( - f'Cannot start instance={self.name}: {e}' - ) from e - - def shutdown(self, method: str | None = None) -> None: - """ - Shutdown instance. - - Shutdown methods: - - SOFT - Use guest agent to shutdown. If guest agent is unavailable - NORMAL method will be used. - - NORMAL - Use method choosen by hypervisor to shutdown. Usually send ACPI - signal to guest OS. OS may ignore ACPI e.g. if guest is hanged. - - HARD - Shutdown instance without any guest OS shutdown. This is simular - to unplugging machine from power. Internally send SIGTERM to - instance process and destroy it gracefully. - - UNSAFE - Force shutdown. Internally send SIGKILL to instance process. - There is high data corruption risk! - - If method is None NORMAL method will used. - - :param method: Method used to shutdown instance - """ - methods = { - 'SOFT': libvirt.VIR_DOMAIN_SHUTDOWN_GUEST_AGENT, - 'NORMAL': libvirt.VIR_DOMAIN_SHUTDOWN_DEFAULT, - 'HARD': libvirt.VIR_DOMAIN_DESTROY_GRACEFUL, - 'UNSAFE': libvirt.VIR_DOMAIN_DESTROY_DEFAULT, - } - if method is None: - method = 'NORMAL' - if not isinstance(method, str): - raise TypeError( - f"Shutdown method must be a 'str', not {type(method)}" - ) - method = method.upper() - if method not in methods: - raise ValueError(f"Unsupported shutdown method: '{method}'") - try: - if method in ['SOFT', 'NORMAL']: - self.domain.shutdownFlags(flags=methods[method]) - elif method in ['HARD', 'UNSAFE']: - self.domain.destroyFlags(flags=methods[method]) - except libvirt.libvirtError as e: - raise InstanceError( - f'Cannot shutdown instance={self.name} ' f'{method=}: {e}' - ) from e - - def reboot(self) -> None: - """Send ACPI signal to guest OS to reboot. OS may ignore this.""" - try: - self.domain.reboot() - except libvirt.libvirtError as e: - raise InstanceError( - f'Cannot reboot instance={self.name}: {e}' - ) from e - - def reset(self) -> None: - """ - Reset instance. - - Copypaste from libvirt doc: - - Reset a domain immediately without any guest OS shutdown. - Reset emulates the power reset button on a machine, where all - hardware sees the RST line set and reinitializes internal state. - - Note that there is a risk of data loss caused by reset without any - guest OS shutdown. - """ - try: - self.domain.reset() - except libvirt.libvirtError as e: - raise InstanceError( - f'Cannot reset instance={self.name}: {e}' - ) from e - - def power_reset(self) -> None: - """ - Shutdown instance and start. - - By analogy with real hardware, this is a normal server shutdown, - and then turning off from the power supply and turning it on again. - - This method is applicable in cases where there has been a - configuration change in libvirt and you need to restart the - instance to apply the new configuration. - """ - self.shutdown(method='NORMAL') - self.start() - - def set_autostart(self, *, enabled: bool) -> None: - """ - Set autostart flag for instance. - - :param enabled: Bool argument to set or unset autostart flag. - """ - autostart = 1 if enabled else 0 - try: - self.domain.setAutostart(autostart) - except libvirt.libvirtError as e: - raise InstanceError( - f'Cannot set autostart flag for instance={self.name} ' - f'{autostart=}: {e}' - ) from e - - def set_vcpus(self, nvcpus: int, *, live: bool = False) -> None: - """ - Set vCPU number. - - If `live` is True and instance is not currently running vCPUs - will set in config and will applied when instance boot. - - NB: Note that if this call is executed before the guest has - finished booting, the guest may fail to process the change. - - :param nvcpus: Number of vCPUs - :param live: Affect a running instance - """ - if nvcpus <= 0: - raise InstanceError('Cannot set zero vCPUs') - if nvcpus > self.get_max_vcpus(): - raise InstanceError('vCPUs count is greather than max_vcpus') - if nvcpus == self.get_info().nproc: - log.warning( - 'Instance instance=%s already have %s vCPUs, nothing to do', - self.name, - nvcpus, - ) - return - try: - flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG - self.domain.setVcpusFlags(nvcpus, flags=flags) - if live is True: - if not self.is_running(): - log.warning( - 'Instance is not running, changes applied in ' - 'instance config.' - ) - return - flags = libvirt.VIR_DOMAIN_AFFECT_LIVE - self.domain.setVcpusFlags(nvcpus, flags=flags) - if self.guest_agent.is_available(): - try: - self.guest_agent.raise_for_commands( - ['guest-set-vcpus'] - ) - flags = libvirt.VIR_DOMAIN_VCPU_GUEST - self.domain.setVcpusFlags(nvcpus, flags=flags) - except GuestAgentCommandNotSupportedError: - log.warning( - 'Cannot set vCPUs in guest via agent, you may ' - 'need to apply changes in guest manually.' - ) - else: - log.warning( - 'Cannot set vCPUs in guest OS on instance=%s. ' - 'You may need to apply CPUs in guest manually.', - self.name, - ) - except libvirt.libvirtError as e: - raise InstanceError( - f'Cannot set vCPUs for instance={self.name}: {e}' - ) from e - - def set_memory(self, memory: int, *, live: bool = False) -> None: - """ - Set memory. - - If `live` is True and instance is not currently running set memory - in config and will applied when instance boot. - - :param memory: Memory value in mebibytes - :param live: Affect a running instance - """ - if memory <= 0: - raise InstanceError('Cannot set zero memory') - if (memory * 1024) > self.get_max_memory(): - raise InstanceError('Memory is greather than max_memory') - if (memory * 1024) == self.get_info().memory: - log.warning( - "Instance '%s' already have %s memory, nothing to do", - self.name, - memory, - ) - return - if live and self.is_running(): - flags = ( - libvirt.VIR_DOMAIN_AFFECT_LIVE - | libvirt.VIR_DOMAIN_AFFECT_CONFIG - ) - else: - flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG - try: - self.domain.setMemoryFlags(memory * 1024, flags=flags) - except libvirt.libvirtError as e: - msg = f'Cannot set memory for instance={self.name} {memory=}: {e}' - raise InstanceError(msg) from e - - def _get_disk_by_target(self, target: str) -> etree.Element: - xml = etree.fromstring(self.dump_xml()) # noqa: S320 - child = xml.xpath(f'/domain/devices/disk/target[@dev="{target}"]') - return child[0].getparent() if child else None - - def attach_device( - self, device: DeviceConfig, *, live: bool = False - ) -> None: - """ - Attach device to compute instance. - - :param device: Object with device description e.g. DiskConfig - :param live: Affect a running instance - """ - if live and self.is_running(): - flags = ( - libvirt.VIR_DOMAIN_AFFECT_LIVE - | libvirt.VIR_DOMAIN_AFFECT_CONFIG - ) - else: - flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG - if isinstance(device, DiskConfig): # noqa: SIM102 - if self._get_disk_by_target(device.target): - log.warning( - "Volume with target '%s' is already attached", - device.target, - ) - return - self.domain.attachDeviceFlags(device.to_xml(), flags=flags) - - def detach_device( - self, device: DeviceConfig, *, live: bool = False - ) -> None: - """ - Dettach device from compute instance. - - :param device: Object with device description e.g. DiskConfig - :param live: Affect a running instance - """ - if live and self.is_running(): - flags = ( - libvirt.VIR_DOMAIN_AFFECT_LIVE - | libvirt.VIR_DOMAIN_AFFECT_CONFIG - ) - else: - flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG - if isinstance(device, DiskConfig): # noqa: SIM102 - if self._get_disk_by_target(device.target) is None: - log.warning( - "Volume with target '%s' is already detached", - device.target, - ) - return - self.domain.detachDeviceFlags(device.to_xml(), flags=flags) - - def detach_disk(self, name: str) -> None: - """ - Detach disk device by target name. - - There is no ``attach_disk()`` method. Use :func:`attach_device` - with :class:`DiskConfig` as argument. - - :param name: Disk name e.g. 'vda', 'sda', etc. This name may - not match the name of the disk inside the guest OS. - """ - xml = self._get_disk_by_target(name) - if xml is None: - log.warning( - "Volume with target '%s' is already detached", - name, - ) - return - disk_params = { - 'disk_type': xml.get('type'), - 'source': xml.find('source').get('file'), - 'target': xml.find('target').get('dev'), - 'readonly': False if xml.find('readonly') is None else True, # noqa: SIM211 - } - for param in disk_params: - if disk_params[param] is None: - msg = ( - f"Cannot detach volume with target '{name}': " - f"parameter '{param}' is not defined in libvirt XML " - 'config on host.' - ) - raise InstanceError(msg) - self.detach_device(DiskConfig(**disk_params), live=True) - - def resize_disk( - self, name: str, capacity: int, unit: units.DataUnit - ) -> None: - """ - Resize attached block device. - - :param name: Disk device name e.g. `vda`, `sda`, etc. - :param capacity: New capacity. - :param unit: Capacity unit. - """ - self.domain.blockResize( - name, - units.to_bytes(capacity, unit=unit), - flags=libvirt.VIR_DOMAIN_BLOCK_RESIZE_BYTES, - ) - - def get_disks(self) -> list[DiskConfig]: - """Return list of attached disks.""" - raise NotImplementedError - - def pause(self) -> None: - """Pause instance.""" - if not self.is_running(): - raise InstanceError('Cannot pause inactive instance') - self.domain.suspend() - - def resume(self) -> None: - """Resume paused instance.""" - self.domain.resume() - - def get_ssh_keys(self, user: str) -> list[str]: - """ - Return list of SSH keys on guest for specific user. - - :param user: Username. - """ - raise NotImplementedError - - def set_ssh_keys(self, user: str, ssh_keys: list[str]) -> None: - """ - Add SSH keys to guest for specific user. - - :param user: Username. - :param ssh_keys: List of public SSH keys. - """ - raise NotImplementedError - - def delete_ssh_keys(self, user: str, ssh_keys: list[str]) -> None: - """ - Remove SSH keys from guest for specific user. - - :param user: Username. - :param ssh_keys: List of public SSH keys. - """ - raise NotImplementedError - - def set_user_password( - self, user: str, password: str, *, encrypted: bool = False - ) -> None: - """ - Set new user password in guest OS. - - This action performs by guest agent inside the guest. - - :param user: Username. - :param password: Password. - :param encrypted: Set it to True if password is already encrypted. - Right encryption method depends on guest OS. - """ - if not self.guest_agent.is_available(): - raise InstanceError( - 'Cannot change password: guest agent is unavailable' - ) - self.guest_agent.raise_for_commands(['guest-set-user-password']) - flags = libvirt.VIR_DOMAIN_PASSWORD_ENCRYPTED if encrypted else 0 - self.domain.setUserPassword(user, password, flags=flags) - - def dump_xml(self, *, inactive: bool = False) -> str: - """Return instance XML description.""" - flags = libvirt.VIR_DOMAIN_XML_INACTIVE if inactive else 0 - return self.domain.XMLDesc(flags) - - def delete(self) -> None: - """Undefine instance.""" - # TODO @ge: delete local disks - self.shutdown(method='HARD') - self.domain.undefine() diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/instance/schemas.py b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/instance/schemas.py deleted file mode 100644 index f5a677c..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/instance/schemas.py +++ /dev/null @@ -1,165 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Compute instance related objects schemas.""" - -import re -from enum import StrEnum -from pathlib import Path - -from pydantic import BaseModel, Extra, validator - -from compute.utils.units import DataUnit - - -class EntityModel(BaseModel): - """Basic entity model.""" - - class Config: - """Do not allow extra fields.""" - - extra = Extra.forbid - - -class CPUEmulationMode(StrEnum): - """CPU emulation mode enumerated.""" - - HOST_PASSTHROUGH = 'host-passthrough' - HOST_MODEL = 'host-model' - CUSTOM = 'custom' - MAXIMUM = 'maximum' - - -class CPUTopologySchema(EntityModel): - """CPU topology model.""" - - sockets: int - cores: int - threads: int - dies: int = 1 - - -class CPUFeaturesSchema(EntityModel): - """CPU features model.""" - - require: list[str] - disable: list[str] - - -class CPUSchema(EntityModel): - """CPU model.""" - - emulation_mode: CPUEmulationMode - model: str | None - vendor: str | None - topology: CPUTopologySchema | None - features: CPUFeaturesSchema | None - - -class VolumeType(StrEnum): - """Storage volume types enumeration.""" - - FILE = 'file' - - -class VolumeCapacitySchema(EntityModel): - """Storage volume capacity field model.""" - - value: int - unit: DataUnit - - -class VolumeSchema(EntityModel): - """Storage volume model.""" - - type: VolumeType # noqa: A003 - target: str - capacity: VolumeCapacitySchema - source: str | None = None - is_readonly: bool = False - is_system: bool = False - - -class NetworkInterfaceSchema(EntityModel): - """Network inerface model.""" - - source: str - mac: str - - -class BootOptionsSchema(EntityModel): - """Instance boot settings.""" - - order: tuple - - -class InstanceSchema(EntityModel): - """Compute instance model.""" - - name: str - title: str | None - description: str | None - memory: int - max_memory: int - vcpus: int - max_vcpus: int - cpu: CPUSchema - machine: str - emulator: Path - arch: str - boot: BootOptionsSchema - volumes: list[VolumeSchema] - network_interfaces: list[NetworkInterfaceSchema] - image: str | None = None - - @validator('name') - def _check_name(cls, value: str) -> str: # noqa: N805 - if not re.match(r'^[a-z0-9_]+$', value): - msg = ( - 'Name can contain only lowercase letters, numbers ' - 'and underscore.' - ) - raise ValueError(msg) - return value - - @validator('cpu') - def _check_topology(cls, cpu: int, values: dict) -> CPUSchema: # noqa: N805 - topo = cpu.topology - max_vcpus = values['max_vcpus'] - if topo and topo.sockets * topo.cores * topo.threads != max_vcpus: - msg = f'CPU topology does not match with {max_vcpus=}' - raise ValueError(msg) - return cpu - - @validator('volumes') - def _check_volumes(cls, volumes: list) -> list: # noqa: N805 - if len([v for v in volumes if v.is_system is True]) != 1: - msg = 'volumes list must contain one system volume' - raise ValueError(msg) - vol_with_source = 0 - for vol in volumes: - if vol.is_system is True and vol.is_readonly is True: - msg = 'volume marked as system cannot be readonly' - raise ValueError(msg) - if vol.source is not None: - vol_with_source += 1 - return volumes - - @validator('network_interfaces') - def _check_network_interfaces(cls, value: list) -> list: # noqa: N805 - if not value: - msg = 'Network interfaces list must contain at least one element' - raise ValueError(msg) - return value diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/session.py b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/session.py deleted file mode 100644 index de5f900..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/session.py +++ /dev/null @@ -1,286 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Hypervisor session manager.""" - -import logging -import os -from contextlib import AbstractContextManager -from types import TracebackType -from typing import Any, NamedTuple -from uuid import uuid4 - -import libvirt -from lxml import etree - -from .exceptions import ( - InstanceNotFoundError, - SessionError, - StoragePoolNotFoundError, -) -from .instance import Instance, InstanceConfig, InstanceSchema -from .storage import DiskConfig, StoragePool, VolumeConfig -from .utils import units - - -log = logging.getLogger(__name__) - - -class Capabilities(NamedTuple): - """Store domain capabilities info.""" - - arch: str - virt_type: str - emulator: str - machine: str - max_vcpus: int - cpu_vendor: str - cpu_model: str - cpu_features: dict - usable_cpus: list[dict] - - -class NodeInfo(NamedTuple): - """ - Store compute node info. - - See https://libvirt.org/html/libvirt-libvirt-host.html#virNodeInfo - NOTE: memory unit in libvirt docs is wrong! Actual unit is MiB. - """ - - arch: str - memory: int - cpus: int - mhz: int - nodes: int - sockets: int - cores: int - threads: int - - -class Session(AbstractContextManager): - """ - Hypervisor session context manager. - - :cvar IMAGES_POOL: images storage pool name taken from env - :cvar VOLUMES_POOL: volumes storage pool name taken from env - """ - - IMAGES_POOL = os.getenv('CMP_IMAGES_POOL') - VOLUMES_POOL = os.getenv('CMP_VOLUMES_POOL') - - def __init__(self, uri: str | None = None): - """ - Initialise session with hypervisor. - - :ivar str uri: libvirt connection URI. - :ivar libvirt.virConnect connection: libvirt connection object. - - :param uri: libvirt connection URI. - """ - self.uri = uri or 'qemu:///system' - self.connection = libvirt.open(self.uri) - - def __enter__(self): - """Return Session object.""" - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - exc_traceback: TracebackType | None, - ): - """Close the connection when leaving the context.""" - self.close() - - def close(self) -> None: - """Close connection to libvirt daemon.""" - self.connection.close() - - def get_node_info(self) -> NodeInfo: - """Return information about compute node.""" - info = self.connection.getInfo() - return NodeInfo( - arch=info[0], - memory=info[1], - cpus=info[2], - mhz=info[3], - nodes=info[4], - sockets=info[5], - cores=info[6], - threads=info[7], - ) - - def _cap_get_usable_cpus(self, xml: etree.Element) -> list[dict]: - x = xml.xpath('/domainCapabilities/cpu/mode[@name="custom"]')[0] - cpus = [] - for cpu in x.findall('model'): - if cpu.get('usable') == 'yes': - cpus.append( # noqa: PERF401 - { - 'vendor': cpu.get('vendor'), - 'model': cpu.text, - } - ) - return cpus - - def _cap_get_cpu_features(self, xml: etree.Element) -> dict: - x = xml.xpath('/domainCapabilities/cpu/mode[@name="host-model"]')[0] - require = [] - disable = [] - for feature in x.findall('feature'): - policy = feature.get('policy') - name = feature.get('name') - if policy == 'require': - require.append(name) - if policy == 'disable': - disable.append(name) - return {'require': require, 'disable': disable} - - def get_capabilities(self) -> Capabilities: - """Return capabilities e.g. arch, virt, emulator, etc.""" - prefix = '/domainCapabilities' - hprefix = f'{prefix}/cpu/mode[@name="host-model"]' - caps = etree.fromstring(self.connection.getDomainCapabilities()) # noqa: S320 - return Capabilities( - arch=caps.xpath(f'{prefix}/arch/text()')[0], - virt_type=caps.xpath(f'{prefix}/domain/text()')[0], - emulator=caps.xpath(f'{prefix}/path/text()')[0], - machine=caps.xpath(f'{prefix}/machine/text()')[0], - max_vcpus=int(caps.xpath(f'{prefix}/vcpu/@max')[0]), - cpu_vendor=caps.xpath(f'{hprefix}/vendor/text()')[0], - cpu_model=caps.xpath(f'{hprefix}/model/text()')[0], - cpu_features=self._cap_get_cpu_features(caps), - usable_cpus=self._cap_get_cpus(caps), - ) - - def create_instance(self, **kwargs: Any) -> Instance: - """ - Create and return new compute instance. - - :param name: Instance name. - :type name: str - :param title: Instance title for humans. - :type title: str - :param description: Some information about instance. - :type description: str - :param memory: Memory in MiB. - :type memory: int - :param max_memory: Maximum memory in MiB. - :type max_memory: int - :param vcpus: Number of vCPUs. - :type vcpus: int - :param max_vcpus: Maximum vCPUs. - :type max_vcpus: int - :param cpu: CPU configuration. See :class:`CPUSchema` for info. - :type cpu: dict - :param machine: QEMU emulated machine. - :type machine: str - :param emulator: Path to emulator. - :type emulator: str - :param arch: CPU architecture to virtualization. - :type arch: str - :param boot: Boot settings. See :class:`BootOptionsSchema`. - :type boot: dict - :param image: Source disk image name for system disk. - :type image: str - :param volumes: List of storage volume configs. For more info - see :class:`VolumeSchema`. - :type volumes: list[dict] - :param network_interfaces: List of virtual network interfaces - configs. See :class:`NetworkInterfaceSchema` for more info. - :type network_interfaces: list[dict] - """ - data = InstanceSchema(**kwargs) - config = InstanceConfig(data) - log.info('Define XML...') - log.info(config.to_xml()) - self.connection.defineXML(config.to_xml()) - log.info('Getting instance...') - instance = self.get_instance(config.name) - log.info('Creating volumes...') - for volume in data.volumes: - log.info('Creating volume=%s', volume) - capacity = units.to_bytes( - volume.capacity.value, volume.capacity.unit - ) - log.info('Connecting to images pool...') - images_pool = self.get_storage_pool(self.IMAGES_POOL) - log.info('Connecting to volumes pool...') - volumes_pool = self.get_storage_pool(self.VOLUMES_POOL) - log.info('Building volume configuration...') - if not volume.source: - vol_name = f'{uuid4()}.qcow2' - else: - vol_name = volume.source - vol_conf = VolumeConfig( - name=vol_name, - path=str(volumes_pool.path.joinpath(vol_name)), - capacity=capacity, - ) - log.info('Volume configuration is:\n %s', vol_conf.to_xml()) - if volume.is_system is True and data.image: - log.info( - "Volume is marked as 'system', start cloning image..." - ) - log.info('Get image %s', data.image) - image = images_pool.get_volume(data.image) - log.info('Cloning image into volumes pool...') - vol = volumes_pool.clone_volume(image, vol_conf) - log.info( - 'Resize cloned volume to specified size: %s', - capacity, - ) - vol.resize(capacity, unit=units.DataUnit.BYTES) - else: - log.info('Create volume...') - volumes_pool.create_volume(vol_conf) - log.info('Attaching volume to instance...') - instance.attach_device( - DiskConfig( - disk_type=volume.type, - source=vol_conf.path, - target=volume.target, - readonly=volume.is_readonly, - ) - ) - return instance - - def get_instance(self, name: str) -> Instance: - """Get compute instance by name.""" - try: - return Instance(self.connection.lookupByName(name)) - except libvirt.libvirtError as e: - if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN: - raise InstanceNotFoundError(name) from e - raise SessionError(e) from e - - def list_instances(self) -> list[Instance]: - """List all instances.""" - return [Instance(dom) for dom in self.connection.listAllDomains()] - - def get_storage_pool(self, name: str) -> StoragePool: - """Get storage pool by name.""" - try: - return StoragePool(self.connection.storagePoolLookupByName(name)) - except libvirt.libvirtError as e: - if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_POOL: - raise StoragePoolNotFoundError(name) from e - raise SessionError(e) from e - - def list_storage_pools(self) -> list[StoragePool]: - """List all strage pools.""" - return [StoragePool(p) for p in self.connection.listStoragePools()] diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/storage/__init__.py b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/storage/__init__.py deleted file mode 100644 index 34aae30..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/storage/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -from .pool import StoragePool -from .volume import DiskConfig, Volume, VolumeConfig diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/storage/pool.py b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/storage/pool.py deleted file mode 100644 index cb17494..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/storage/pool.py +++ /dev/null @@ -1,124 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Manage storage pools.""" - -import logging -from pathlib import Path -from typing import NamedTuple - -import libvirt -from lxml import etree - -from compute.exceptions import StoragePoolError, VolumeNotFoundError - -from .volume import Volume, VolumeConfig - - -log = logging.getLogger(__name__) - - -class StoragePoolUsageInfo(NamedTuple): - """Storage pool usage info.""" - - capacity: int - allocation: int - available: int - - -class StoragePool: - """Storage pool manipulating class.""" - - def __init__(self, pool: libvirt.virStoragePool): - """Initislise StoragePool.""" - self.pool = pool - self.name = pool.name() - self.path = self._get_path() - - def _get_path(self) -> Path: - """Return storage pool path.""" - xml = etree.fromstring(self.pool.XMLDesc()) # noqa: S320 - return Path(xml.xpath('/pool/target/path/text()')[0]) - - def get_usage_info(self) -> StoragePoolUsageInfo: - """Return info about storage pool usage.""" - xml = etree.fromstring(self.pool.XMLDesc()) # noqa: S320 - return StoragePoolUsageInfo( - capacity=int(xml.xpath('/pool/capacity/text()')[0]), - allocation=int(xml.xpath('/pool/allocation/text()')[0]), - available=int(xml.xpath('/pool/available/text()')[0]), - ) - - def dump_xml(self) -> str: - """Return storage pool XML description as string.""" - return self.pool.XMLDesc() - - def refresh(self) -> None: - """Refresh storage pool.""" - # TODO @ge: handle libvirt asynchronous job related exceptions - self.pool.refresh() - - def create_volume(self, vol_conf: VolumeConfig) -> Volume: - """Create storage volume and return Volume instance.""" - log.info( - 'Create storage volume vol=%s in pool=%s', vol_conf.name, self.name - ) - vol = self.pool.createXML( - vol_conf.to_xml(), - flags=libvirt.VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, - ) - return Volume(self.pool, vol) - - def clone_volume(self, src: Volume, dst: VolumeConfig) -> Volume: - """ - Make storage volume copy. - - :param src: Input volume - :param dst: Output volume config - """ - log.info( - 'Start volume cloning ' - 'src_pool=%s src_vol=%s dst_pool=%s dst_vol=%s', - src.pool_name, - src.name, - self.pool.name, - dst.name, - ) - vol = self.pool.createXMLFrom( - dst.to_xml(), # new volume XML description - src.vol, # source volume virStorageVol object - flags=libvirt.VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, - ) - if vol is None: - raise StoragePoolError - return Volume(self.pool, vol) - - def get_volume(self, name: str) -> Volume | None: - """Lookup and return Volume instance or None.""" - log.info( - 'Lookup for storage volume vol=%s in pool=%s', name, self.pool.name - ) - try: - vol = self.pool.storageVolLookupByName(name) - return Volume(self.pool, vol) - except libvirt.libvirtError as e: - if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_VOL: - raise VolumeNotFoundError(name) from e - log.exception('unexpected error from libvirt') - raise StoragePoolError(e) from e - - def list_volumes(self) -> list[Volume]: - """Return list of volumes in storage pool.""" - return [Volume(self.pool, vol) for vol in self.pool.listAllVolumes()] diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/storage/volume.py b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/storage/volume.py deleted file mode 100644 index 11a1dc4..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/storage/volume.py +++ /dev/null @@ -1,138 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Manage storage volumes.""" - -from dataclasses import dataclass -from pathlib import Path -from time import time - -import libvirt -from lxml import etree -from lxml.builder import E - -from compute.common import DeviceConfig, EntityConfig -from compute.utils import units - - -@dataclass -class VolumeConfig(EntityConfig): - """ - Storage volume XML config builder. - - Generate XML config for creating a volume in a libvirt - storage pool. - """ - - name: str - path: str - capacity: int - - def to_xml(self) -> str: - """Return XML config for libvirt.""" - unixtime = str(int(time())) - xml = E.volume(type='file') - xml.append(E.name(self.name)) - xml.append(E.key(self.path)) - xml.append(E.source()) - xml.append(E.capacity(str(self.capacity), unit='bytes')) - xml.append(E.allocation('0')) - xml.append( - E.target( - E.path(self.path), - E.format(type='qcow2'), - E.timestamps( - E.atime(unixtime), E.mtime(unixtime), E.ctime(unixtime) - ), - E.compat('1.1'), - E.features(E.lazy_refcounts()), - ) - ) - return etree.tostring(xml, encoding='unicode', pretty_print=True) - - -@dataclass -class DiskConfig(DeviceConfig): - """ - Disk XML config builder. - - Generate XML config for attaching or detaching storage volumes - to compute instances. - """ - - disk_type: str - source: str | Path - target: str - readonly: bool = False - - def to_xml(self) -> str: - """Return XML config for libvirt.""" - xml = E.disk(type=self.disk_type, device='disk') - xml.append(E.driver(name='qemu', type='qcow2', cache='writethrough')) - if self.disk_type == 'file': - xml.append(E.source(file=str(self.source))) - xml.append(E.target(dev=self.target, bus='virtio')) - if self.readonly: - xml.append(E.readonly()) - return etree.tostring(xml, encoding='unicode', pretty_print=True) - - -class Volume: - """Storage volume manipulating class.""" - - def __init__( - self, pool: libvirt.virStoragePool, vol: libvirt.virStorageVol - ): - """ - Initialise Volume. - - :param pool: libvirt virStoragePool object - :param vol: libvirt virStorageVol object - """ - self.pool = pool - self.pool_name = pool.name() - self.vol = vol - self.name = vol.name() - self.path = Path(vol.path()) - - def dump_xml(self) -> str: - """Return volume XML description as string.""" - return self.vol.XMLDesc() - - def clone(self, vol_conf: VolumeConfig) -> None: - """ - Make a copy of volume to the same storage pool. - - :param vol_info VolumeInfo: New storage volume dataclass object - """ - self.pool.createXMLFrom( - vol_conf.to_xml(), - self.vol, - flags=libvirt.VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, - ) - - def resize(self, capacity: int, unit: units.DataUnit) -> None: - """ - Resize volume. - - :param capacity int: Volume new capacity. - :param unit DataUnit: Data unit. Internally converts into bytes. - """ - # TODO @ge: Check actual volume size before resize - self.vol.resize(units.to_bytes(capacity, unit=unit)) - - def delete(self) -> None: - """Delete volume from storage pool.""" - self.vol.delete() diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/utils/__init__.py b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/utils/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/utils/config_loader.py b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/utils/config_loader.py deleted file mode 100644 index aaeb0fe..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/utils/config_loader.py +++ /dev/null @@ -1,56 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Configuration loader.""" - -import tomllib -from collections import UserDict -from pathlib import Path - -from compute.exceptions import ConfigLoaderError - - -DEFAULT_CONFIGURATION = {} -DEFAULT_CONFIG_FILE = '/etc/computed/computed.toml' - - -class ConfigLoader(UserDict): - """UserDict for storing configuration.""" - - def __init__(self, file: Path | None = None): - """ - Initialise ConfigLoader. - - :param file: Path to configuration file. If `file` is None - use default path from DEFAULT_CONFIG_FILE constant. - """ - # TODO @ge: load deafult configuration - self.file = Path(file) if file else Path(DEFAULT_CONFIG_FILE) - super().__init__(self.load()) - - def load(self) -> dict: - """Load confguration object from TOML file.""" - try: - with Path(self.file).open('rb') as configfile: - return tomllib.load(configfile) - # TODO @ge: add config schema validation - except tomllib.TOMLDecodeError as tomlerr: - raise ConfigLoaderError( - f'Bad TOML syntax in config file: {self.file}: {tomlerr}' - ) from tomlerr - except (OSError, ValueError) as readerr: - raise ConfigLoaderError( - f'Cannot read config file: {self.file}: {readerr}' - ) from readerr diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/utils/ids.py b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/utils/ids.py deleted file mode 100644 index 8a6454a..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/utils/ids.py +++ /dev/null @@ -1,33 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Random identificators.""" - -# ruff: noqa: S311, C417 - -import random - - -def random_mac() -> str: - """Retrun random MAC address.""" - mac = [ - 0x00, - 0x16, - 0x3E, - random.randint(0x00, 0x7F), - random.randint(0x00, 0xFF), - random.randint(0x00, 0xFF), - ] - return ':'.join(map(lambda x: '%02x' % x, mac)) diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/utils/units.py b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/utils/units.py deleted file mode 100644 index 57a4583..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/lib/python3/dist-packages/compute/utils/units.py +++ /dev/null @@ -1,54 +0,0 @@ -# This file is part of Compute -# -# Compute is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -"""Tools for data units convertion.""" - -from enum import StrEnum - - -class DataUnit(StrEnum): - """Data units enumerated.""" - - BYTES = 'bytes' - KIB = 'KiB' - MIB = 'MiB' - GIB = 'GiB' - TIB = 'TiB' - - -class InvalidDataUnitError(ValueError): - """Data unit is not valid.""" - - def __init__(self, msg: str): - """Initialise InvalidDataUnitError.""" - super().__init__( - f'{msg}, valid units are: {", ".join(list(DataUnit))}' - ) - - -def to_bytes(value: int, unit: DataUnit = DataUnit.BYTES) -> int: - """Convert value to bytes. See :class:`DataUnit`.""" - try: - _ = DataUnit(unit) - except ValueError as e: - raise InvalidDataUnitError(e) from e - powers = { - DataUnit.BYTES: 0, - DataUnit.KIB: 1, - DataUnit.MIB: 2, - DataUnit.GIB: 3, - DataUnit.TIB: 4, - } - return value * pow(1024, powers[unit]) diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/share/bash-completion/completions/compute b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/share/bash-completion/completions/compute deleted file mode 100644 index a0dcdf2..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/share/bash-completion/completions/compute +++ /dev/null @@ -1,93 +0,0 @@ -# compute bash completion script - -_compute_root_cmd=" - --version - --verbose - --connect - --log-level - init - exec - ls - start - shutdown - reboot - reset - powrst - pause - resume - status - setvcpus - setmem - setpasswd" -_compute_init_opts="" -_compute_exec_opts=" - --timeout - --executable - --env - --no-join-args" -_compute_ls_opts="" -_compute_start_opts="" -_compute_shutdown_opts="--method" -_compute_reboot_opts="" -_compute_reset_opts="" -_compute_powrst_opts="" -_compute_pause_opts="" -_compute_resume_opts="" -_compute_status_opts="" -_compute_setvcpus_opts="" -_compute_setmem_opts="" -_compute_setpasswd_opts="--encrypted" - -_compute_complete_instances() -{ - for file in /etc/libvirt/qemu/*.xml; do - nodir="${file##*/}" - printf '%s ' "${nodir//\.xml}" - done -} - -_compute_compreply() -{ - if [[ "$current" = [a-z]* ]]; then - _compute_compwords="$(_compute_complete_instances)" - else - _compute_compwords="$*" - fi - COMPREPLY=($(compgen -W "$_compute_compwords" -- "$current")) -} - -_compute_complete() -{ - local current previous nshift - current="${COMP_WORDS[COMP_CWORD]}" - case "$COMP_CWORD" in - 1) COMPREPLY=($(compgen -W "$_compute_root_cmd" -- "$current")) - ;; - 2|3|4|5) - nshift=$((COMP_CWORD-1)) - previous="${COMP_WORDS[COMP_CWORD-nshift]}" - case "$previous" in - init) COMPREPLY=($(compgen -f -- "$current"));; - exec) _compute_compreply "$_compute_exec_opts";; - ls) COMPREPLY=($(compgen -W "$_compute_ls_opts" -- "$current"));; - start) _compute_compreply "$_compute_start_opts";; - shutdown) _compute_compreply "$_compute_shutdown_opts";; - reboot) _compute_compreply "$_compute_reboot_opts";; - reset) _compute_compreply "$_compute_reset_opts";; - powrst) _compute_compreply "$_compute_powrst_opts";; - pause) _compute_compreply "$_compute_pause_opts";; - resume) _compute_compreply "$_compute_resume_opts";; - status) _compute_compreply "$_compute_status_opts";; - setvcpus) _compute_compreply "$_compute_setvcpus_opts";; - setmem) _compute_compreply "$_compute_setmem_opts";; - setpasswd) _compute_compreply "$_compute_setpasswd_opts";; - *) COMPREPLY=() - esac - ;; - *) COMPREPLY=($(compgen -W "$_compute_compwords" -- "$current")) - esac -} - -complete -F _compute_complete compute - -# vim: ft=bash diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/share/doc/compute/README.md b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/share/doc/compute/README.md deleted file mode 100644 index 0131e8e..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/share/doc/compute/README.md +++ /dev/null @@ -1,65 +0,0 @@ -# Compute - -Compute instances management library and tools. - -## Docs - -Run `make serve-docs`. See [Development](#development) below. - -## Roadmap - -- [x] Create instances -- [ ] CDROM -- [ ] cloud-init for provisioning instances -- [x] Instance power management -- [x] Instance pause and resume -- [x] vCPU hotplug -- [x] Memory hotplug -- [x] Hot disk resize [not tested] -- [ ] CPU topology customization -- [x] CPU customization (emulation mode, model, vendor, features) -- [ ] BIOS/UEFI settings -- [x] Device attaching -- [x] Device detaching -- [ ] GPU passthrough -- [ ] CPU guarantied resource percent support -- [x] QEMU Guest Agent management -- [ ] Instance resources usage stats -- [ ] SSH-keys management -- [x] Setting user passwords in guest -- [x] QCOW2 disks support -- [ ] ZVOL support -- [ ] Network disks support -- [ ] Images service integration (Images service is not implemented yet) -- [ ] Manage storage pools -- [ ] Idempotency -- [ ] CLI [in progress] -- [ ] HTTP API -- [ ] Instance migrations -- [ ] Instance snapshots -- [ ] Instance backups -- [ ] LXC - -## Development - -Python 3.11+ is required. - -Install [poetry](https://python-poetry.org/), clone this repository and run: - -``` -poetry install --with dev --with docs -``` - -# Build Debian package - -Install Docker first, then run: - -``` -make build-deb -``` - -`compute` and `compute-doc` packages will built. See packaging/build directory. Packages can be installed via `dpkg` or `apt-get`: - -``` -apt-get install ./compute*.deb -``` diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/share/doc/compute/changelog.Debian.gz b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/share/doc/compute/changelog.Debian.gz deleted file mode 100644 index 40eae6fedeef605a8bc33ff14a672c4eec8e46c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 176 zcmV;h08jrPiwFP!000020}YJJ4uUWgME88fEPc_GVqD-On#j($@DbNoF3?C@LR+GL zZzr>woH^3!A$Y=!vy5?8)0Cyz9M9{myp*SVdEO$7EgAXSYpPYyNdheJ=#)dO?+Ecj zy&W_ek9Sagy@Dfxv|1}4DT6RLKT@SJ(qPfpF^-L8QI)1>3A>h#Mt!?VejGF855S9} eMhIN(1i?iPkr#YZtaB`RO!5cgr!y+J0000<1Wum- diff --git a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/share/doc/compute/copyright b/packaging/build/compute-0.1.0.dev1/debian/compute/usr/share/doc/compute/copyright deleted file mode 100644 index 185dcbf..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/compute/usr/share/doc/compute/copyright +++ /dev/null @@ -1,32 +0,0 @@ -Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Source: https://git.lulzette.ru/hstack/compute -Upstream-Name: compute - -Files: - * -Copyright: - 2023 ge -License: GPL-3.0+ - -Files: - debian/* -Copyright: - 2023 ge -License: GPL-3.0+ - -License: GPL-3.0+ - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - . - This package is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - . - You should have received a copy of the GNU General Public License - along with this program. If not, see . -Comment: - On Debian systems, the complete text of the GNU General - Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". diff --git a/packaging/build/compute-0.1.0.dev1/debian/control b/packaging/build/compute-0.1.0.dev1/debian/control deleted file mode 100644 index 6b99835..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/control +++ /dev/null @@ -1,48 +0,0 @@ -Source: compute -Section: admin -Priority: optional -Maintainer: ge -Rules-Requires-Root: no -Build-Depends: - debhelper-compat (= 13), - dh-sequence-python3, - bash-completion, - pybuild-plugin-pyproject, - python3-poetry-core, - python3-setuptools, - python3-all, - python3-sphinx, - python3-sphinx-multiversion, - python3-libvirt, - python3-lxml, - python3-yaml, - python3-pydantic -Standards-Version: 4.6.2 -Homepage: https://git.lulzette.ru/hstack/compute - -Package: compute -Architecture: all -Depends: - ${python3:Depends}, - ${misc:Depends}, - qemu-system, - qemu-utils, - libvirt-daemon-system, - libvirt-clients, - python3-libvirt, - python3-lxml, - python3-yaml, - python3-pydantic -Recommends: - dnsmasq -Suggests: - compute-doc -Description: Compute instances management library and tools (Python 3) - -Package: compute-doc -Section: doc -Architecture: all -Depends: - ${sphinxdoc:Depends}, - ${misc:Depends}, -Description: Compute instances management library and tools (documentation) diff --git a/packaging/build/compute-0.1.0.dev1/debian/copyright b/packaging/build/compute-0.1.0.dev1/debian/copyright deleted file mode 100644 index 185dcbf..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/copyright +++ /dev/null @@ -1,32 +0,0 @@ -Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Source: https://git.lulzette.ru/hstack/compute -Upstream-Name: compute - -Files: - * -Copyright: - 2023 ge -License: GPL-3.0+ - -Files: - debian/* -Copyright: - 2023 ge -License: GPL-3.0+ - -License: GPL-3.0+ - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - . - This package is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - . - You should have received a copy of the GNU General Public License - along with this program. If not, see . -Comment: - On Debian systems, the complete text of the GNU General - Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". diff --git a/packaging/build/compute-0.1.0.dev1/debian/debhelper-build-stamp b/packaging/build/compute-0.1.0.dev1/debian/debhelper-build-stamp deleted file mode 100644 index 3445b01..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/debhelper-build-stamp +++ /dev/null @@ -1,2 +0,0 @@ -compute -compute-doc diff --git a/packaging/build/compute-0.1.0.dev1/debian/docs b/packaging/build/compute-0.1.0.dev1/debian/docs deleted file mode 100644 index b43bf86..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/docs +++ /dev/null @@ -1 +0,0 @@ -README.md diff --git a/packaging/build/compute-0.1.0.dev1/debian/files b/packaging/build/compute-0.1.0.dev1/debian/files deleted file mode 100644 index e63edf9..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/files +++ /dev/null @@ -1,3 +0,0 @@ -compute-doc_0.1.0.dev1-1_all.deb doc optional -compute_0.1.0.dev1-1_all.deb admin optional -compute_0.1.0.dev1-1_amd64.buildinfo admin optional diff --git a/packaging/build/compute-0.1.0.dev1/debian/rules b/packaging/build/compute-0.1.0.dev1/debian/rules deleted file mode 100755 index f99ef32..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/rules +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/make -f - -export DH_VERBOSE = 1 -export PYBUILD_DESTDIR_python3=debian/compute - -%: - dh $@ --with python3,sphinxdoc,bash-completion --buildsystem=pybuild - -override_dh_auto_test: - @echo No tests there - -override_dh_sphinxdoc: -ifeq (,$(findstring nodoc, $(DEB_BUILD_OPTIONS))) - http_proxy=127.0.0.1:9 https_proxy=127.0.0.1:9 \ - HTTP_PROXY=127.0.0.1:9 HTTPS_PROXY=127.0.0.1:9 \ - PYTHONPATH=. PYTHON=python3 python3 -m sphinx $(SPHINXOPTS) -b html \ - ../docs/source \ - $(CURDIR)/debian/compute-doc/usr/share/doc/compute-doc/html - dh_sphinxdoc -endif diff --git a/packaging/build/compute-0.1.0.dev1/debian/source/format b/packaging/build/compute-0.1.0.dev1/debian/source/format deleted file mode 100644 index 163aaf8..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/packaging/build/compute-0.1.0.dev1/debian/source/options b/packaging/build/compute-0.1.0.dev1/debian/source/options deleted file mode 100644 index cb61fa5..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/source/options +++ /dev/null @@ -1 +0,0 @@ -extend-diff-ignore = "^[^/]*[.]egg-info/" diff --git a/packaging/build/compute-0.1.0.dev1/debian/upstream/metadata.ex b/packaging/build/compute-0.1.0.dev1/debian/upstream/metadata.ex deleted file mode 100644 index 3fc47cc..0000000 --- a/packaging/build/compute-0.1.0.dev1/debian/upstream/metadata.ex +++ /dev/null @@ -1,10 +0,0 @@ -# Example file for upstream/metadata. -# See https://wiki.debian.org/UpstreamMetadata for more info/fields. -# Below an example based on a github project. - -# Bug-Database: https://github.com//compute/issues -# Bug-Submit: https://github.com//compute/issues/new -# Changelog: https://github.com//compute/blob/master/CHANGES -# Documentation: https://github.com//compute/wiki -# Repository-Browse: https://github.com//compute -# Repository: https://github.com//compute.git diff --git a/packaging/build/compute-0.1.0.dev1/pyproject.toml b/packaging/build/compute-0.1.0.dev1/pyproject.toml deleted file mode 100644 index f7aab25..0000000 --- a/packaging/build/compute-0.1.0.dev1/pyproject.toml +++ /dev/null @@ -1,61 +0,0 @@ -[tool.poetry] -name = 'compute' -version = '0.1.0-dev1' -description = 'Compute instances management library and tools' -authors = ['ge '] -readme = 'README.md' - -[tool.poetry.dependencies] -python = '^3.11' -libvirt-python = '9.0.0' -lxml = '^4.9.2' -pydantic = '1.10.4' -pyyaml = "^6.0.1" - -[tool.poetry.scripts] -compute = 'compute.cli.control:cli' - -[tool.poetry.group.dev.dependencies] -ruff = '^0.1.3' -isort = '^5.12.0' - -[tool.poetry.group.docs.dependencies] -sphinx = '^7.2.6' -sphinx-autobuild = '^2021.3.14' -sphinx-multiversion = '^0.2.4' - -[build-system] -requires = ['poetry-core'] -build-backend = 'poetry.core.masonry.api' - -[tool.isort] -skip = ['.gitignore'] -lines_after_imports = 2 -include_trailing_comma = true -split_on_trailing_comma = true - -[tool.ruff] -line-length = 79 -indent-width = 4 -target-version = 'py311' - -[tool.ruff.lint] -select = ['ALL'] -ignore = [ - 'Q000', 'Q003', 'D211', 'D212', - 'ANN101', 'ISC001', 'COM812', - 'D203', 'ANN204', 'T201', - 'EM102', 'TRY003', 'EM101', - 'TD003', 'TD006', 'FIX002', # 'todo' strings linting -] -exclude = ['__init__.py'] - -[tool.ruff.lint.flake8-annotations] -mypy-init-return = true -allow-star-arg-any = true - -[tool.ruff.format] -quote-style = 'single' - -[tool.ruff.isort] -lines-after-imports = 2 diff --git a/packaging/build/compute-doc_0.1.0.dev1-1_all.deb b/packaging/build/compute-doc_0.1.0.dev1-1_all.deb deleted file mode 100644 index c855890142ef68ebf4b458346f82e88e33503a60..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40424 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 So|BNV#Ao{g000001X)_6^9At$ diff --git a/packaging/build/compute_0.1.0.dev1-1.dsc b/packaging/build/compute_0.1.0.dev1-1.dsc deleted file mode 100644 index 91f1fdb..0000000 --- a/packaging/build/compute_0.1.0.dev1-1.dsc +++ /dev/null @@ -1,21 +0,0 @@ -Format: 3.0 (quilt) -Source: compute -Binary: compute, compute-doc -Architecture: all -Version: 0.1.0.dev1-1 -Maintainer: ge -Homepage: https://git.lulzette.ru/hstack/compute -Standards-Version: 4.6.2 -Build-Depends: debhelper-compat (= 13), dh-sequence-python3, bash-completion, pybuild-plugin-pyproject, python3-poetry-core, python3-setuptools, python3-all, python3-sphinx, python3-sphinx-multiversion, python3-libvirt, python3-lxml, python3-yaml, python3-pydantic -Package-List: - compute deb admin optional arch=all - compute-doc deb doc optional arch=all -Checksums-Sha1: - 94be605a5a0ca8b0ea93a46dd5029a2513486190 20824 compute_0.1.0.dev1.orig.tar.gz - 57790e9df9659f913fa1da65b77c84a3aba4976c 2660 compute_0.1.0.dev1-1.debian.tar.xz -Checksums-Sha256: - e310d2ddbdb334737efc7adcc98eac2db2f158e5e989ddfade2ddfae07a6174d 20824 compute_0.1.0.dev1.orig.tar.gz - c9e267c79fa5a9e06625ac0502af528f4b526c74035fa23e6933c2c8e6429ab2 2660 compute_0.1.0.dev1-1.debian.tar.xz -Files: - de78bd5eecc56034a990dd9395a089c4 20824 compute_0.1.0.dev1.orig.tar.gz - cb9d6978a83d7f1842063315333d6278 2660 compute_0.1.0.dev1-1.debian.tar.xz diff --git a/packaging/build/compute_0.1.0.dev1-1_all.deb b/packaging/build/compute_0.1.0.dev1-1_all.deb deleted file mode 100644 index d448f2231fa0b5a10947ae24224cb64299845e2f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21644 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 -Changed-By: ge -Description: - compute - Compute instances management library and tools (Python 3) - compute-doc - Compute instances management library and tools (documentation) -Changes: - compute (0.1.0.dev1-1) UNRELEASED; urgency=medium - . - * This is the development build, see commits in upstream repo for info. -Checksums-Sha1: - 455d0b203d96d97d4272d30be72c27cdde50fdc5 1123 compute_0.1.0.dev1-1.dsc - 94be605a5a0ca8b0ea93a46dd5029a2513486190 20824 compute_0.1.0.dev1.orig.tar.gz - 57790e9df9659f913fa1da65b77c84a3aba4976c 2660 compute_0.1.0.dev1-1.debian.tar.xz - ef2a0d6dd481adc0cf4bed1a2bc98536f1795adf 40424 compute-doc_0.1.0.dev1-1_all.deb - 20ecb0342e494a426634a5124462e49c6f7fd2c9 21644 compute_0.1.0.dev1-1_all.deb - 78f050568f3f50c415f23caf851482663c78513e 8126 compute_0.1.0.dev1-1_amd64.buildinfo -Checksums-Sha256: - c92ba4e3db43b496e01aa912f6e59240f7cd647b8b4950005182d91d071e31ac 1123 compute_0.1.0.dev1-1.dsc - e310d2ddbdb334737efc7adcc98eac2db2f158e5e989ddfade2ddfae07a6174d 20824 compute_0.1.0.dev1.orig.tar.gz - c9e267c79fa5a9e06625ac0502af528f4b526c74035fa23e6933c2c8e6429ab2 2660 compute_0.1.0.dev1-1.debian.tar.xz - 1c0d14fc87885f5dafe8bcbe1b6a07d9a57ce2dc0943a9837f751e3142ee8a42 40424 compute-doc_0.1.0.dev1-1_all.deb - a1f5a032f653276be3e4dc43818d663850463167a2b4b39138e184be1dabb44f 21644 compute_0.1.0.dev1-1_all.deb - d4ae62c2a518e36ba1acd6d56a94d1b218ffd766f5f558d7c73ac7a2ffe8102d 8126 compute_0.1.0.dev1-1_amd64.buildinfo -Files: - 635eae482cdff5bbe99a3911ed9e915c 1123 admin optional compute_0.1.0.dev1-1.dsc - de78bd5eecc56034a990dd9395a089c4 20824 admin optional compute_0.1.0.dev1.orig.tar.gz - cb9d6978a83d7f1842063315333d6278 2660 admin optional compute_0.1.0.dev1-1.debian.tar.xz - 8a8c6490cb363870735ec2572cf65cdf 40424 doc optional compute-doc_0.1.0.dev1-1_all.deb - bf5fb2ffd00e5373a54461f34b2d7033 21644 admin optional compute_0.1.0.dev1-1_all.deb - c319ab6fc548baccadb65dee3b0869af 8126 admin optional compute_0.1.0.dev1-1_amd64.buildinfo diff --git a/packaging/build/compute_0.1.0.dev1.orig.tar.gz b/packaging/build/compute_0.1.0.dev1.orig.tar.gz deleted file mode 100644 index fcb6882313d06126099819d8417de54da00684f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20824 zcmV)7K*zryiwFn+00002|6^}$aCLNLEif)IE-)@+Wp*(xbYXG;?Y(Pz+c=UaJfHO| zxaoHuN9W{I|_wDp-`9LW$^N^$Kk{KC>%!VAAXZhi$7I=TdlSA;yb3dTdVEWKX?y+_#Hm8 zEDuxY{trLqXZ4jg&f{^^ZEv+&o3GbbH`_t$)#lb#d#m<`<>&wT&mb93XL+>J3SixX zVRYAidD7e7J?I7F;rHDCo9pXU`+s$FYx587^^Mi7jn?|w<_7Hl)zyuSKX|R>{{PKC zKY2Th0kxX=;>8mH$z%{^-Z-3uH_(I}Z>BNz3bhQ+UjcLiVXxt)_F9FD_jt+wKw zKU{b_X%y-s!DJ7TcTbKE#P`7{nGILsNt}DvN$O40*^Nj#h{g$k!%Tdi>ZuH{Lp*52dk0i01pWUSc(`X8RmI7xP^2xc^GNQ(9Am+$TZBd{5DNy zH@DjOZ)RZ{PVzV+FeS4TAs4~FfG62(I!#gu*njUGeDL1Q00Q3j4Q895_cYMUmNIXa zK@ks7!we7r1_`~&VeB0JeU(-w(+3DG|HsFp zeJklO%At`@&f7L~*;2+; zIQTT1%H;ij?C|a`c5AJ6{FvXuJlBGD`%gH#H2T*pPNN}gU}|PG^3JD8l&6mu_1iq3 zW}TNWr&MQ!lY=C^dD&><&YeVFeoJjklPt~?L0Hn+q*JS1US8I?25)3&cxB~2&Tj!l z@6=Z$JXo^!llNv8kA^VVt2hK8!At<8#h`#heFEgTj?*k}LbuUG>xYQe71m!FMpxY6 zr8pBWX-x7L617X&dgk57&@@)ena*(rpyEqv4X`JT1~{?6JC=0@FubcsP6`m>E)KoR z;q=qZr3WPJGMwfsH&K2m#wLC$AOtVPP<{^NSihbA2TT5c$^UEo|9WdRXs^G1)mq3IZ$R-S|Np!2|7Um*U&kY2S*Br{ zd¶#P_E7X-|{PT{D_lI#3FOrwtXn9S%<11=!W@-)7pVmY3hFX2D~J~h66gccxa zHi6>>Pha4N({YA<;E#8Qz#m4FC=Ey6@$70854?Tgo+ikJ!)P!iyM>eT3Y)J-9Ninw}GM3opZ8Aj;2HJwDF)I)u4|+WtHK8(;_5Qwh_WtO@nYVrTi}&~KlauYk zvtRy~hrCMyxxiR)OUNH0BMs9*p863+4GkRhPIlfyjqNvk`+H}}0gDAd(afRL>nLaLFE@&eJzV3!*D4_>q+Pg+JxCv}=@bHS;ZK`iO z$>ch|DSn?0ZliH1s>7%VlSJ)P{wXsB=Pon(=P~f{P48neg1e*q%YFP$JxrJU-;)2+ z_`mk+we?_YqrJ7U)n4*{KRW+64&%x1!2hjD{%?J2Yin(b`M;(7cgg=P`M)2L{~M#& zZ4^&fzM5W#10J=YONdr8Xq%WoV#Y*9Fc`&>A4AGjtJUxiCf6Iw!)(d_E$RO}{%`a3 z>-Oqu`_*c&{%Z4eYjtC}Wqxe_59sFikpV8?|L8mNf9;LdCX|Hz54>P|$^R|s|8o6* z=llO^>(yrPYIS{Mt+l-WFX=ygpX6yW`Zf{3eEPq(4y0ec|FqhhTSWht??21?|MLF7 zy#Mq4pD+93ZXc#MfTqx;_#G$m+bFp~6&(39$>g`}b`(9RACH-o8;nNLfE1;q+~7kN zrMvMU=K}fTl++11Z+r5{$+KBJl!^F#T@7s%U){xNE`L6T;}KVxJ`Pc1ZXm0D3`a2| zZZAy%F%3b6ETp|~nSze!VGvD?af>}ljWt>0juh_B;AjVY>p_KR7!A2Iqb>W9tf*_2 zoA(+f%gk~>C|M#NX0=)kmc;AIg$Zt=d>_6>X}#Z{gyX2+Z(xc32o=pTD0n`)3r47< zS#J=gj_z>F>D961Aymx{!YQs!y>S7(Fx-PQx`E9ar8Lj?fJY-}spi3F6ppWkA?XPM z+(RH2Y1;7)lL-(8?Q-1M`&M|8EJB#Ig)u^UC;N6 z$%MmUABu~)z_*TvplEn2f1wE&~1(_jCN`qIwMD*(i^vJdDg32X+RDqO+{1sRk)04F5OuHHGntC8d7hr_n9z zCi3K2uQ;Ej6Ql3@c$nW3+{fWVeH>2fqX^D31cCvDU*l>0X9ch(b_JBGdzQ|khGQXd zXGdvXZ#6vv>TM&K0gUC&y2U0nbN~Q5fT3D*K!hjtr>>2G!9SCDQa8%ur<{VHyKoeY z{s~N2oxsp=7Qz8R!6t)B!UBdRQY>JU+AvcZbEe||=cL#yyjEI?0DGC%ks{FIBf9mK zrb1ni$c`kA79z@RL|eGtDAKeI=^t(%^!%phpPp@>^?Y7doPI&3aX{33V0Ew23~pAU ztTEs75_Dt>0aD~MAhdxMgx3+fip85AG&}!o{&yR}&s4 z_{xG_@_CH5o0`KtXtk?0x z{_w`(Bg_h~9O-N#tXTb6=#Qf#eqG8^)%ZN6J};cA7f08+auyLBBM#bEtO#JqPsiFX-Z2Hpvu*d%zsTQw$1 z#DJM$4>)|2Iiys@^&;xfB28dqI#@(vXigY1;;cAbXxdF)Frx5U=9Qk=DV?(>bVONM z=bQ%lCtOfmk;a9|#6%+)hlF`o)GBv@22!~48JwPQB!$;vdCaD=s9aO6CpV3a!2TNH z6@#`F?lH*lGj1`fRX1lfRns`FP$J5J?Ei{WyUY(D+33L4KRAP%*WS_JQ@lT#%kFLQyraxvr z?_1+Ipr(G=KG>g2{;&NAvpXnNBNBnkj)&Dc9-IZfxOu?g6<)<7xD-a2#pvi+;xL}z zITlZ@6RW67ugeP!?s+01KC*%^4U%ru8^EAGH0&aIoR6>!?M^#$7-a(>@JME>iiGLl z7V`7~2bfkWI3}~i$Sy0AOU2n*GD+?7GTqVsL;r3to#DDEm;{*MEIKC3Popd+l}bYs zQ0(&;&VXOA0H4*O`^v1dj|QE7$MbKKEML)VF8zYH@X6@Y7b1%ynTC(ouoFmOe zjhruP?B_IW+@A(P(z2R36??Kp`xCaG>?`42rcLAgv(ILpI9=H4A>7FEx&w;|De*81 zQlOg2xDN^S#+M7OS%U0Ul3=yZev-nzgqkq4A#6cx>UQW~d=VIJ5CCn@?oE&*<-^t5 zuiEt^u*uNRKbQ8kCCIZjHXbIlqw(a30{UuP)TmG#jfS|7{lI7bp6=_Tfe?WWs4`YP z_eaUVzp#iuvsWdOef{E2jm;BeYWTrbMkK8wd|R$QUWH@ob12Atge zWFGady3Kw2We(3lOvOiv0?f>cA&5_p-kvcR%x5N+y$#c$tL*#jlU=*)Y?8rw;41y$ z@O1laPnOS|We$%{4z~AwV{(B6Se?sBK;qr=>p=%x&oOMjBprJpi?|gdG!FB@Ezd?= zDvF^FLO5@HWI=rsNvn=z9uRIzP42?2;7!hMrSjTuG-tOo%ItRBk{7!kKJD2P`3jsW zNkXXIdZ{o2_&xL1N}|6kZIBZma1bZ1>(eFR6g0ZMZse#R@bCS z$xYW6PmUUEsa-j`J{t`d532H{(8}Z480NsE_DQDGRUMy%_jsv%AC0DOWf`3h#etG+ zT~0+~epl{vo_%HIE=sSGOdlqn#$6u`2%~-uSY*tBIO6Wx5EzIe`4)!K^`i+rAc!W( z3ylBdaShCI4U)+u8su6cFdyMvn0EaSCwso#wRm6kL^b3ni(*gcePs3yocIbo`D)4e z;}rPKJmu$K$GG-;AA9>+g~4qS!-{r`_v6y2lN(R(<_QD+SX#b}uCS%$E9Z!muJ&rL zcbmwv#G;Wh3RxRR)e?;IT*Y#;8*%l}UvIXw~u1uGfj)+rjJwx`y{ zVYaR*fD;#Q%8EeEGL++>xB*xCI=-P>fUnI0YgGY{%32GmHq~3mMA2;B$BQ|Tmt+Wi z0k)mJU3uke?@1F9^!xwYu`7H<4pEv?LQ*viG4^v&uj3i@E)+Hha3W8Nu+t&RuMp7_ zfJ$6$X{(CrlJZFrJ$ZcLZ^ZsqkS~+C`}_caib@jdUU-cfOKQeQ@|7ME5_wWp$`k8F zz!zO-UIybF$>9asvw)7WVix9lD=_=>3Mnd&auWG;Bgkv-V0-Uyw|6q9zP1N*b4QBj zHyh7jvSobPY+37K!Sz0jNpOj6^1CWv4&21?)*Y&~11Mfaa+pIKqH1LeY};&IJO`lK z>>kXy7EfWW&G7Onp1jO%OSngpVi zaLgnVLUEvdF^)dN$&lpQJ*j8SU}DZ-lB}S>Wd#TNJry?luHC zv2y+_N01=k!WJ2%#A-?@I~SsWQvWi&dI(auphh99*aH#i^QpFyNdW566M|lAJj-VQ z*2jMI0MN_;i2a*1nN91Cx|M65nQM;nxTh{UPjG^~_ec<~qf^ywQ$IlQH4pAQLxTuB zZGa_GfZaWBh-wW;>Gc)}V0ss4uvxPR6-(i?5TZXxcQ3wTobSzXqOkH=qqJz!O&ShR zPkHo+EJvOuj|zjD9`J`qpFTw%>GE1+2p_D8Lqt_zcBOeW%kyMXaojy^elv4^EMWbH z8T#dEk*`7cFN??VC`{=sUQ7UZ3A`v;r@BOqjSP>q2K+r4ArQx*X794mmS^Oj&Xj`TIa;?(2Nu@;cI z_}C#4p5xHN)On{~J}XZCVVq4zVX>`5{o?$CAB#sK#D=A@$n@&bNP(j|00Ak;G4EtH zzKT*g4pD5u@#iizkv+&eg+A_aG(psxO?WqmUG9&MhQ+pI2z!WkyIm zzYA+h6f0+)BMB4W)<>vd^61%pi6z2Yh!hSH@JWfYZa!=(k%Fzp#MMxC-^Vf3-EXww zA)F;n`p zD$L>mdq^`+ajMXrZ}@RubSE_1bw%Ww_2!RWl!;46Yb)f}_$8H||M?w`)ihYd*`K8` zfTvzFj$N zN(0S9JPp^ikvB-jBi@b;xazOU`un3$XVC447Ah&RMv_+hZ_(pb0{rP7s(v7c)N$dU zR^gQ9*L#Tbs?H*#d`}uaaq;5e;mv-prD-v0W1UT+hbc4Ttcmd%$tAS=MX6NPV${22 zdn8n!^QGr2@sRWXvICi={r}SbU$_6?+S~|QuU@_0+E`uM|Nr3j|G;S^lW+F^x7h#R z=H|Mz|8K9aVf>f%wbt6w{(ouzzqJ4V5$*qB^|HtD6$Tk9ocx7X%6NYJ%?_}xSFkE@ zL1PK4vdrmC@;HAKHwq|N*yL}yW zeud`CkVESf{TPP7X^5}yhe^Iy1c?#u0BRhRhvxzJ5Pe$T^;}-^e@p()@c+E|I#}Oa zf4%W~eaZj**!*ANW#k)qzy~LBkdvFy+bmi-O_0^YSMGb%FSt)>QW!N3%|tPsIk_2! z*faVNlGv|kK4!;3q+E*+?1^+GH8eUXoC-Xvk62Ej6pwL$YCG;8K1{+pKoHb3;?Atj zi~io3`WUG4B<2DLgtl)PY=6~QMRzVQ3DsTFM1(FNEj!kkYe_%OZcq_4uk@@me<-Hc zq8Yt51geW`-xyH+GxYWa^$8nlaDKxvY2ob*t^lVTXL8}hby#apLFBDNHi0m|8ij*T zs33(u#cQ02t3||`uiFkl0&xq-Ew6{Ntm+8nNfetqv`3(Is_xG*9P{V76TPEa-)pLlF+6paVj%NoC}SmkC6yzy;BZhN z4xTIQX~#et*^LQGqw}J_k3cDBa3%?xaMsb8!1)G8RWS+N2+|@1jkmuI%FY2Ug0pRq z;)L|_{bzaq|G#wqUu$n|1sknbt@X9F<^BK1zW+-a_02&57QO$hx77WAb#)8le{Qa= zZ!Yiu%lrTG{{KVW|2ed#<{qNTDe;p-d&+2?6xTDeON(%yKQjGa@_$SI&xrrAxgM;y z*Eid(W&HOg|Hu5FMv%XX1)R_SwKq2O_#f-I|F_!hW&F=2|F`7-ez^CaJ(qaUezq{e zf&4Q|CUyW2;`*+_EZSU`Jm1ykI=gg6a|J-qFdg8!w=jkhT@*$~hE1W%nW|vj?9cO*j zV4-k|#Bx4XGv&oYOD7i+htPc;u@z{&hybyjDooNS9Nf}_eF?*`b7$WrG?MP*M1g*Fe2gIU0B zTj!zBDybr{86JumEms=-YZk*@MP+G-jXidrz=64sNreYueJgOw46&p+2UBA$fnSuF zkQa!eqs3&XQnf_U{$eK-L0N29j%&st+%#e)aCiyBK(;b`Ls2Z6+&!TbMQm|!ZAFQn zHBW#>EEmB@c0J25+X(1VRS2WHxbg^LEv9!q`6ULx;CqYkUy=nb;Vgso7(I9;x$f*r zsqok}0O|#T7e1z(F0)FNX)R>sXZYR<4D5T0PR<`fv|;FYmzU@M{`TR!?hX>Mv);); z_W^JG{>9~`-Mv`kU39JD_VIOkw!3#&8n(UOJN(Ta z+rrQG^)+yQ87#_(g1KCp1G(dYR@2GPRfYR=z5($D?kMu#h0{8|zIKs4|4a*|!^v?`x^mKQ~K!lR#n zC3;7G?jQ&Ml-=3>{4<=b(11^_(z7qpeFAxA$B+yaRnVnf2e$&%fWPxAIHT2lcBTq% zfdKCn^d;nX9Ab!iWlcpB15whS<=5yqv$94b5Li986Xu)G6xqPMqlJh<2Vw1`Kr&hz0@`)0 zTtJx6<4m6<%Pb<(E&;3%iwkEq>?TWdiMY(s~z!9^j zNpfGFiGtI;x1vw^FNU;d@ukIS1fVzJioj(qEpk_ErNMXt%i8@TK5$LwC5a`kULJmm zCg}V}I{mdU1S!7di9fINq>ULi?C6ggVwel^KlC+yssFLm|1kW&Y^??x>#M7;Hnx`f zA4~lY(*G#p-TW5%zZ)Ctt#;x6WgY#$Yyt)@^*@&SA4~m@A5H(`pdxS&zq9xIAuy(W zjMnQ*C0>+5nM%KU${s$aT-2NjB2QN7pwgp<@ko}9azMi(Igs9CM0U?o_+U?3GFNx) z(lkB0d{;FQ!&VLzJdD<*#h)BhoPBZ)VwMAr$U?J8oM+Eb)3)@kdHg%aA9^zM=>cBe zWh$#6fj=k&m+p= zi_y<=YgQ?hWR~POyrK;Ju-jn^QmqwAFiXi;!bLHeVwS^r#zh(YW#&s~@SKmotaU5J z($!Y6l&4`M?7=?FO*yHen7y51labJhs94Zr*HZ;*CW7dcBrGCKF|-tzv5PI~3I!NN zIZX5r8ZpLLCVU$WK4C8M8nF>_!4SHXyFm>Nn|K88k513}$J?i;XYWsrKD>Kxsj=`} z&PA^n*4UpUlgM|M8pk(j$Pss_sP5n&$$!`DAJfZ%vH^&aQf zRmrAz4JX=FIQZ1XC@)v>&~KF52t$mj{MJk;LGvKvvqIz*?taxop;Yf6VQ~-@a8a3^ z3XZOLR;fT2(SI*cO_>nw1sr6)F2>VU8@E05@7;NVQ5*s0A6~-f!CO z=AYpjQe!A7%Dd1!)LA#VD_EVf&V7Hn8~YU-1ov)T@q6YOP_TJ(&JoJ57eyUSXe{5H zhO|<3yIP}S^ce3F-zDqS1t=6RBCO3o{_M3|tLu#>-B7yz-!SY&MJt0@ngTK%*o{52 zq1sb+wJ}s88IDah9RaE#ep6(zJRUf8`swnu}fas0Io@K?tP;hdn)P?`uFi*0I zHI=6yd<_TFxDM+F-=^^ZaH*mSu#^;CD7n6_%ZO3_oWde_I)>w+U~qGa4$?5YT~yM- zpXu0fR@D7$mSO3YJXzsDGV0iaL&t$jW)(QqKh3Y>LK*g1%XlEZ*Gsv@gyqGj*h(^` zVIRDbt}3)BUtvu2usSO+*nQ5ZUyV8A1qOe58xJx;PVXkD#)Q&|uD{a8P#`np7V#&Z zoby^DWggKC-5D@&)zvKP`m^k6PEBj+2e;v55{+EEf;h$SrqK1T;>pmt<^iA?YIcYT z!6_0al9Th3^oF$db#YD5a>=HOt_OJaE4hxQRC%d;rvCf)BMqYem8gVFiKo2#@9Oms~gm@xl6+_0Ah3P z)j9=&!h4C2h&D~*ahN^|JbMl$7h@~&W6Uk(35u&HH+86?M_LB>l5!FD9Oe0ApJD}x zIQF)148^8Sqb~Z3Zp+FtS`Ss%g~;k8x{lz)8VGJfTFyu=2PMB~6(bW?1ea)xU~17Lj^zjf2`qPJnJ2oM!!=Ow(jg{DflpN9}8*BB~QZaL8o}k*}vwn2y&Wh;}ZE{7czM zmF?PSuI<|M%+j=}$pSL1-f+rBMIqv$trEJVyQ|H(&UG~2zaKqJQRPD-3h91G(=>s! z@+xfH3n;HFa?|aRgvH$9(dpSX#si1roN8G#(^2K*!{OoH;XA03&L$Hww^>x>&HmBO z-+H@H1>S!Rd$7NboBZ+`p3|QT)6NJfV{s$YiLC2tXcAN%@i9T_ zg9(JCrb|bGLB}msOc)+B?G@OHEuOb7tb@9sv0Wd8;mLhb$P1U00yKhBUE~W&a#sB4)CAoeG-6iD}#b2*PicPtKf{?&x%xvuxTd0VjDQ>s*zPR5&vx%W{zTs z<`_Ai6c&IKjZkfr%oCNHER@qt{>&Y8ZSJ0Io1%o*8{WTly|xLypS+g0f^ExK;!SU* z%_)sy2RbXhDK2AwnH(%^RZ6?0W}X&gcjxM0>LbQ2}9)4C3iVqlHm6zQ%d*1_J^ zW+bo=Z;QU8&U4YxpdbYSD}WwPOs(yM@F5=0#xhFlT{xPt#)M!t;J?4cZ_FSr8mbE* zLQg`x)F=;uMcfNVfRSx85!zN8!4tavC}ilWXA99vW|yY~dMFuBv%Aaal1EnLXcyEscy zb37liSvVR2k^yt)ZSNfKnHUk@Ou`Y?;6Wdq2Jk-xhKC%y0%H|)B@h%A^f0Ged|cAU z`F{Ik*J!x}Y^4~6>S(ezZJ=jG1pC=2G*2EF-)urJKDa%k0t2B5i8ul5C>Wa*GdEDWh0B(te7om||IAkG^xPi(&bHF7j z(z=ExYLw26BlbjDT>`g;-A(BXJ3V7B6PA_)k9|RP;V8wbirD6^xC_0V9R1RN zce1_Hd;4MEs>n+@ziO#VLubQW04wq^=XKTGYzrGLwltS*TK?Ay(s~B_xr(g5u&9+c zp22Pc;t>MppQk>ZBq9nhmuP%>QE_glG4mH0X4)}jVW6)FWO>XVk(uB@U%&V;DSQTG z=6E~k6P~_(@n1CNy4H~3o_ObsZA}GShp~@wuMmB{Mb9gB^1sp*V?XD=7v||1jja9% z%bE&l7W5~m$dkJJP0w0;OY6riU3moTyH7iO#k0^H=1QI{j?)Cca|8Cd0-R1ZpMlqb zD+clVK#)88dUhp^vS=Q_wA(m(S#fY9JIVBM8fLjT;|j6ipi{GIhl+6@kE3A>JRO`t z^N(7q1%AvzM+mnOAE!J6)bY+ya5{lb)Pv|f9awPE6#|4X9g?bg7KuhqPS0S>lZc$i zunlM|B*4E$8NZStqR<6dXLgcY=$z;BSPbb5#LGIJjiUt4>;XyNkm=!ZYO_^M&6)Kx zkPg@J_rf_H6`qZ9v~2w+BVL&~6ZWsEZlU|;5t2jHDr1#*xG{{>YBy;I^Af>^9^-NX z0}99^A+GsNfyQ$TsDsxN|1)uLN@1L9?|vfO4k2DJN_M9d_KXKpe)C^3?dAJWKi zDwF8mik($0+*g+xL5=0HW=ZCSs6x98!7bYqu8>)`5R9^2tm9{stkkA^?nRld*JckCtc6D6oz~NKCUmx~K%iRuozBC&QVIJ~luX+dje(FHsD_C_(9VH39qlZLubI?fAU6^SvXwX- z0MRvb67o6@d%aM{5Z2JtHc3s3a>#~U!l{3|1aRhFt?**NnwEd=dacEHsbk@+p2&@9%x=&A%f)Zvk|nudZxl z_^+&hb_sh*W71o6I1QQWI7xaGfeEef?!2gWn^c)I2cjQgzp*T5{v^I0uufN(Rpx)y zpnMWm>yLt&I1Mx9fyTRwLl)mQi4Vl%!k^!kWEGhelv_hJ2y-AQY~Vj*RgfY2mYrKY zKe!ep6P>&U^S16U0tDt9%@&IZHs|Aqn--e@_^r7&hDH_B_GF$+dueOxx>#S&lyM{9 zfgj6MW7>t~>v%CGKj!%z=+A~E4ZMo49`opXF+<{6@++Aku5EHAbyM%%W{bosK7}t5 zb9b^tPwCmg90{;KojZD=&SU?NnO|ayxIK$6dhsm2NHpF_S+2!I5Ma8o+TTHZD|n8F;htl=RyhjlwDp=`4jA0VBYdSm z9pMLbh*`h(Uoy;J3T5G!IJ%cSn)AP+nZ=9G{Oik$i?YK#YVo{vf!h&C7AiY7$QF`% zB58!_g+I*maB$n_-fW96PVHEp51a=ICK6e+Av%G( z%cKU^LVs?hT0A?WmPit{0E0@E5CZ7v9;&HWF-3iqtH=X0hj<-t8iZ%H-FD~0M^@hfF)H+QpC$@hw{XDi!0Y?1*go87#6x3uxRt858r$6oP>ShYiVw>T(>y z=>Yy?Z9+bcs?4tX~9*fU^#OQp5$Vkp1$|6DHSq?Xe`WY z5MRdwYP!6wxIR`eASN|k9DYpN zL(=lAm_xylstTsU{7HOso6Ag`lu!j5Mo8B*noz}a>lF8?kGRjWG877B1x%{#LHr7~ z`YG?h`jam%&x-6&4<#|@u8j@_|9*6`+wUFjocwZp*4t%mECF>}AIlPQBPz(Xu4DHF zidSAOrI1(YtjR;m@laObQp#{vs)<>Q!)VT=p;~|MaC_%$?_-Zm4#lx)&DLRe232>V z!+QC~jP!8M@%drG9JBl6{K-2z+CB3AdV@X)s42M24Z;y~A`4UoNkiRz(9cA#a1Q_A z{@<7JAC~bS^!N|0t+in5)z)j26E348EaN|5{0HI1`)k8LEQtTmZmq$05&xmp-dM%> z538%KW&DR_{D)=yhaWBeL&@=e8sX{;g*&Lslf;NTaEZ7Asffi8O=e>mYv43bd+?Jp zP$vQyUYUmhc10M2>EjT<4)YLMZ^A4(V9(sWhdd3NsLd4*$+f#9GD1MIJQYMi$~~n+ zF%B+3?bTJwg)=osf}SHPiW&fWQNdUkYxIRhZb$(U0Qw*Rqr@PU%Y>=(n=r*J0Rdb8Kyx&~}>9@71{ z4PxP_TyqMCKE;cl!drNefL_Y!7nA z%>q2d)7my%pSVb&X~xK`9y?q!7aIWI3?05gC>JH};(5;@g@fGeG0UT|l_zKHcJ1w+ zyC@4l6b@ob8&!={_(4Xr#={E zO}SO&y9!FtihXqWs=SYTw7w`_z_z6qDihd0z?GfvnfmtGl#u_kLpasLuYtM1^zsh1KZt%@jNVqcQk=A z2mwXP5L9tM2#SP7^yEuzWE|p`AgXYy3a;1^hNaeGa@2GOgEE2-w|wpw_H-Be+E6oO z3=Lmoyb@a$ghj!NTtAGxCwGQ zTemZ6s|WdOq~OmVzxMcuV>JQvUbd|NqhC|L+S=t%Clb`FwaI^9nRr^9;u4|94XoT89Fz`K%6LEbH#_=o;)`7AkkE0 zHj9TUIx>7;e`@S#5g@rL#u;}nONk&$A5%W1HjN-Wy*?iLq zINY?PT{4VwRjlZy-gi?98nrOe&iK*K2-b{3%d2=4=P}$@T=8f)6pirmH_%EK!4n)p zEL@pB%T&vPFHOp5%EsIxwZ0}DS80VDT_qJ_aFmy@u$aXAeQuHjVVG42`46F$=S1R} z;4_UDg$D`3lOq_A1%ixUAbaMx+ea90L>N-z8tT>!!(>2??(S3A{r~1|5Aqoh2QHO) z2l1Q04BcZcge}ChWSFr9&aQ-#onpAse%Pt2PqQtMUf<)QfGjXaP|(i z-}O%W$45u|9Tr+Q7l#r99LLPns$}e6k@3iV4kM=(tsQOaw@}ve7Y_%c4{z@|3 zT2QF&?;ITWwM-!$(7P;`*K_?wWwfJN8oQj0FAQ}gK}zRE;h(z{`3Re)J|x0vp?yA_ z>;=yYdE{t>AC?_jy-(@1q~;H`00j6i#xTIhYq0lTvQ){R6Qf9N&uJt=WA(nZCY6}<~L<-xdRFHfk7ZsQtjXsWDFRz zj_I7Eu)U!}S@YFlc-oMTHgrzqB{cjJS%CAuQWVA)tki&xHUP3U9dOXr`Gq0-hEzOX zAIQQo9F6Ke>q#_9VsLy$A-heUj!#Z>D4bwfzKngz_<@CV_qccRcD>bh8Yh0Pc6!Ae zkKZXqAW|CD4z9#3xDM`7chN6%OdyMwl+3ZFI*&DfQE@%LX*mn+6?;jAB8R!ELXD%m z)LIaCZMj9Nz2F?H9p9=rp8?OQR{Tg2(#|NTJ&tN9BpdB|D)fBEVMvBUf zn0&b*k>hSitnTMxAhP48)~0OZi%D5^&c7h8`XagrtZ`o;8&afzO}ZX5)s28{Np)&F zO{41=@y3NM#VLQQ%3b@P`TLjoxKxmaaGF&*1TqQyZfOM7j)DY?jl$&<06SNHgw((> z>m_d7dV_G@+`sBZRZ&}bBdV+~fn8A@e^*zQ(W%{aMee-n@?jV53UzlQnE&#xP?G95 zN++PW1zJP6Rn;lCdI;*ySk(Y!&aW?tp9t>fq>I?PHF)hTEY~d6&^agylBD9gNz0|5 zKi!Av4P3moCyz$BL-&qe_96mV2!`b`x1 zb_Q3w%x06c{XE-^SOOAjJR;YKa^@OFbt_Vd$#Nx6vJUC&MCqYi3cqhC5ivWVW|Sbt7^RT< z{Cn>}s=!7=nOq*LB_q;}It^7Syg$ekyOpx+No$4$COBjK7Uw|uk!OJBkmk-XY=q@a zpBps=En0(x23Mg1XMnGy+;wTU%}uz#C$zOrS&M-kzF-pbBxJD68WxykH(RKBm2gk0 zz(_OY%+k>$WPo|RmE!GKO0S9=S}{XiHLWx`Q;UryayIdCD6+|siB*whG+hYmDkDa$ zL*A_icUcJSU8r2CRc8)eC%P0aq-(1-O48l1f=87&`@=iqT6?j#s#G{I#JU^9lsglW!Zb_CGwG1Utu?5PQLF-cNEMPy z6hNAjSGt*5f65BL3c6x*QaZD&n(*;y-AVzdyI+y}gpPG7W>wE`X7OlPEQ)oqlqW5; zpcuYFH`%GsCGTPWXL=i|H@*b_8YK6ter>TUYpuS~lMRPHjur~(Z!dMHo2ssCvV8MK zcC!m)x2^*=z|`QMNjxELRMu`dF8LD4y2_W$lQ8Y01KwVob^deW$&EqNb8P-Xy$(U+ zRtBUE$!ChwXI)$pfZ0yLFqn=~4fKT+w<#ia4n_&PBg7s6O(qEAn0?{=iP{`0%Z@}k zHNoI`kl!H?Ia_e!n;Z71ipj36TrQUiuT=p#QffS5k6LtHvJRE7)S$?BCjmw`{EF7u z;jKoYw8)tb`XqBIeDW%vgoRfyx64K8j;<@Fh2P!Fz@(|G_A3$$cS*KVQ7u-ub7WZs zE8cdCJuZ_Lt#(PMq&$WiLL=+uYWi|?-db_f+E-Kb7elwtrv%*I)4SC9ol%l}noZw4 z;!7_J#=h1EHu@FSC&Yl?3qtGOPxROR|G88>9iY-G$zu!i=wM2#K@@ zBH<0dvds<*5I@Bh=L46nPbZ)K*{QQJQ^0oOM}g_;rotgG<=NEeMRG)YZ2|8P@EO2i z2PScZgo#~1z#Kwz*5UppU-O6a4(C3KN{@MqJy;ivcSQduDw?wofE7N?Q5=8l!Z_Ie zdLsxVp7S87m7z2P1)16Fz>d;OwW@=2GFe8v*n%7>KRrd=VAFp(JQ2&g}q z!dE#TfkY7tFYGOyhtPZ&H=W2iX}!BM&3mSH+TiDvd<3pmmaYqVv*0zPS$F~=T<>vK zC(YBZ!UO+sb`*;oZp!fy4M3dI-4(CuR>=PFk+JJJfyj9eG^zfGPD^@m5O@{+@NVsa zl`FtJT*nI3>J~5bg$Q-PF>+%tAv7Qq& zRNgLo)lf36_m~4~Dn1jG^UfjZzEzCvJSw#PDy$1u#r|8d_`~~O>bei9-`C|~;RkdG zVS_TV*^QFZCm@$TYX5iZ8rY%A3(~j_BY!QVW?% zTFOtC+sg(G)T2{RwBEeZAgCPW#+zapzZjWVa|E4Qf!S-){|fn)rvwPv`|h2)=d%gE zbj@zXCC{n~&hlE@Z~Zt16MBOt*y__Ocdpq*lPsj6NY=1to-Ngsu?-qo*IK#W(`k){ zPo(6XQqf0VYwLFKtfqbQs_ju%0dI4XvB&4oBmrYkhe}Sj#v4-e-!J7y3SaENe1TV3 z#ZE0+^X70nG*xWXdFbofLtB9BFpfykaCAdj;5I+Q-awUh%;jKq~mDsh_dpkvrZAXr0po0W!;%mtTBsKuG)N`1Zm)wFC z>?p!H_#WUm3h0m|2oNNR+9~TCIg2qr1df8U0f>*c_y+LrXaU5H0q+*Mucp7c0C};o z2(f)QGoPx^is{Jwf+N`}?E@1zGO!e05@fvHqK{ zwu;87CYoI$+rQ7ESq9`pbzdak+1=SLuVWfh+_6|>Q4Qu&_9{)uO=vbd9HE$L@+{BP zoxcEs?%}EzS!ooXpOrb3J1B(d8fYZrq{e)nxNG*+!dH-tX{e{ zxKS1J+FYI@AUM67o@To}?o(vYsDh>hdpuJ0@AOs#*^q9!uX){9cD-05=-e>t?^<%Q z8uq!XMR_5se|akLC`iR-p)zdG=&d;hq%n}-)#R0L{gAmO$LZDul`bE0q^?E?a5CUxhAe?w{m7oF90#CA)(9UFrFMO_7D z-;HsNTgO2oO*{?N=_dx|kT~1p@Up>h0gW;_`X`l(5=we}Q_i|2cCwTy!8h$!`ZaHI zGZo)<9gw*R4vFTqp4YQPe&3tRcV{ycx0B=I!`G+<*SE)pA1sf4oj=isDgb%sR_uv?UQHes zx#0CB`N^6ls^5LK#cyWf$|E)3`8hIx+R#?I=l_n*z?D1z(u?tI zg4;GNp*+2O{>%>63(6h0YybiUry;xFOznrUIgj@1q8LokuPwP$dgliaN=i*OBBH@T4W75d3Nw~F2d__!vS)Ph~?S8 z2pz&x->Xgc1@eS(lOny@Mzxj9-L9sLwLBk1mO(@Pc@R{JcXt@=*$liHSGWHc;|p6* z+r7-K^)5#eS6$A$54I+DBg&9g)))Vgtdi-OHYjy;6L<8Y`-mxcR~ySx1hy>$RdwETl+Fm|v)s5-|G#dTB`8_&buaOihH@UOAx4S)gbuQa&E;Nk!8@ zxrfPoVHV3W{hC=z8_t=K(q|s+OfDI>wzuU}c2{XWkjn?|d}OFMy-H>Zjo47gjFlE} zM{zw<(asc?zhU%N#1ZN+i{ieXc)0k0e{-^wR_g<$ox9iAbw6-7vnu7ic%QGyQ#0>^ z9WTGI+Hqb0!{e;zJQc%3Jo!j#6ukh~MFZI%YG@Lsx9}&sdZUdCI#?b-D zC#rP-1ATk8{LvDJz$bW%#ScIpEJY&D?Mwkfhotr%;KGlHWc|!dKr5#Tg-3BSN{Xc$ z6HZ3-+~()GH#o|deIp+2?mq~Y(|<2+_d)w^43sdmTJBp{+KkqDSe(R%LH)gc*y@pc zb3Eql?Sx%3eaqdqv!0$vbn$5u+~Ic$Cj*{QwA>UV^6}_XOY_&I&D_pf59J>0?|a7o zB^LNa$H+@_~}X{jBuw&u`&S{bEySgUIhju2>(I^qW8#igiQQIZ5^;u+b&l8 z3_65;?u-SN`Y#xIzoQT)Dm~T)fp;rIZ^auMWBSFi8 z@LJx@?fNCE$ z;Bh2tcE+fGi@9-*Nd8b_q1Lm(W{jN_pxFHk!uMR*L+o2(<{4L8rfn&GiHwY;tIRhQMI~OzL07*ub^0SNQ?;zDy-2OdN z_!$;$!at=g@{#r4%(E|DgsS%Y_%m%6`eb+0TTmw%vX*m+m8&I#{%7Ae%0e53)4|zhvNp%Lm@AO;;zo=DuS!|g~;n>Ck zq24Y0%WnFf4S-*Tqa_-8!%rs~Wi!R2Z_#T?4W^DwyHJUFcr%^}8MvDL@R*}A?l9<6 zf82BeSL`ch5F!IP48%NI(xG`hYb=jQ6J|6Iyl=%I|03%ng_F^+cF7@lHIsqNd{-2v z%(>C>X-zWQf=YA0#Iw=w+}5rb_H9je?Fcv7K)<4Ub!?Ej$w~0p_%+stuTVig(0#jeUD*%Q=uEvYR;X_vqk{0ppon<3J9|T|V_xNpi#ZXLUxp zf@FDk={R5EH(GJ2kt#mhpwyM0cfgvH>k0bS?G75#$A`@UJdF3ABL)Yj@87nn&hScd zw0T4>8<&%0%#l{zfk-K2Ofi@0+!_%?j;1;gUzt^K9EBbRBpDGkq9exi1i9#3qB_Kr7WQ8cksI*MD zub<7e{dM9Wb+=tMxsE$`hdly{bZGUb5;Xi&=+r<>U~Oc)i%fJ5ZfF}vH)q3a$=t%e z^>GbKt%Ilg98MiCweg%KT}a#$C=$HXSx)%3{Z2UOeQvzIe;5Bs(k))n4K!4;5raHF zS0gQT=OOyqwXk_WnJ}yL z*Nu>Ttk@P*BBbDv4;U|QTpSE;v7y(5c9zBcS<_6F zT*P-^+bodD^FIl#nQMyW96uGgKuP2=`AL8~DLlm%{XnrPkK0Ka-~5mtxW5G=32N5! z2oZB^?zT70mbO17pSc)WqVBEuFM&;}b0K}I+nu^IO)vk`|3hD+I_~hZsc#J1WMnJ# zOZcD}J90^$+dB+y6~mD;FJ6B;_4F8<=?; zo%L(BQtCt|rU~c5F1PJS(4pvI^(@i-{*+;Ipcqj(UBD9oAv(zgC>IE_FX$MrqKEXs zhR~-n2Tr_Z3yfd1(&V8F*N$mp4wxq%M6Q==;w4se0kGCl8#57z0^ z)d(X>g!etxyV|@;1-sCQQ|N{np)k+#SFT%9hUmStzp6Tk>-EPpk$HU!N~dR{jr!G$ zOg5y946QTp)U#X-{<4w*;^4#!O{;WXN_n9!=H$iTM;RN3$9@`=G)^j-op$_|=eHM! zBqCV5FYncLx;Yq3^CY$cbuR>2(9P1G_@!?1G1*Rtn4 zA6+P9T_POYT-B;m1McqWY4B&j3{T)k=@4w>N5+m>cqg55C&<>vkDT@ccge20Qt&>Y zp%&O-B{z8c?YSZf`nGF|^`g4E>1$5t?D)h77W$2-Up`jt1h{Hj e#FeHu+)k{a`DOpd(mTHikg;5o6eL?AC;K0Ss!YNF diff --git a/packaging/build/docs/Makefile b/packaging/build/docs/Makefile deleted file mode 100644 index d0c3cbf..0000000 --- a/packaging/build/docs/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = source -BUILDDIR = build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/packaging/build/docs/make.bat b/packaging/build/docs/make.bat deleted file mode 100644 index 747ffb7..0000000 --- a/packaging/build/docs/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=source -set BUILDDIR=build - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.https://www.sphinx-doc.org/ - exit /b 1 -) - -if "%1" == "" goto help - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/packaging/build/docs/source/_templates/versioning.html b/packaging/build/docs/source/_templates/versioning.html deleted file mode 100644 index 318bd87..0000000 --- a/packaging/build/docs/source/_templates/versioning.html +++ /dev/null @@ -1,8 +0,0 @@ -{% if versions %} -

{{ _('Версии') }}

-
-{% endif %} diff --git a/packaging/build/docs/source/conf.py b/packaging/build/docs/source/conf.py deleted file mode 100644 index d8738f3..0000000 --- a/packaging/build/docs/source/conf.py +++ /dev/null @@ -1,33 +0,0 @@ -# Add /mnt/build/compute-0.1.0.dev1 to path for autodoc Sphinx extension -import os -import sys -sys.path.insert(0, os.path.abspath('/mnt/build/compute-0.1.0.dev1')) - -# Project information -project = 'Compute' -copyright = '2023, Compute Authors' -author = 'Compute Authors' -release = '0.1.0' - -# Sphinx general settings -extensions = [ - 'sphinx.ext.autodoc', - 'sphinx_multiversion', -] -templates_path = ['_templates'] -exclude_patterns = [] -language = 'en' - -# HTML output settings -html_theme = 'alabaster' -html_static_path = ['_static'] -html_sidebars = { - '**': [ - 'about.html', - 'navigation.html', - 'relations.html', - 'searchbox.html', - 'donate.html', - 'versioning.html', - ] -} diff --git a/packaging/build/docs/source/index.rst b/packaging/build/docs/source/index.rst deleted file mode 100644 index 81222c2..0000000 --- a/packaging/build/docs/source/index.rst +++ /dev/null @@ -1,16 +0,0 @@ -Compute -======= - -Compute instances management library. - -.. toctree:: - :maxdepth: 1 - - pyapi/index - -Indices and tables ------------------- - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/packaging/build/docs/source/pyapi/exceptions.rst b/packaging/build/docs/source/pyapi/exceptions.rst deleted file mode 100644 index 3912721..0000000 --- a/packaging/build/docs/source/pyapi/exceptions.rst +++ /dev/null @@ -1,5 +0,0 @@ -``exceptions`` -============== - -.. automodule:: compute.exceptions - :members: diff --git a/packaging/build/docs/source/pyapi/index.rst b/packaging/build/docs/source/pyapi/index.rst deleted file mode 100644 index e0cebb8..0000000 --- a/packaging/build/docs/source/pyapi/index.rst +++ /dev/null @@ -1,49 +0,0 @@ -Python API -========== - -The API allows you to perform actions on instances programmatically. Below is -an example of changing parameters and launching the `myinstance` instance. - -.. code-block:: python - - import logging - - from compute import Session - - logging.basicConfig(level=logging.DEBUG) - - with Session() as session: - instance = session.get_instance('myinstance') - instance.set_vcpus(4) - instance.start() - instance.set_autostart(enabled=True) - - -:class:`Session` context manager provides an abstraction over :class:`libvirt.virConnect` -and returns objects of other classes of the present library. - -Entity representation ---------------------- - -Entities such as a compute-instance are represented as classes. These classes directly -call libvirt methods to perform operations on the hypervisor. An example class is -:class:`Volume`. - -The configuration files of various libvirt objects in `compute` are described by special -dataclasses. The dataclass stores object parameters in its properties and can return an -XML config for libvirt using the ``to_xml()`` method. For example :class:`VolumeConfig`. - -`Pydantic `_ models are used to validate input data. -For example :class:`VolumeSchema`. - -Modules documentation ---------------------- - -.. toctree:: - :maxdepth: 4 - - session - instance/index - storage/index - utils - exceptions diff --git a/packaging/build/docs/source/pyapi/instance/guest_agent.rst b/packaging/build/docs/source/pyapi/instance/guest_agent.rst deleted file mode 100644 index 1305140..0000000 --- a/packaging/build/docs/source/pyapi/instance/guest_agent.rst +++ /dev/null @@ -1,6 +0,0 @@ -``guest_agent`` -=============== - -.. automodule:: compute.instance.guest_agent - :members: - :special-members: __init__ diff --git a/packaging/build/docs/source/pyapi/instance/index.rst b/packaging/build/docs/source/pyapi/instance/index.rst deleted file mode 100644 index 659ffc2..0000000 --- a/packaging/build/docs/source/pyapi/instance/index.rst +++ /dev/null @@ -1,10 +0,0 @@ -``instance`` -============ - -.. toctree:: - :maxdepth: 1 - :caption: Contents: - - instance - guest_agent - schemas diff --git a/packaging/build/docs/source/pyapi/instance/instance.rst b/packaging/build/docs/source/pyapi/instance/instance.rst deleted file mode 100644 index 3c58f1f..0000000 --- a/packaging/build/docs/source/pyapi/instance/instance.rst +++ /dev/null @@ -1,6 +0,0 @@ -``instance`` -============ - -.. automodule:: compute.instance.instance - :members: - :special-members: __init__ diff --git a/packaging/build/docs/source/pyapi/instance/schemas.rst b/packaging/build/docs/source/pyapi/instance/schemas.rst deleted file mode 100644 index 7dacabf..0000000 --- a/packaging/build/docs/source/pyapi/instance/schemas.rst +++ /dev/null @@ -1,5 +0,0 @@ -``schemas`` -=========== - -.. automodule:: compute.instance.schemas - :members: diff --git a/packaging/build/docs/source/pyapi/session.rst b/packaging/build/docs/source/pyapi/session.rst deleted file mode 100644 index 2dec16e..0000000 --- a/packaging/build/docs/source/pyapi/session.rst +++ /dev/null @@ -1,6 +0,0 @@ -``session`` -=========== - -.. automodule:: compute.session - :members: - :special-members: __init__ diff --git a/packaging/build/docs/source/pyapi/storage/index.rst b/packaging/build/docs/source/pyapi/storage/index.rst deleted file mode 100644 index e9ea734..0000000 --- a/packaging/build/docs/source/pyapi/storage/index.rst +++ /dev/null @@ -1,9 +0,0 @@ -``storage`` -============ - -.. toctree:: - :maxdepth: 1 - :caption: Contents: - - pool - volume diff --git a/packaging/build/docs/source/pyapi/storage/pool.rst b/packaging/build/docs/source/pyapi/storage/pool.rst deleted file mode 100644 index 398124e..0000000 --- a/packaging/build/docs/source/pyapi/storage/pool.rst +++ /dev/null @@ -1,6 +0,0 @@ -``pool`` -======== - -.. automodule:: compute.storage.pool - :members: - :special-members: __init__ diff --git a/packaging/build/docs/source/pyapi/storage/volume.rst b/packaging/build/docs/source/pyapi/storage/volume.rst deleted file mode 100644 index e1ba8d0..0000000 --- a/packaging/build/docs/source/pyapi/storage/volume.rst +++ /dev/null @@ -1,6 +0,0 @@ -``volume`` -========== - -.. automodule:: compute.storage.volume - :members: - :special-members: __init__ diff --git a/packaging/build/docs/source/pyapi/utils.rst b/packaging/build/docs/source/pyapi/utils.rst deleted file mode 100644 index b5ab60a..0000000 --- a/packaging/build/docs/source/pyapi/utils.rst +++ /dev/null @@ -1,14 +0,0 @@ -``utils`` -========= - -``utils.units`` ---------------- - -.. automodule:: compute.utils.units - :members: - -``utils.ids`` -------------- - -.. automodule:: compute.utils.ids - :members: