├── .github └── workflows │ └── lockdown.yml ├── .gitignore ├── .gitlab-ci.yml ├── CONTRIBUTING.md ├── COPYING ├── Cargo.toml ├── README.md ├── ci ├── buildenv │ ├── almalinux-9.sh │ ├── alpine-320.sh │ ├── alpine-edge.sh │ ├── centos-stream-9.sh │ ├── debian-12-cross-aarch64.sh │ ├── debian-12-cross-armv6l.sh │ ├── debian-12-cross-armv7l.sh │ ├── debian-12-cross-i686.sh │ ├── debian-12-cross-mips64el.sh │ ├── debian-12-cross-mipsel.sh │ ├── debian-12-cross-ppc64le.sh │ ├── debian-12-cross-s390x.sh │ ├── debian-12.sh │ ├── debian-sid.sh │ ├── fedora-40.sh │ ├── fedora-41.sh │ ├── fedora-rawhide.sh │ ├── opensuse-leap-15.sh │ ├── opensuse-tumbleweed.sh │ ├── ubuntu-2204.sh │ └── ubuntu-2404.sh ├── cirrus │ ├── build.yml │ ├── freebsd-13.vars │ ├── freebsd-14.vars │ └── macos-14.vars ├── containers │ ├── almalinux-9.Dockerfile │ ├── alpine-320.Dockerfile │ ├── alpine-edge.Dockerfile │ ├── centos-stream-9.Dockerfile │ ├── debian-12-cross-aarch64.Dockerfile │ ├── debian-12-cross-armv6l.Dockerfile │ ├── debian-12-cross-armv7l.Dockerfile │ ├── debian-12-cross-i686.Dockerfile │ ├── debian-12-cross-mips64el.Dockerfile │ ├── debian-12-cross-mipsel.Dockerfile │ ├── debian-12-cross-ppc64le.Dockerfile │ ├── debian-12-cross-s390x.Dockerfile │ ├── debian-12.Dockerfile │ ├── debian-sid.Dockerfile │ ├── fedora-40.Dockerfile │ ├── fedora-41.Dockerfile │ ├── fedora-rawhide.Dockerfile │ ├── opensuse-leap-15.Dockerfile │ ├── opensuse-tumbleweed.Dockerfile │ ├── ubuntu-2204.Dockerfile │ └── ubuntu-2404.Dockerfile ├── gitlab.yml ├── gitlab │ ├── build-templates.yml │ ├── builds.yml │ ├── container-templates.yml │ ├── containers.yml │ └── sanity-checks.yml ├── lcitool │ └── projects │ │ └── libvirt-rust.yml └── manifest.yml ├── examples ├── auth.rs ├── console-read.rs ├── guest_agent.rs ├── hello.rs ├── migrate.rs └── suspend.rs ├── src ├── connect.rs ├── domain.rs ├── domain_snapshot.rs ├── enumutil.rs ├── error.rs ├── interface.rs ├── lib.rs ├── network.rs ├── nodedev.rs ├── nwfilter.rs ├── secret.rs ├── storage_pool.rs ├── storage_vol.rs ├── stream.rs ├── typedparams.rs └── util.rs ├── tests ├── api.rs ├── common │ └── mod.rs ├── connect.rs ├── domain.rs ├── integration_qemu.rs ├── interface.rs ├── libvirtd.conf ├── libvirtd.sasl ├── network.rs ├── storage_pool.rs └── stream.rs ├── tools └── api_tests.py └── virt-sys ├── Cargo.toml ├── bindgen └── bindings.rs ├── build.rs ├── src └── lib.rs └── wrapper.h /.github/workflows/lockdown.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Configuration for Repo Lockdown - https://github.com/dessant/repo-lockdown 3 | 4 | name: 'Repo Lockdown' 5 | 6 | on: 7 | issues: 8 | types: opened 9 | pull_request_target: 10 | types: opened 11 | 12 | permissions: 13 | pull-requests: write 14 | issues: write 15 | 16 | jobs: 17 | action: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: dessant/repo-lockdown@v2 21 | with: 22 | issue-comment: | 23 | Thank you for your interest in the libvirt project. 24 | 25 | Since this repository is a read-only mirror of the project's master 26 | repostory hosted on GitLab, issues opened here are not processed. 27 | 28 | We kindly request that new issues are reported to 29 | 30 | https://gitlab.com/libvirt/libvirt-rust/-/issues/new 31 | 32 | Thank you for your time and understanding. 33 | lock-issue: true 34 | close-issue: true 35 | pr-comment: | 36 | Thank you for your interest in the libvirt project. 37 | 38 | Since this repository is a read-only mirror of the project's master 39 | repostory hosted on GitLab, merge requests opened here are not 40 | processed. 41 | 42 | We kindly request that contributors fork the project at 43 | 44 | https://gitlab.com/libvirt/libvirt-rust/ 45 | 46 | push changes to the fork, and then open a new merge request at 47 | 48 | https://gitlab.com/libvirt/libvirt-rust/-/merge_requests/new 49 | 50 | Thank you for your time and understanding. 51 | lock-pr: true 52 | close-pr: true 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | 4 | .idea/ 5 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | 2 | stages: 3 | - containers 4 | - builds 5 | - sanity_checks 6 | 7 | .native_git_build_job: 8 | extends: 9 | - .gitlab_native_build_job 10 | script: 11 | - export MAKEFLAGS="-j$(getconf _NPROCESSORS_ONLN)" 12 | - export SCRATCH_DIR="/tmp/scratch" 13 | - export VROOT="$SCRATCH_DIR/vroot" 14 | - export LIBDIR="$VROOT/lib" 15 | - export LD_LIBRARY_PATH="$LIBDIR" 16 | - export PATH="$VROOT/bin:$PATH" 17 | - export PKG_CONFIG_PATH="$LIBDIR/pkgconfig" 18 | - export RUSTFLAGS="-D warnings" 19 | - export RUSTDOCFLAGS="-D warnings" 20 | - pushd "$PWD" 21 | - mkdir -p "$SCRATCH_DIR" 22 | - cd "$SCRATCH_DIR" 23 | - git clone --depth 1 https://gitlab.com/libvirt/libvirt.git 24 | - cd libvirt 25 | - meson build -Ddriver_libvirtd=disabled "--prefix=$VROOT" "--libdir=$LIBDIR" 26 | - ninja -C build install 27 | - popd 28 | - cargo test --verbose 29 | - cargo test --verbose --features ${LIBVIRT_RUST_TEST_FEATURES:-qemu} 30 | - cargo test --verbose --manifest-path=virt-sys/Cargo.toml 31 | - cargo test --doc --verbose --features qemu 32 | - cargo test --doc --verbose --manifest-path=virt-sys/Cargo.toml 33 | - cargo doc 34 | - cargo doc --features qemu 35 | 36 | .native_build_job: 37 | extends: 38 | - .gitlab_native_build_job 39 | script: 40 | - export RUSTFLAGS="-D warnings" 41 | - export RUSTDOCFLAGS="-D warnings" 42 | - cargo test --verbose --features ${LIBVIRT_RUST_TEST_FEATURES:-qemu} 43 | - cargo test --verbose --manifest-path=virt-sys/Cargo.toml 44 | - if test "$CLIPPY" = "enable"; then 45 | cargo clippy --quiet --no-deps --all-targets >cargo-clippy.txt 2>&1 || true ; 46 | if test -s cargo-clippy.txt; then 47 | echo "clippy error, see cargo-clippy.txt artifact for details"; 48 | exit 1; 49 | fi; 50 | fi 51 | - if test "$DOC" = "enable"; then 52 | if ! cargo doc 2> cargo-doc.txt || ! cargo doc --features qemu 2>> cargo-doc.txt ; then 53 | echo "cargo doc error, see cargo-doc.txt artifact for details"; 54 | exit 1; 55 | fi; 56 | fi 57 | 58 | artifacts: 59 | paths: 60 | - cargo-clippy.txt 61 | - cargo-doc.txt 62 | expire_in: 1 week 63 | when: on_failure 64 | 65 | .cross_build_job: 66 | extends: 67 | - .gitlab_cross_build_job 68 | script: 69 | - export RUSTFLAGS="-D warnings" 70 | - export RUSTDOCFLAGS="-D warnings" 71 | - cargo build --verbose --target $RUST_TARGET 72 | 73 | include: '/ci/gitlab.yml' 74 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to libvirt-rust 2 | 3 | The libvirt Rust API binding accepts code contributions via merge requests 4 | on the GitLab project: 5 | 6 | https://gitlab.com/libvirt/libvirt-rust/-/merge_requests 7 | 8 | It is required that automated CI pipelines succeed before a merge request 9 | will be accepted. The global pipeline status for the `master` branch is 10 | visible at: 11 | 12 | https://gitlab.com/libvirt/libvirt-rust/pipelines 13 | 14 | CI pipeline results for merge requests will be visible via the contributors' 15 | own private repository fork: 16 | 17 | https://gitlab.com/yourusername/libvirt-rust/pipelines 18 | 19 | Contributions submitted to the project must be in compliance with the 20 | Developer Certificate of Origin Version 1.1. This is documented at: 21 | 22 | https://developercertificate.org/ 23 | 24 | To indicate compliance, each commit in a series must have a "Signed-off-by" 25 | tag with the submitter's name and email address. This can be added by passing 26 | the `-s` flag to `git commit` when creating the patches. 27 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "virt" 3 | version = "0.4.2" 4 | edition = "2021" 5 | authors = ["Sahid Orentino Ferdjaoui ",] 6 | license = "LGPL-2.1" 7 | readme = "README.md" 8 | description = "Rust bindings to the libvirt C library" 9 | documentation = "https://docs.rs/virt" 10 | keywords = ["libvirt", "virtualization", "KVM", "QEMU", "Xen",] 11 | categories = ["api-bindings", "emulators",] 12 | repository = "https://gitlab.com/libvirt/libvirt-rust" 13 | homepage = "https://libvirt.org/" 14 | rust-version = "1.63" 15 | 16 | [dependencies] 17 | libc = "0.2.0" 18 | virt-sys = { path = "virt-sys", version = "0.3.0" } 19 | uuid = "1.7.0" 20 | 21 | [dev-dependencies] 22 | serde = { version = "1.0.0", features = ["derive"] } 23 | serde-xml-rs = { version = "0.6.0" } 24 | pkg-config = { version = "0.3.0" } 25 | 26 | [features] 27 | qemu = ["virt-sys/qemu"] 28 | bindgen_regenerate = ["virt-sys/bindgen_regenerate"] 29 | api_coverage = [] 30 | 31 | [[example]] 32 | name = "guest_agent" 33 | path = "examples/guest_agent.rs" 34 | required-features = [ "qemu" ] 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # This crate provides a Rust bindings to the libvirt C library 2 | 3 | The bindings try to be a direct mapping of the underling C API 4 | with some differences to match Rust conventions. 5 | 6 | ## Important considerations 7 | 8 | Make sure the `libvirt-dev` or `libvirt-devel` package is installed 9 | (or that the development files are in your include path). 10 | 11 | The bindings do not implement all of what the C library is providing 12 | but we do consider the current API quite stable. 13 | 14 | The bindings use standard errors handling from Rust. Each method 15 | (there are some exceptions) returns a type `Option` or `Result`. 16 | 17 | ## Optional features 18 | 19 | * `qemu` allows using `libvirt-qemu` functions, such as `qemu_monitor_command`. 20 | 21 | * `bindgen_regenerate` uses the `bindgen` crate to generate a 22 | Rust-compatible representation of the C API. The output for a 23 | recent version of libvirt is already included in the repository, so 24 | only maintainers should ever need to use this feature. 25 | 26 | ## Documentation 27 | 28 | * https://libvirt.org/html/index.html 29 | * https://docs.rs/crate/virt/ 30 | 31 | ### To execute locally tests and other excerices 32 | 33 | `cargo fmt -v -- --check` 34 | 35 | The code is formatted using `rustfmt`, you should ensure that the 36 | check is passing before to submit your patch(es). It may be required 37 | to execute `rustup component add rustfmt` in your environment. 38 | 39 | `cargo test --verbose` 40 | 41 | Integration tests use a real connection to libvirtd. For instance 42 | integration_qemu.rs uses a qemu:///system connection. They are all 43 | ignored by default. 44 | 45 | `cargo test --verbose -- --ignored` 46 | 47 | Similar to 48 | [libvirt-go-module](https://gitlab.com/libvirt/libvirt-go-module), 49 | the integration tests also require that libvirtd listens on localhost 50 | with sasl auth. This can be setup by editing 51 | `/etc/libvirt/libvirtd.conf` as follows: 52 | 53 | ``` 54 | listen_tls=0 55 | listen_tcp=1 56 | auth_tcp=sasl 57 | listen_addr="127.0.0.1" 58 | ``` 59 | 60 | and starting libvirtd with the --listen flag (this can 61 | be set in /etc/sysconfig/libvirtd to make it persistent). 62 | 63 | Then create a sasl user 64 | 65 | `saslpasswd2 -a libvirt user` 66 | 67 | and enter "pass" as the password. 68 | 69 | ### To run examples 70 | 71 | ``` 72 | # cargo run --example hello 73 | # cargo run --example migrate -- qemu:///system tcp+qemu://192.168.0.1/system myguest 74 | # cargo run -F qemu --example guest_agent -- qemu:///system myguest 75 | 76 | ``` 77 | 78 | ## Contributing 79 | 80 | The libvirt project aims to add support for new APIs to libvirt-rs as 81 | soon as they are added to the main libvirt C library. If you are 82 | submitting changes to the libvirt C library API, please submit a 83 | libvirt-rs change at the same time. 84 | 85 | For more information, see the [CONTRIBUTING](CONTRIBUTING.md) file. 86 | 87 | The list of missing methods can be displayed with: 88 | 89 | ``` 90 | $ python tools/api_tests.py virDomain 91 | {'file': 'libvirt-domain', 'name': 'virDomainMigrateSetMaxSpeed', 'module': 'libvirt-domain'} 92 | {'file': 'libvirt-domain', 'name': 'virDomainRef', 'module': 'libvirt-domain'} 93 | {'file': 'libvirt-domain', 'name': 'virDomainGetMemoryParameters', 'module': 'libvirt-domain'} 94 | ... 95 | ``` 96 | -------------------------------------------------------------------------------- /ci/buildenv/almalinux-9.sh: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | function install_buildenv() { 8 | dnf update -y 9 | dnf install 'dnf-command(config-manager)' -y 10 | dnf config-manager --set-enabled -y crb 11 | dnf install -y epel-release 12 | dnf install -y \ 13 | ca-certificates \ 14 | cargo \ 15 | ccache \ 16 | clang-devel \ 17 | clippy \ 18 | cpp \ 19 | gcc \ 20 | gettext \ 21 | git \ 22 | glib2-devel \ 23 | glibc-devel \ 24 | glibc-langpack-en \ 25 | gnutls-devel \ 26 | libnl3-devel \ 27 | libtirpc-devel \ 28 | libvirt-devel \ 29 | libxml2 \ 30 | libxml2-devel \ 31 | libxslt \ 32 | make \ 33 | meson \ 34 | ninja-build \ 35 | perl-base \ 36 | pkgconfig \ 37 | python3 \ 38 | python3-docutils \ 39 | rust \ 40 | rust-std-static 41 | rm -f /usr/lib*/python3*/EXTERNALLY-MANAGED 42 | rpm -qa | sort > /packages.txt 43 | mkdir -p /usr/libexec/ccache-wrappers 44 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc 45 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 46 | } 47 | 48 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" 49 | export LANG="en_US.UTF-8" 50 | export MAKE="/usr/bin/make" 51 | export NINJA="/usr/bin/ninja" 52 | export PYTHON="/usr/bin/python3" 53 | -------------------------------------------------------------------------------- /ci/buildenv/alpine-320.sh: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | function install_buildenv() { 8 | apk update 9 | apk upgrade 10 | apk add \ 11 | ca-certificates \ 12 | cargo \ 13 | ccache \ 14 | clang-dev \ 15 | gcc \ 16 | git \ 17 | libvirt-dev \ 18 | pkgconf \ 19 | rust \ 20 | rust-clippy 21 | apk list --installed | sort > /packages.txt 22 | mkdir -p /usr/libexec/ccache-wrappers 23 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc 24 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 25 | } 26 | 27 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" 28 | export LANG="en_US.UTF-8" 29 | -------------------------------------------------------------------------------- /ci/buildenv/alpine-edge.sh: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | function install_buildenv() { 8 | apk update 9 | apk upgrade 10 | apk add \ 11 | ca-certificates \ 12 | cargo \ 13 | ccache \ 14 | clang-dev \ 15 | gcc \ 16 | git \ 17 | libvirt-dev \ 18 | pkgconf \ 19 | rust \ 20 | rust-clippy 21 | apk list --installed | sort > /packages.txt 22 | mkdir -p /usr/libexec/ccache-wrappers 23 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc 24 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 25 | } 26 | 27 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" 28 | export LANG="en_US.UTF-8" 29 | -------------------------------------------------------------------------------- /ci/buildenv/centos-stream-9.sh: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | function install_buildenv() { 8 | dnf distro-sync -y 9 | dnf install 'dnf-command(config-manager)' -y 10 | dnf config-manager --set-enabled -y crb 11 | dnf install -y epel-release 12 | dnf install -y epel-next-release 13 | dnf install -y \ 14 | ca-certificates \ 15 | cargo \ 16 | ccache \ 17 | clang-devel \ 18 | clippy \ 19 | gcc \ 20 | git \ 21 | glibc-langpack-en \ 22 | libvirt-devel \ 23 | pkgconfig \ 24 | rust \ 25 | rust-std-static 26 | rpm -qa | sort > /packages.txt 27 | mkdir -p /usr/libexec/ccache-wrappers 28 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc 29 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 30 | } 31 | 32 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" 33 | export LANG="en_US.UTF-8" 34 | -------------------------------------------------------------------------------- /ci/buildenv/debian-12-cross-aarch64.sh: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | function install_buildenv() { 8 | export DEBIAN_FRONTEND=noninteractive 9 | apt-get update 10 | apt-get dist-upgrade -y 11 | apt-get install --no-install-recommends -y \ 12 | ca-certificates \ 13 | cargo \ 14 | ccache \ 15 | git \ 16 | libclang-dev \ 17 | locales \ 18 | pkgconf \ 19 | rust-clippy \ 20 | rustc 21 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen 22 | dpkg-reconfigure locales 23 | export DEBIAN_FRONTEND=noninteractive 24 | dpkg --add-architecture arm64 25 | apt-get update 26 | apt-get dist-upgrade -y 27 | apt-get install --no-install-recommends -y dpkg-dev 28 | apt-get install --no-install-recommends -y \ 29 | gcc-aarch64-linux-gnu \ 30 | libstd-rust-dev:arm64 \ 31 | libvirt-dev:arm64 32 | mkdir -p /usr/local/share/meson/cross 33 | printf "[binaries]\n\ 34 | c = '/usr/bin/aarch64-linux-gnu-gcc'\n\ 35 | ar = '/usr/bin/aarch64-linux-gnu-gcc-ar'\n\ 36 | strip = '/usr/bin/aarch64-linux-gnu-strip'\n\ 37 | pkgconfig = '/usr/bin/aarch64-linux-gnu-pkg-config'\n\ 38 | \n\ 39 | [host_machine]\n\ 40 | system = 'linux'\n\ 41 | cpu_family = 'aarch64'\n\ 42 | cpu = 'aarch64'\n\ 43 | endian = 'little'\n" > /usr/local/share/meson/cross/aarch64-linux-gnu 44 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt 45 | mkdir -p /usr/libexec/ccache-wrappers 46 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/aarch64-linux-gnu-cc 47 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/aarch64-linux-gnu-gcc 48 | } 49 | 50 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" 51 | export LANG="en_US.UTF-8" 52 | 53 | export ABI="aarch64-linux-gnu" 54 | export RUST_TARGET="aarch64-unknown-linux-gnu" 55 | -------------------------------------------------------------------------------- /ci/buildenv/debian-12-cross-armv6l.sh: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | function install_buildenv() { 8 | export DEBIAN_FRONTEND=noninteractive 9 | apt-get update 10 | apt-get dist-upgrade -y 11 | apt-get install --no-install-recommends -y \ 12 | ca-certificates \ 13 | cargo \ 14 | ccache \ 15 | git \ 16 | libclang-dev \ 17 | locales \ 18 | pkgconf \ 19 | rust-clippy \ 20 | rustc 21 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen 22 | dpkg-reconfigure locales 23 | export DEBIAN_FRONTEND=noninteractive 24 | dpkg --add-architecture armel 25 | apt-get update 26 | apt-get dist-upgrade -y 27 | apt-get install --no-install-recommends -y dpkg-dev 28 | apt-get install --no-install-recommends -y \ 29 | gcc-arm-linux-gnueabi \ 30 | libstd-rust-dev:armel \ 31 | libvirt-dev:armel 32 | mkdir -p /usr/local/share/meson/cross 33 | printf "[binaries]\n\ 34 | c = '/usr/bin/arm-linux-gnueabi-gcc'\n\ 35 | ar = '/usr/bin/arm-linux-gnueabi-gcc-ar'\n\ 36 | strip = '/usr/bin/arm-linux-gnueabi-strip'\n\ 37 | pkgconfig = '/usr/bin/arm-linux-gnueabi-pkg-config'\n\ 38 | \n\ 39 | [host_machine]\n\ 40 | system = 'linux'\n\ 41 | cpu_family = 'arm'\n\ 42 | cpu = 'arm'\n\ 43 | endian = 'little'\n" > /usr/local/share/meson/cross/arm-linux-gnueabi 44 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt 45 | mkdir -p /usr/libexec/ccache-wrappers 46 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabi-cc 47 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabi-gcc 48 | } 49 | 50 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" 51 | export LANG="en_US.UTF-8" 52 | 53 | export ABI="arm-linux-gnueabi" 54 | export RUST_TARGET="armv5te-unknown-linux-gnueabi" 55 | -------------------------------------------------------------------------------- /ci/buildenv/debian-12-cross-armv7l.sh: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | function install_buildenv() { 8 | export DEBIAN_FRONTEND=noninteractive 9 | apt-get update 10 | apt-get dist-upgrade -y 11 | apt-get install --no-install-recommends -y \ 12 | ca-certificates \ 13 | cargo \ 14 | ccache \ 15 | git \ 16 | libclang-dev \ 17 | locales \ 18 | pkgconf \ 19 | rust-clippy \ 20 | rustc 21 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen 22 | dpkg-reconfigure locales 23 | export DEBIAN_FRONTEND=noninteractive 24 | dpkg --add-architecture armhf 25 | apt-get update 26 | apt-get dist-upgrade -y 27 | apt-get install --no-install-recommends -y dpkg-dev 28 | apt-get install --no-install-recommends -y \ 29 | gcc-arm-linux-gnueabihf \ 30 | libstd-rust-dev:armhf \ 31 | libvirt-dev:armhf 32 | mkdir -p /usr/local/share/meson/cross 33 | printf "[binaries]\n\ 34 | c = '/usr/bin/arm-linux-gnueabihf-gcc'\n\ 35 | ar = '/usr/bin/arm-linux-gnueabihf-gcc-ar'\n\ 36 | strip = '/usr/bin/arm-linux-gnueabihf-strip'\n\ 37 | pkgconfig = '/usr/bin/arm-linux-gnueabihf-pkg-config'\n\ 38 | \n\ 39 | [host_machine]\n\ 40 | system = 'linux'\n\ 41 | cpu_family = 'arm'\n\ 42 | cpu = 'armhf'\n\ 43 | endian = 'little'\n" > /usr/local/share/meson/cross/arm-linux-gnueabihf 44 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt 45 | mkdir -p /usr/libexec/ccache-wrappers 46 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabihf-cc 47 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabihf-gcc 48 | } 49 | 50 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" 51 | export LANG="en_US.UTF-8" 52 | 53 | export ABI="arm-linux-gnueabihf" 54 | export RUST_TARGET="armv7-unknown-linux-gnueabihf" 55 | -------------------------------------------------------------------------------- /ci/buildenv/debian-12-cross-i686.sh: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | function install_buildenv() { 8 | export DEBIAN_FRONTEND=noninteractive 9 | apt-get update 10 | apt-get dist-upgrade -y 11 | apt-get install --no-install-recommends -y \ 12 | ca-certificates \ 13 | cargo \ 14 | ccache \ 15 | git \ 16 | libclang-dev \ 17 | locales \ 18 | pkgconf \ 19 | rust-clippy \ 20 | rustc 21 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen 22 | dpkg-reconfigure locales 23 | export DEBIAN_FRONTEND=noninteractive 24 | dpkg --add-architecture i386 25 | apt-get update 26 | apt-get dist-upgrade -y 27 | apt-get install --no-install-recommends -y dpkg-dev 28 | apt-get install --no-install-recommends -y \ 29 | gcc-i686-linux-gnu \ 30 | libstd-rust-dev:i386 \ 31 | libvirt-dev:i386 32 | mkdir -p /usr/local/share/meson/cross 33 | printf "[binaries]\n\ 34 | c = '/usr/bin/i686-linux-gnu-gcc'\n\ 35 | ar = '/usr/bin/i686-linux-gnu-gcc-ar'\n\ 36 | strip = '/usr/bin/i686-linux-gnu-strip'\n\ 37 | pkgconfig = '/usr/bin/i686-linux-gnu-pkg-config'\n\ 38 | \n\ 39 | [host_machine]\n\ 40 | system = 'linux'\n\ 41 | cpu_family = 'x86'\n\ 42 | cpu = 'i686'\n\ 43 | endian = 'little'\n" > /usr/local/share/meson/cross/i686-linux-gnu 44 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt 45 | mkdir -p /usr/libexec/ccache-wrappers 46 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/i686-linux-gnu-cc 47 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/i686-linux-gnu-gcc 48 | } 49 | 50 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" 51 | export LANG="en_US.UTF-8" 52 | 53 | export ABI="i686-linux-gnu" 54 | export RUST_TARGET="i686-unknown-linux-gnu" 55 | -------------------------------------------------------------------------------- /ci/buildenv/debian-12-cross-mips64el.sh: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | function install_buildenv() { 8 | export DEBIAN_FRONTEND=noninteractive 9 | apt-get update 10 | apt-get dist-upgrade -y 11 | apt-get install --no-install-recommends -y \ 12 | ca-certificates \ 13 | cargo \ 14 | ccache \ 15 | git \ 16 | libclang-dev \ 17 | locales \ 18 | pkgconf \ 19 | rust-clippy \ 20 | rustc 21 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen 22 | dpkg-reconfigure locales 23 | export DEBIAN_FRONTEND=noninteractive 24 | dpkg --add-architecture mips64el 25 | apt-get update 26 | apt-get dist-upgrade -y 27 | apt-get install --no-install-recommends -y dpkg-dev 28 | apt-get install --no-install-recommends -y \ 29 | gcc-mips64el-linux-gnuabi64 \ 30 | libstd-rust-dev:mips64el \ 31 | libvirt-dev:mips64el 32 | mkdir -p /usr/local/share/meson/cross 33 | printf "[binaries]\n\ 34 | c = '/usr/bin/mips64el-linux-gnuabi64-gcc'\n\ 35 | ar = '/usr/bin/mips64el-linux-gnuabi64-gcc-ar'\n\ 36 | strip = '/usr/bin/mips64el-linux-gnuabi64-strip'\n\ 37 | pkgconfig = '/usr/bin/mips64el-linux-gnuabi64-pkg-config'\n\ 38 | \n\ 39 | [host_machine]\n\ 40 | system = 'linux'\n\ 41 | cpu_family = 'mips64'\n\ 42 | cpu = 'mips64el'\n\ 43 | endian = 'little'\n" > /usr/local/share/meson/cross/mips64el-linux-gnuabi64 44 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt 45 | mkdir -p /usr/libexec/ccache-wrappers 46 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/mips64el-linux-gnuabi64-cc 47 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/mips64el-linux-gnuabi64-gcc 48 | } 49 | 50 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" 51 | export LANG="en_US.UTF-8" 52 | 53 | export ABI="mips64el-linux-gnuabi64" 54 | export RUST_TARGET="mips64el-unknown-linux-gnuabi64" 55 | -------------------------------------------------------------------------------- /ci/buildenv/debian-12-cross-mipsel.sh: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | function install_buildenv() { 8 | export DEBIAN_FRONTEND=noninteractive 9 | apt-get update 10 | apt-get dist-upgrade -y 11 | apt-get install --no-install-recommends -y \ 12 | ca-certificates \ 13 | cargo \ 14 | ccache \ 15 | git \ 16 | libclang-dev \ 17 | locales \ 18 | pkgconf \ 19 | rust-clippy \ 20 | rustc 21 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen 22 | dpkg-reconfigure locales 23 | export DEBIAN_FRONTEND=noninteractive 24 | dpkg --add-architecture mipsel 25 | apt-get update 26 | apt-get dist-upgrade -y 27 | apt-get install --no-install-recommends -y dpkg-dev 28 | apt-get install --no-install-recommends -y \ 29 | gcc-mipsel-linux-gnu \ 30 | libstd-rust-dev:mipsel \ 31 | libvirt-dev:mipsel 32 | mkdir -p /usr/local/share/meson/cross 33 | printf "[binaries]\n\ 34 | c = '/usr/bin/mipsel-linux-gnu-gcc'\n\ 35 | ar = '/usr/bin/mipsel-linux-gnu-gcc-ar'\n\ 36 | strip = '/usr/bin/mipsel-linux-gnu-strip'\n\ 37 | pkgconfig = '/usr/bin/mipsel-linux-gnu-pkg-config'\n\ 38 | \n\ 39 | [host_machine]\n\ 40 | system = 'linux'\n\ 41 | cpu_family = 'mips'\n\ 42 | cpu = 'mipsel'\n\ 43 | endian = 'little'\n" > /usr/local/share/meson/cross/mipsel-linux-gnu 44 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt 45 | mkdir -p /usr/libexec/ccache-wrappers 46 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/mipsel-linux-gnu-cc 47 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/mipsel-linux-gnu-gcc 48 | } 49 | 50 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" 51 | export LANG="en_US.UTF-8" 52 | 53 | export ABI="mipsel-linux-gnu" 54 | export RUST_TARGET="mipsel-unknown-linux-gnu" 55 | -------------------------------------------------------------------------------- /ci/buildenv/debian-12-cross-ppc64le.sh: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | function install_buildenv() { 8 | export DEBIAN_FRONTEND=noninteractive 9 | apt-get update 10 | apt-get dist-upgrade -y 11 | apt-get install --no-install-recommends -y \ 12 | ca-certificates \ 13 | cargo \ 14 | ccache \ 15 | git \ 16 | libclang-dev \ 17 | locales \ 18 | pkgconf \ 19 | rust-clippy \ 20 | rustc 21 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen 22 | dpkg-reconfigure locales 23 | export DEBIAN_FRONTEND=noninteractive 24 | dpkg --add-architecture ppc64el 25 | apt-get update 26 | apt-get dist-upgrade -y 27 | apt-get install --no-install-recommends -y dpkg-dev 28 | apt-get install --no-install-recommends -y \ 29 | gcc-powerpc64le-linux-gnu \ 30 | libstd-rust-dev:ppc64el \ 31 | libvirt-dev:ppc64el 32 | mkdir -p /usr/local/share/meson/cross 33 | printf "[binaries]\n\ 34 | c = '/usr/bin/powerpc64le-linux-gnu-gcc'\n\ 35 | ar = '/usr/bin/powerpc64le-linux-gnu-gcc-ar'\n\ 36 | strip = '/usr/bin/powerpc64le-linux-gnu-strip'\n\ 37 | pkgconfig = '/usr/bin/powerpc64le-linux-gnu-pkg-config'\n\ 38 | \n\ 39 | [host_machine]\n\ 40 | system = 'linux'\n\ 41 | cpu_family = 'ppc64'\n\ 42 | cpu = 'powerpc64le'\n\ 43 | endian = 'little'\n" > /usr/local/share/meson/cross/powerpc64le-linux-gnu 44 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt 45 | mkdir -p /usr/libexec/ccache-wrappers 46 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/powerpc64le-linux-gnu-cc 47 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/powerpc64le-linux-gnu-gcc 48 | } 49 | 50 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" 51 | export LANG="en_US.UTF-8" 52 | 53 | export ABI="powerpc64le-linux-gnu" 54 | export RUST_TARGET="powerpc64le-unknown-linux-gnu" 55 | -------------------------------------------------------------------------------- /ci/buildenv/debian-12-cross-s390x.sh: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | function install_buildenv() { 8 | export DEBIAN_FRONTEND=noninteractive 9 | apt-get update 10 | apt-get dist-upgrade -y 11 | apt-get install --no-install-recommends -y \ 12 | ca-certificates \ 13 | cargo \ 14 | ccache \ 15 | git \ 16 | libclang-dev \ 17 | locales \ 18 | pkgconf \ 19 | rust-clippy \ 20 | rustc 21 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen 22 | dpkg-reconfigure locales 23 | export DEBIAN_FRONTEND=noninteractive 24 | dpkg --add-architecture s390x 25 | apt-get update 26 | apt-get dist-upgrade -y 27 | apt-get install --no-install-recommends -y dpkg-dev 28 | apt-get install --no-install-recommends -y \ 29 | gcc-s390x-linux-gnu \ 30 | libstd-rust-dev:s390x \ 31 | libvirt-dev:s390x 32 | mkdir -p /usr/local/share/meson/cross 33 | printf "[binaries]\n\ 34 | c = '/usr/bin/s390x-linux-gnu-gcc'\n\ 35 | ar = '/usr/bin/s390x-linux-gnu-gcc-ar'\n\ 36 | strip = '/usr/bin/s390x-linux-gnu-strip'\n\ 37 | pkgconfig = '/usr/bin/s390x-linux-gnu-pkg-config'\n\ 38 | \n\ 39 | [host_machine]\n\ 40 | system = 'linux'\n\ 41 | cpu_family = 's390x'\n\ 42 | cpu = 's390x'\n\ 43 | endian = 'big'\n" > /usr/local/share/meson/cross/s390x-linux-gnu 44 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt 45 | mkdir -p /usr/libexec/ccache-wrappers 46 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/s390x-linux-gnu-cc 47 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/s390x-linux-gnu-gcc 48 | } 49 | 50 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" 51 | export LANG="en_US.UTF-8" 52 | 53 | export ABI="s390x-linux-gnu" 54 | export RUST_TARGET="s390x-unknown-linux-gnu" 55 | -------------------------------------------------------------------------------- /ci/buildenv/debian-12.sh: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | function install_buildenv() { 8 | export DEBIAN_FRONTEND=noninteractive 9 | apt-get update 10 | apt-get dist-upgrade -y 11 | apt-get install --no-install-recommends -y \ 12 | ca-certificates \ 13 | cargo \ 14 | ccache \ 15 | gcc \ 16 | git \ 17 | libclang-dev \ 18 | libstd-rust-dev \ 19 | libvirt-dev \ 20 | locales \ 21 | pkgconf \ 22 | rust-clippy \ 23 | rustc 24 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen 25 | dpkg-reconfigure locales 26 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt 27 | mkdir -p /usr/libexec/ccache-wrappers 28 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc 29 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 30 | } 31 | 32 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" 33 | export LANG="en_US.UTF-8" 34 | -------------------------------------------------------------------------------- /ci/buildenv/debian-sid.sh: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | function install_buildenv() { 8 | export DEBIAN_FRONTEND=noninteractive 9 | apt-get update 10 | apt-get dist-upgrade -y 11 | apt-get install --no-install-recommends -y \ 12 | ca-certificates \ 13 | cargo \ 14 | ccache \ 15 | gcc \ 16 | git \ 17 | libclang-dev \ 18 | libstd-rust-dev \ 19 | libvirt-dev \ 20 | locales \ 21 | pkgconf \ 22 | rust-clippy \ 23 | rustc 24 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen 25 | dpkg-reconfigure locales 26 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt 27 | mkdir -p /usr/libexec/ccache-wrappers 28 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc 29 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 30 | } 31 | 32 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" 33 | export LANG="en_US.UTF-8" 34 | -------------------------------------------------------------------------------- /ci/buildenv/fedora-40.sh: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | function install_buildenv() { 8 | dnf update -y 9 | dnf install -y \ 10 | ca-certificates \ 11 | cargo \ 12 | ccache \ 13 | clang-devel \ 14 | clippy \ 15 | gcc \ 16 | git \ 17 | glibc-langpack-en \ 18 | libvirt-devel \ 19 | pkgconfig \ 20 | rust \ 21 | rust-std-static 22 | rpm -qa | sort > /packages.txt 23 | mkdir -p /usr/libexec/ccache-wrappers 24 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc 25 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 26 | } 27 | 28 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" 29 | export LANG="en_US.UTF-8" 30 | -------------------------------------------------------------------------------- /ci/buildenv/fedora-41.sh: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | function install_buildenv() { 8 | dnf update -y 9 | dnf install -y \ 10 | ca-certificates \ 11 | cargo \ 12 | ccache \ 13 | clang-devel \ 14 | clippy \ 15 | gcc \ 16 | git \ 17 | glibc-langpack-en \ 18 | libvirt-devel \ 19 | pkgconfig \ 20 | rust \ 21 | rust-std-static 22 | rpm -qa | sort > /packages.txt 23 | mkdir -p /usr/libexec/ccache-wrappers 24 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc 25 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 26 | } 27 | 28 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" 29 | export LANG="en_US.UTF-8" 30 | -------------------------------------------------------------------------------- /ci/buildenv/fedora-rawhide.sh: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | function install_buildenv() { 8 | dnf update -y --nogpgcheck fedora-gpg-keys 9 | dnf distro-sync -y 10 | dnf install -y \ 11 | ca-certificates \ 12 | cargo \ 13 | ccache \ 14 | clang-devel \ 15 | clippy \ 16 | gcc \ 17 | git \ 18 | glibc-langpack-en \ 19 | libvirt-devel \ 20 | pkgconfig \ 21 | rust \ 22 | rust-std-static 23 | rpm -qa | sort > /packages.txt 24 | mkdir -p /usr/libexec/ccache-wrappers 25 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc 26 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 27 | } 28 | 29 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" 30 | export LANG="en_US.UTF-8" 31 | -------------------------------------------------------------------------------- /ci/buildenv/opensuse-leap-15.sh: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | function install_buildenv() { 8 | zypper update -y 9 | zypper addrepo -fc https://download.opensuse.org/update/leap/15.6/backports/openSUSE:Backports:SLE-15-SP6:Update.repo 10 | zypper install -y \ 11 | ca-certificates \ 12 | cargo \ 13 | ccache \ 14 | clang-devel \ 15 | gcc \ 16 | git \ 17 | glibc-locale \ 18 | libvirt-devel \ 19 | pkgconfig \ 20 | rust 21 | rpm -qa | sort > /packages.txt 22 | mkdir -p /usr/libexec/ccache-wrappers 23 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc 24 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 25 | } 26 | 27 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" 28 | export LANG="en_US.UTF-8" 29 | -------------------------------------------------------------------------------- /ci/buildenv/opensuse-tumbleweed.sh: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | function install_buildenv() { 8 | zypper dist-upgrade -y 9 | zypper install -y \ 10 | ca-certificates \ 11 | cargo \ 12 | ccache \ 13 | clang-devel \ 14 | gcc \ 15 | git \ 16 | glibc-locale \ 17 | libvirt-devel \ 18 | pkgconfig \ 19 | rust 20 | rpm -qa | sort > /packages.txt 21 | mkdir -p /usr/libexec/ccache-wrappers 22 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc 23 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 24 | } 25 | 26 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" 27 | export LANG="en_US.UTF-8" 28 | -------------------------------------------------------------------------------- /ci/buildenv/ubuntu-2204.sh: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | function install_buildenv() { 8 | export DEBIAN_FRONTEND=noninteractive 9 | apt-get update 10 | apt-get dist-upgrade -y 11 | apt-get install --no-install-recommends -y \ 12 | ca-certificates \ 13 | cargo \ 14 | ccache \ 15 | gcc \ 16 | git \ 17 | libclang-dev \ 18 | libstd-rust-dev \ 19 | libvirt-dev \ 20 | locales \ 21 | pkgconf \ 22 | rust-clippy \ 23 | rustc 24 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen 25 | dpkg-reconfigure locales 26 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt 27 | mkdir -p /usr/libexec/ccache-wrappers 28 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc 29 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 30 | } 31 | 32 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" 33 | export LANG="en_US.UTF-8" 34 | -------------------------------------------------------------------------------- /ci/buildenv/ubuntu-2404.sh: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | function install_buildenv() { 8 | export DEBIAN_FRONTEND=noninteractive 9 | apt-get update 10 | apt-get dist-upgrade -y 11 | apt-get install --no-install-recommends -y \ 12 | ca-certificates \ 13 | cargo \ 14 | ccache \ 15 | gcc \ 16 | git \ 17 | libclang-dev \ 18 | libstd-rust-dev \ 19 | libvirt-dev \ 20 | locales \ 21 | pkgconf \ 22 | rust-clippy \ 23 | rustc 24 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen 25 | dpkg-reconfigure locales 26 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt 27 | mkdir -p /usr/libexec/ccache-wrappers 28 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc 29 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 30 | } 31 | 32 | export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" 33 | export LANG="en_US.UTF-8" 34 | -------------------------------------------------------------------------------- /ci/cirrus/build.yml: -------------------------------------------------------------------------------- 1 | @CIRRUS_VM_INSTANCE_TYPE@: 2 | @CIRRUS_VM_IMAGE_SELECTOR@: @CIRRUS_VM_IMAGE_NAME@ 3 | 4 | env: 5 | CI_REPOSITORY_URL: "@CI_REPOSITORY_URL@" 6 | CI_COMMIT_REF_NAME: "@CI_COMMIT_REF_NAME@" 7 | CI_MERGE_REQUEST_REF_PATH: "@CI_MERGE_REQUEST_REF_PATH@" 8 | CI_COMMIT_SHA: "@CI_COMMIT_SHA@" 9 | PATH: "@PATH_EXTRA@:$PATH" 10 | PKG_CONFIG_PATH: "@PKG_CONFIG_PATH@" 11 | 12 | build_task: 13 | install_script: 14 | - @UPDATE_COMMAND@ 15 | - @UPGRADE_COMMAND@ 16 | - @INSTALL_COMMAND@ @PKGS@ 17 | clone_script: 18 | - git clone --depth 100 "$CI_REPOSITORY_URL" . 19 | - git fetch origin "${CI_MERGE_REQUEST_REF_PATH:-$CI_COMMIT_REF_NAME}" 20 | - git reset --hard "$CI_COMMIT_SHA" 21 | build_script: 22 | - cargo test 23 | -------------------------------------------------------------------------------- /ci/cirrus/freebsd-13.vars: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | CCACHE='/usr/local/bin/ccache' 8 | CPAN_PKGS='' 9 | CROSS_PKGS='' 10 | MAKE='/usr/local/bin/gmake' 11 | NINJA='/usr/local/bin/ninja' 12 | PACKAGING_COMMAND='pkg' 13 | PIP3='/usr/local/bin/pip-3.8' 14 | PKGS='ca_root_nss ccache4 git libvirt pkgconf rust' 15 | PYPI_PKGS='' 16 | PYTHON='/usr/local/bin/python3' 17 | -------------------------------------------------------------------------------- /ci/cirrus/freebsd-14.vars: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | CCACHE='/usr/local/bin/ccache' 8 | CPAN_PKGS='' 9 | CROSS_PKGS='' 10 | MAKE='/usr/local/bin/gmake' 11 | NINJA='/usr/local/bin/ninja' 12 | PACKAGING_COMMAND='pkg' 13 | PIP3='/usr/local/bin/pip' 14 | PKGS='ca_root_nss ccache4 git libvirt pkgconf rust' 15 | PYPI_PKGS='' 16 | PYTHON='/usr/local/bin/python3' 17 | -------------------------------------------------------------------------------- /ci/cirrus/macos-14.vars: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | CCACHE='/opt/homebrew/bin/ccache' 8 | CPAN_PKGS='' 9 | CROSS_PKGS='' 10 | MAKE='/opt/homebrew/bin/gmake' 11 | NINJA='/opt/homebrew/bin/ninja' 12 | PACKAGING_COMMAND='brew' 13 | PIP3='/opt/homebrew/bin/pip3' 14 | PKGS='ccache git libvirt pkg-config rust' 15 | PYPI_PKGS='' 16 | PYTHON='/opt/homebrew/bin/python3' 17 | -------------------------------------------------------------------------------- /ci/containers/almalinux-9.Dockerfile: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | FROM docker.io/library/almalinux:9 8 | 9 | RUN dnf update -y && \ 10 | dnf install 'dnf-command(config-manager)' -y && \ 11 | dnf config-manager --set-enabled -y crb && \ 12 | dnf install -y epel-release && \ 13 | dnf install -y \ 14 | ca-certificates \ 15 | cargo \ 16 | ccache \ 17 | clang-devel \ 18 | clippy \ 19 | cpp \ 20 | gcc \ 21 | gettext \ 22 | git \ 23 | glib2-devel \ 24 | glibc-devel \ 25 | glibc-langpack-en \ 26 | gnutls-devel \ 27 | libnl3-devel \ 28 | libtirpc-devel \ 29 | libvirt-devel \ 30 | libxml2 \ 31 | libxml2-devel \ 32 | libxslt \ 33 | make \ 34 | meson \ 35 | ninja-build \ 36 | perl-base \ 37 | pkgconfig \ 38 | python3 \ 39 | python3-docutils \ 40 | rust \ 41 | rust-std-static && \ 42 | dnf autoremove -y && \ 43 | dnf clean all -y && \ 44 | rm -f /usr/lib*/python3*/EXTERNALLY-MANAGED && \ 45 | rpm -qa | sort > /packages.txt && \ 46 | mkdir -p /usr/libexec/ccache-wrappers && \ 47 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ 48 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 49 | 50 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 51 | ENV LANG "en_US.UTF-8" 52 | ENV MAKE "/usr/bin/make" 53 | ENV NINJA "/usr/bin/ninja" 54 | ENV PYTHON "/usr/bin/python3" 55 | -------------------------------------------------------------------------------- /ci/containers/alpine-320.Dockerfile: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | FROM docker.io/library/alpine:3.20 8 | 9 | RUN apk update && \ 10 | apk upgrade && \ 11 | apk add \ 12 | ca-certificates \ 13 | cargo \ 14 | ccache \ 15 | clang-dev \ 16 | gcc \ 17 | git \ 18 | libvirt-dev \ 19 | pkgconf \ 20 | rust \ 21 | rust-clippy && \ 22 | apk list --installed | sort > /packages.txt && \ 23 | mkdir -p /usr/libexec/ccache-wrappers && \ 24 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ 25 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 26 | 27 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 28 | ENV LANG "en_US.UTF-8" 29 | -------------------------------------------------------------------------------- /ci/containers/alpine-edge.Dockerfile: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | FROM docker.io/library/alpine:edge 8 | 9 | RUN apk update && \ 10 | apk upgrade && \ 11 | apk add \ 12 | ca-certificates \ 13 | cargo \ 14 | ccache \ 15 | clang-dev \ 16 | gcc \ 17 | git \ 18 | libvirt-dev \ 19 | pkgconf \ 20 | rust \ 21 | rust-clippy && \ 22 | apk list --installed | sort > /packages.txt && \ 23 | mkdir -p /usr/libexec/ccache-wrappers && \ 24 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ 25 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 26 | 27 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 28 | ENV LANG "en_US.UTF-8" 29 | -------------------------------------------------------------------------------- /ci/containers/centos-stream-9.Dockerfile: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | FROM quay.io/centos/centos:stream9 8 | 9 | RUN dnf distro-sync -y && \ 10 | dnf install 'dnf-command(config-manager)' -y && \ 11 | dnf config-manager --set-enabled -y crb && \ 12 | dnf install -y epel-release && \ 13 | dnf install -y epel-next-release && \ 14 | dnf install -y \ 15 | ca-certificates \ 16 | cargo \ 17 | ccache \ 18 | clang-devel \ 19 | clippy \ 20 | gcc \ 21 | git \ 22 | glibc-langpack-en \ 23 | libvirt-devel \ 24 | pkgconfig \ 25 | rust \ 26 | rust-std-static && \ 27 | dnf autoremove -y && \ 28 | dnf clean all -y && \ 29 | rpm -qa | sort > /packages.txt && \ 30 | mkdir -p /usr/libexec/ccache-wrappers && \ 31 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ 32 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 33 | 34 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 35 | ENV LANG "en_US.UTF-8" 36 | -------------------------------------------------------------------------------- /ci/containers/debian-12-cross-aarch64.Dockerfile: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | FROM docker.io/library/debian:12-slim 8 | 9 | RUN export DEBIAN_FRONTEND=noninteractive && \ 10 | apt-get update && \ 11 | apt-get install -y eatmydata && \ 12 | eatmydata apt-get dist-upgrade -y && \ 13 | eatmydata apt-get install --no-install-recommends -y \ 14 | ca-certificates \ 15 | cargo \ 16 | ccache \ 17 | git \ 18 | libclang-dev \ 19 | locales \ 20 | pkgconf \ 21 | rust-clippy \ 22 | rustc && \ 23 | eatmydata apt-get autoremove -y && \ 24 | eatmydata apt-get autoclean -y && \ 25 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ 26 | dpkg-reconfigure locales 27 | 28 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 29 | ENV LANG "en_US.UTF-8" 30 | 31 | RUN export DEBIAN_FRONTEND=noninteractive && \ 32 | dpkg --add-architecture arm64 && \ 33 | eatmydata apt-get update && \ 34 | eatmydata apt-get dist-upgrade -y && \ 35 | eatmydata apt-get install --no-install-recommends -y dpkg-dev && \ 36 | eatmydata apt-get install --no-install-recommends -y \ 37 | gcc-aarch64-linux-gnu \ 38 | libstd-rust-dev:arm64 \ 39 | libvirt-dev:arm64 && \ 40 | eatmydata apt-get autoremove -y && \ 41 | eatmydata apt-get autoclean -y && \ 42 | mkdir -p /usr/local/share/meson/cross && \ 43 | printf "[binaries]\n\ 44 | c = '/usr/bin/aarch64-linux-gnu-gcc'\n\ 45 | ar = '/usr/bin/aarch64-linux-gnu-gcc-ar'\n\ 46 | strip = '/usr/bin/aarch64-linux-gnu-strip'\n\ 47 | pkgconfig = '/usr/bin/aarch64-linux-gnu-pkg-config'\n\ 48 | \n\ 49 | [host_machine]\n\ 50 | system = 'linux'\n\ 51 | cpu_family = 'aarch64'\n\ 52 | cpu = 'aarch64'\n\ 53 | endian = 'little'\n" > /usr/local/share/meson/cross/aarch64-linux-gnu && \ 54 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ 55 | mkdir -p /usr/libexec/ccache-wrappers && \ 56 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/aarch64-linux-gnu-cc && \ 57 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/aarch64-linux-gnu-gcc 58 | 59 | ENV ABI "aarch64-linux-gnu" 60 | ENV RUST_TARGET "aarch64-unknown-linux-gnu" 61 | -------------------------------------------------------------------------------- /ci/containers/debian-12-cross-armv6l.Dockerfile: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | FROM docker.io/library/debian:12-slim 8 | 9 | RUN export DEBIAN_FRONTEND=noninteractive && \ 10 | apt-get update && \ 11 | apt-get install -y eatmydata && \ 12 | eatmydata apt-get dist-upgrade -y && \ 13 | eatmydata apt-get install --no-install-recommends -y \ 14 | ca-certificates \ 15 | cargo \ 16 | ccache \ 17 | git \ 18 | libclang-dev \ 19 | locales \ 20 | pkgconf \ 21 | rust-clippy \ 22 | rustc && \ 23 | eatmydata apt-get autoremove -y && \ 24 | eatmydata apt-get autoclean -y && \ 25 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ 26 | dpkg-reconfigure locales 27 | 28 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 29 | ENV LANG "en_US.UTF-8" 30 | 31 | RUN export DEBIAN_FRONTEND=noninteractive && \ 32 | dpkg --add-architecture armel && \ 33 | eatmydata apt-get update && \ 34 | eatmydata apt-get dist-upgrade -y && \ 35 | eatmydata apt-get install --no-install-recommends -y dpkg-dev && \ 36 | eatmydata apt-get install --no-install-recommends -y \ 37 | gcc-arm-linux-gnueabi \ 38 | libstd-rust-dev:armel \ 39 | libvirt-dev:armel && \ 40 | eatmydata apt-get autoremove -y && \ 41 | eatmydata apt-get autoclean -y && \ 42 | mkdir -p /usr/local/share/meson/cross && \ 43 | printf "[binaries]\n\ 44 | c = '/usr/bin/arm-linux-gnueabi-gcc'\n\ 45 | ar = '/usr/bin/arm-linux-gnueabi-gcc-ar'\n\ 46 | strip = '/usr/bin/arm-linux-gnueabi-strip'\n\ 47 | pkgconfig = '/usr/bin/arm-linux-gnueabi-pkg-config'\n\ 48 | \n\ 49 | [host_machine]\n\ 50 | system = 'linux'\n\ 51 | cpu_family = 'arm'\n\ 52 | cpu = 'arm'\n\ 53 | endian = 'little'\n" > /usr/local/share/meson/cross/arm-linux-gnueabi && \ 54 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ 55 | mkdir -p /usr/libexec/ccache-wrappers && \ 56 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabi-cc && \ 57 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabi-gcc 58 | 59 | ENV ABI "arm-linux-gnueabi" 60 | ENV RUST_TARGET "armv5te-unknown-linux-gnueabi" 61 | -------------------------------------------------------------------------------- /ci/containers/debian-12-cross-armv7l.Dockerfile: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | FROM docker.io/library/debian:12-slim 8 | 9 | RUN export DEBIAN_FRONTEND=noninteractive && \ 10 | apt-get update && \ 11 | apt-get install -y eatmydata && \ 12 | eatmydata apt-get dist-upgrade -y && \ 13 | eatmydata apt-get install --no-install-recommends -y \ 14 | ca-certificates \ 15 | cargo \ 16 | ccache \ 17 | git \ 18 | libclang-dev \ 19 | locales \ 20 | pkgconf \ 21 | rust-clippy \ 22 | rustc && \ 23 | eatmydata apt-get autoremove -y && \ 24 | eatmydata apt-get autoclean -y && \ 25 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ 26 | dpkg-reconfigure locales 27 | 28 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 29 | ENV LANG "en_US.UTF-8" 30 | 31 | RUN export DEBIAN_FRONTEND=noninteractive && \ 32 | dpkg --add-architecture armhf && \ 33 | eatmydata apt-get update && \ 34 | eatmydata apt-get dist-upgrade -y && \ 35 | eatmydata apt-get install --no-install-recommends -y dpkg-dev && \ 36 | eatmydata apt-get install --no-install-recommends -y \ 37 | gcc-arm-linux-gnueabihf \ 38 | libstd-rust-dev:armhf \ 39 | libvirt-dev:armhf && \ 40 | eatmydata apt-get autoremove -y && \ 41 | eatmydata apt-get autoclean -y && \ 42 | mkdir -p /usr/local/share/meson/cross && \ 43 | printf "[binaries]\n\ 44 | c = '/usr/bin/arm-linux-gnueabihf-gcc'\n\ 45 | ar = '/usr/bin/arm-linux-gnueabihf-gcc-ar'\n\ 46 | strip = '/usr/bin/arm-linux-gnueabihf-strip'\n\ 47 | pkgconfig = '/usr/bin/arm-linux-gnueabihf-pkg-config'\n\ 48 | \n\ 49 | [host_machine]\n\ 50 | system = 'linux'\n\ 51 | cpu_family = 'arm'\n\ 52 | cpu = 'armhf'\n\ 53 | endian = 'little'\n" > /usr/local/share/meson/cross/arm-linux-gnueabihf && \ 54 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ 55 | mkdir -p /usr/libexec/ccache-wrappers && \ 56 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabihf-cc && \ 57 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabihf-gcc 58 | 59 | ENV ABI "arm-linux-gnueabihf" 60 | ENV RUST_TARGET "armv7-unknown-linux-gnueabihf" 61 | -------------------------------------------------------------------------------- /ci/containers/debian-12-cross-i686.Dockerfile: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | FROM docker.io/library/debian:12-slim 8 | 9 | RUN export DEBIAN_FRONTEND=noninteractive && \ 10 | apt-get update && \ 11 | apt-get install -y eatmydata && \ 12 | eatmydata apt-get dist-upgrade -y && \ 13 | eatmydata apt-get install --no-install-recommends -y \ 14 | ca-certificates \ 15 | cargo \ 16 | ccache \ 17 | git \ 18 | libclang-dev \ 19 | locales \ 20 | pkgconf \ 21 | rust-clippy \ 22 | rustc && \ 23 | eatmydata apt-get autoremove -y && \ 24 | eatmydata apt-get autoclean -y && \ 25 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ 26 | dpkg-reconfigure locales 27 | 28 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 29 | ENV LANG "en_US.UTF-8" 30 | 31 | RUN export DEBIAN_FRONTEND=noninteractive && \ 32 | dpkg --add-architecture i386 && \ 33 | eatmydata apt-get update && \ 34 | eatmydata apt-get dist-upgrade -y && \ 35 | eatmydata apt-get install --no-install-recommends -y dpkg-dev && \ 36 | eatmydata apt-get install --no-install-recommends -y \ 37 | gcc-i686-linux-gnu \ 38 | libstd-rust-dev:i386 \ 39 | libvirt-dev:i386 && \ 40 | eatmydata apt-get autoremove -y && \ 41 | eatmydata apt-get autoclean -y && \ 42 | mkdir -p /usr/local/share/meson/cross && \ 43 | printf "[binaries]\n\ 44 | c = '/usr/bin/i686-linux-gnu-gcc'\n\ 45 | ar = '/usr/bin/i686-linux-gnu-gcc-ar'\n\ 46 | strip = '/usr/bin/i686-linux-gnu-strip'\n\ 47 | pkgconfig = '/usr/bin/i686-linux-gnu-pkg-config'\n\ 48 | \n\ 49 | [host_machine]\n\ 50 | system = 'linux'\n\ 51 | cpu_family = 'x86'\n\ 52 | cpu = 'i686'\n\ 53 | endian = 'little'\n" > /usr/local/share/meson/cross/i686-linux-gnu && \ 54 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ 55 | mkdir -p /usr/libexec/ccache-wrappers && \ 56 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/i686-linux-gnu-cc && \ 57 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/i686-linux-gnu-gcc 58 | 59 | ENV ABI "i686-linux-gnu" 60 | ENV RUST_TARGET "i686-unknown-linux-gnu" 61 | -------------------------------------------------------------------------------- /ci/containers/debian-12-cross-mips64el.Dockerfile: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | FROM docker.io/library/debian:12-slim 8 | 9 | RUN export DEBIAN_FRONTEND=noninteractive && \ 10 | apt-get update && \ 11 | apt-get install -y eatmydata && \ 12 | eatmydata apt-get dist-upgrade -y && \ 13 | eatmydata apt-get install --no-install-recommends -y \ 14 | ca-certificates \ 15 | cargo \ 16 | ccache \ 17 | git \ 18 | libclang-dev \ 19 | locales \ 20 | pkgconf \ 21 | rust-clippy \ 22 | rustc && \ 23 | eatmydata apt-get autoremove -y && \ 24 | eatmydata apt-get autoclean -y && \ 25 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ 26 | dpkg-reconfigure locales 27 | 28 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 29 | ENV LANG "en_US.UTF-8" 30 | 31 | RUN export DEBIAN_FRONTEND=noninteractive && \ 32 | dpkg --add-architecture mips64el && \ 33 | eatmydata apt-get update && \ 34 | eatmydata apt-get dist-upgrade -y && \ 35 | eatmydata apt-get install --no-install-recommends -y dpkg-dev && \ 36 | eatmydata apt-get install --no-install-recommends -y \ 37 | gcc-mips64el-linux-gnuabi64 \ 38 | libstd-rust-dev:mips64el \ 39 | libvirt-dev:mips64el && \ 40 | eatmydata apt-get autoremove -y && \ 41 | eatmydata apt-get autoclean -y && \ 42 | mkdir -p /usr/local/share/meson/cross && \ 43 | printf "[binaries]\n\ 44 | c = '/usr/bin/mips64el-linux-gnuabi64-gcc'\n\ 45 | ar = '/usr/bin/mips64el-linux-gnuabi64-gcc-ar'\n\ 46 | strip = '/usr/bin/mips64el-linux-gnuabi64-strip'\n\ 47 | pkgconfig = '/usr/bin/mips64el-linux-gnuabi64-pkg-config'\n\ 48 | \n\ 49 | [host_machine]\n\ 50 | system = 'linux'\n\ 51 | cpu_family = 'mips64'\n\ 52 | cpu = 'mips64el'\n\ 53 | endian = 'little'\n" > /usr/local/share/meson/cross/mips64el-linux-gnuabi64 && \ 54 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ 55 | mkdir -p /usr/libexec/ccache-wrappers && \ 56 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/mips64el-linux-gnuabi64-cc && \ 57 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/mips64el-linux-gnuabi64-gcc 58 | 59 | ENV ABI "mips64el-linux-gnuabi64" 60 | ENV RUST_TARGET "mips64el-unknown-linux-gnuabi64" 61 | -------------------------------------------------------------------------------- /ci/containers/debian-12-cross-mipsel.Dockerfile: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | FROM docker.io/library/debian:12-slim 8 | 9 | RUN export DEBIAN_FRONTEND=noninteractive && \ 10 | apt-get update && \ 11 | apt-get install -y eatmydata && \ 12 | eatmydata apt-get dist-upgrade -y && \ 13 | eatmydata apt-get install --no-install-recommends -y \ 14 | ca-certificates \ 15 | cargo \ 16 | ccache \ 17 | git \ 18 | libclang-dev \ 19 | locales \ 20 | pkgconf \ 21 | rust-clippy \ 22 | rustc && \ 23 | eatmydata apt-get autoremove -y && \ 24 | eatmydata apt-get autoclean -y && \ 25 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ 26 | dpkg-reconfigure locales 27 | 28 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 29 | ENV LANG "en_US.UTF-8" 30 | 31 | RUN export DEBIAN_FRONTEND=noninteractive && \ 32 | dpkg --add-architecture mipsel && \ 33 | eatmydata apt-get update && \ 34 | eatmydata apt-get dist-upgrade -y && \ 35 | eatmydata apt-get install --no-install-recommends -y dpkg-dev && \ 36 | eatmydata apt-get install --no-install-recommends -y \ 37 | gcc-mipsel-linux-gnu \ 38 | libstd-rust-dev:mipsel \ 39 | libvirt-dev:mipsel && \ 40 | eatmydata apt-get autoremove -y && \ 41 | eatmydata apt-get autoclean -y && \ 42 | mkdir -p /usr/local/share/meson/cross && \ 43 | printf "[binaries]\n\ 44 | c = '/usr/bin/mipsel-linux-gnu-gcc'\n\ 45 | ar = '/usr/bin/mipsel-linux-gnu-gcc-ar'\n\ 46 | strip = '/usr/bin/mipsel-linux-gnu-strip'\n\ 47 | pkgconfig = '/usr/bin/mipsel-linux-gnu-pkg-config'\n\ 48 | \n\ 49 | [host_machine]\n\ 50 | system = 'linux'\n\ 51 | cpu_family = 'mips'\n\ 52 | cpu = 'mipsel'\n\ 53 | endian = 'little'\n" > /usr/local/share/meson/cross/mipsel-linux-gnu && \ 54 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ 55 | mkdir -p /usr/libexec/ccache-wrappers && \ 56 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/mipsel-linux-gnu-cc && \ 57 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/mipsel-linux-gnu-gcc 58 | 59 | ENV ABI "mipsel-linux-gnu" 60 | ENV RUST_TARGET "mipsel-unknown-linux-gnu" 61 | -------------------------------------------------------------------------------- /ci/containers/debian-12-cross-ppc64le.Dockerfile: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | FROM docker.io/library/debian:12-slim 8 | 9 | RUN export DEBIAN_FRONTEND=noninteractive && \ 10 | apt-get update && \ 11 | apt-get install -y eatmydata && \ 12 | eatmydata apt-get dist-upgrade -y && \ 13 | eatmydata apt-get install --no-install-recommends -y \ 14 | ca-certificates \ 15 | cargo \ 16 | ccache \ 17 | git \ 18 | libclang-dev \ 19 | locales \ 20 | pkgconf \ 21 | rust-clippy \ 22 | rustc && \ 23 | eatmydata apt-get autoremove -y && \ 24 | eatmydata apt-get autoclean -y && \ 25 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ 26 | dpkg-reconfigure locales 27 | 28 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 29 | ENV LANG "en_US.UTF-8" 30 | 31 | RUN export DEBIAN_FRONTEND=noninteractive && \ 32 | dpkg --add-architecture ppc64el && \ 33 | eatmydata apt-get update && \ 34 | eatmydata apt-get dist-upgrade -y && \ 35 | eatmydata apt-get install --no-install-recommends -y dpkg-dev && \ 36 | eatmydata apt-get install --no-install-recommends -y \ 37 | gcc-powerpc64le-linux-gnu \ 38 | libstd-rust-dev:ppc64el \ 39 | libvirt-dev:ppc64el && \ 40 | eatmydata apt-get autoremove -y && \ 41 | eatmydata apt-get autoclean -y && \ 42 | mkdir -p /usr/local/share/meson/cross && \ 43 | printf "[binaries]\n\ 44 | c = '/usr/bin/powerpc64le-linux-gnu-gcc'\n\ 45 | ar = '/usr/bin/powerpc64le-linux-gnu-gcc-ar'\n\ 46 | strip = '/usr/bin/powerpc64le-linux-gnu-strip'\n\ 47 | pkgconfig = '/usr/bin/powerpc64le-linux-gnu-pkg-config'\n\ 48 | \n\ 49 | [host_machine]\n\ 50 | system = 'linux'\n\ 51 | cpu_family = 'ppc64'\n\ 52 | cpu = 'powerpc64le'\n\ 53 | endian = 'little'\n" > /usr/local/share/meson/cross/powerpc64le-linux-gnu && \ 54 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ 55 | mkdir -p /usr/libexec/ccache-wrappers && \ 56 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/powerpc64le-linux-gnu-cc && \ 57 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/powerpc64le-linux-gnu-gcc 58 | 59 | ENV ABI "powerpc64le-linux-gnu" 60 | ENV RUST_TARGET "powerpc64le-unknown-linux-gnu" 61 | -------------------------------------------------------------------------------- /ci/containers/debian-12-cross-s390x.Dockerfile: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | FROM docker.io/library/debian:12-slim 8 | 9 | RUN export DEBIAN_FRONTEND=noninteractive && \ 10 | apt-get update && \ 11 | apt-get install -y eatmydata && \ 12 | eatmydata apt-get dist-upgrade -y && \ 13 | eatmydata apt-get install --no-install-recommends -y \ 14 | ca-certificates \ 15 | cargo \ 16 | ccache \ 17 | git \ 18 | libclang-dev \ 19 | locales \ 20 | pkgconf \ 21 | rust-clippy \ 22 | rustc && \ 23 | eatmydata apt-get autoremove -y && \ 24 | eatmydata apt-get autoclean -y && \ 25 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ 26 | dpkg-reconfigure locales 27 | 28 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 29 | ENV LANG "en_US.UTF-8" 30 | 31 | RUN export DEBIAN_FRONTEND=noninteractive && \ 32 | dpkg --add-architecture s390x && \ 33 | eatmydata apt-get update && \ 34 | eatmydata apt-get dist-upgrade -y && \ 35 | eatmydata apt-get install --no-install-recommends -y dpkg-dev && \ 36 | eatmydata apt-get install --no-install-recommends -y \ 37 | gcc-s390x-linux-gnu \ 38 | libstd-rust-dev:s390x \ 39 | libvirt-dev:s390x && \ 40 | eatmydata apt-get autoremove -y && \ 41 | eatmydata apt-get autoclean -y && \ 42 | mkdir -p /usr/local/share/meson/cross && \ 43 | printf "[binaries]\n\ 44 | c = '/usr/bin/s390x-linux-gnu-gcc'\n\ 45 | ar = '/usr/bin/s390x-linux-gnu-gcc-ar'\n\ 46 | strip = '/usr/bin/s390x-linux-gnu-strip'\n\ 47 | pkgconfig = '/usr/bin/s390x-linux-gnu-pkg-config'\n\ 48 | \n\ 49 | [host_machine]\n\ 50 | system = 'linux'\n\ 51 | cpu_family = 's390x'\n\ 52 | cpu = 's390x'\n\ 53 | endian = 'big'\n" > /usr/local/share/meson/cross/s390x-linux-gnu && \ 54 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ 55 | mkdir -p /usr/libexec/ccache-wrappers && \ 56 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/s390x-linux-gnu-cc && \ 57 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/s390x-linux-gnu-gcc 58 | 59 | ENV ABI "s390x-linux-gnu" 60 | ENV RUST_TARGET "s390x-unknown-linux-gnu" 61 | -------------------------------------------------------------------------------- /ci/containers/debian-12.Dockerfile: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | FROM docker.io/library/debian:12-slim 8 | 9 | RUN export DEBIAN_FRONTEND=noninteractive && \ 10 | apt-get update && \ 11 | apt-get install -y eatmydata && \ 12 | eatmydata apt-get dist-upgrade -y && \ 13 | eatmydata apt-get install --no-install-recommends -y \ 14 | ca-certificates \ 15 | cargo \ 16 | ccache \ 17 | gcc \ 18 | git \ 19 | libclang-dev \ 20 | libstd-rust-dev \ 21 | libvirt-dev \ 22 | locales \ 23 | pkgconf \ 24 | rust-clippy \ 25 | rustc && \ 26 | eatmydata apt-get autoremove -y && \ 27 | eatmydata apt-get autoclean -y && \ 28 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ 29 | dpkg-reconfigure locales && \ 30 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ 31 | mkdir -p /usr/libexec/ccache-wrappers && \ 32 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ 33 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 34 | 35 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 36 | ENV LANG "en_US.UTF-8" 37 | -------------------------------------------------------------------------------- /ci/containers/debian-sid.Dockerfile: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | FROM docker.io/library/debian:sid-slim 8 | 9 | RUN export DEBIAN_FRONTEND=noninteractive && \ 10 | apt-get update && \ 11 | apt-get install -y eatmydata && \ 12 | eatmydata apt-get dist-upgrade -y && \ 13 | eatmydata apt-get install --no-install-recommends -y \ 14 | ca-certificates \ 15 | cargo \ 16 | ccache \ 17 | gcc \ 18 | git \ 19 | libclang-dev \ 20 | libstd-rust-dev \ 21 | libvirt-dev \ 22 | locales \ 23 | pkgconf \ 24 | rust-clippy \ 25 | rustc && \ 26 | eatmydata apt-get autoremove -y && \ 27 | eatmydata apt-get autoclean -y && \ 28 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ 29 | dpkg-reconfigure locales && \ 30 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ 31 | mkdir -p /usr/libexec/ccache-wrappers && \ 32 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ 33 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 34 | 35 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 36 | ENV LANG "en_US.UTF-8" 37 | -------------------------------------------------------------------------------- /ci/containers/fedora-40.Dockerfile: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | FROM registry.fedoraproject.org/fedora:40 8 | 9 | RUN dnf install -y nosync && \ 10 | printf '#!/bin/sh\n\ 11 | if test -d /usr/lib64\n\ 12 | then\n\ 13 | export LD_PRELOAD=/usr/lib64/nosync/nosync.so\n\ 14 | else\n\ 15 | export LD_PRELOAD=/usr/lib/nosync/nosync.so\n\ 16 | fi\n\ 17 | exec "$@"\n' > /usr/bin/nosync && \ 18 | chmod +x /usr/bin/nosync && \ 19 | nosync dnf update -y && \ 20 | nosync dnf install -y \ 21 | ca-certificates \ 22 | cargo \ 23 | ccache \ 24 | clang-devel \ 25 | clippy \ 26 | gcc \ 27 | git \ 28 | glibc-langpack-en \ 29 | libvirt-devel \ 30 | pkgconfig \ 31 | rust \ 32 | rust-std-static && \ 33 | nosync dnf autoremove -y && \ 34 | nosync dnf clean all -y && \ 35 | rpm -qa | sort > /packages.txt && \ 36 | mkdir -p /usr/libexec/ccache-wrappers && \ 37 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ 38 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 39 | 40 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 41 | ENV LANG "en_US.UTF-8" 42 | -------------------------------------------------------------------------------- /ci/containers/fedora-41.Dockerfile: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | FROM registry.fedoraproject.org/fedora:41 8 | 9 | RUN dnf install -y nosync && \ 10 | printf '#!/bin/sh\n\ 11 | if test -d /usr/lib64\n\ 12 | then\n\ 13 | export LD_PRELOAD=/usr/lib64/nosync/nosync.so\n\ 14 | else\n\ 15 | export LD_PRELOAD=/usr/lib/nosync/nosync.so\n\ 16 | fi\n\ 17 | exec "$@"\n' > /usr/bin/nosync && \ 18 | chmod +x /usr/bin/nosync && \ 19 | nosync dnf update -y && \ 20 | nosync dnf install -y \ 21 | ca-certificates \ 22 | cargo \ 23 | ccache \ 24 | clang-devel \ 25 | clippy \ 26 | gcc \ 27 | git \ 28 | glibc-langpack-en \ 29 | libvirt-devel \ 30 | pkgconfig \ 31 | rust \ 32 | rust-std-static && \ 33 | nosync dnf autoremove -y && \ 34 | nosync dnf clean all -y && \ 35 | rpm -qa | sort > /packages.txt && \ 36 | mkdir -p /usr/libexec/ccache-wrappers && \ 37 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ 38 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 39 | 40 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 41 | ENV LANG "en_US.UTF-8" 42 | -------------------------------------------------------------------------------- /ci/containers/fedora-rawhide.Dockerfile: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | FROM registry.fedoraproject.org/fedora:rawhide 8 | 9 | RUN dnf update -y --nogpgcheck fedora-gpg-keys && \ 10 | dnf install -y nosync && \ 11 | printf '#!/bin/sh\n\ 12 | if test -d /usr/lib64\n\ 13 | then\n\ 14 | export LD_PRELOAD=/usr/lib64/nosync/nosync.so\n\ 15 | else\n\ 16 | export LD_PRELOAD=/usr/lib/nosync/nosync.so\n\ 17 | fi\n\ 18 | exec "$@"\n' > /usr/bin/nosync && \ 19 | chmod +x /usr/bin/nosync && \ 20 | nosync dnf distro-sync -y && \ 21 | nosync dnf install -y \ 22 | ca-certificates \ 23 | cargo \ 24 | ccache \ 25 | clang-devel \ 26 | clippy \ 27 | gcc \ 28 | git \ 29 | glibc-langpack-en \ 30 | libvirt-devel \ 31 | pkgconfig \ 32 | rust \ 33 | rust-std-static && \ 34 | nosync dnf autoremove -y && \ 35 | nosync dnf clean all -y && \ 36 | rpm -qa | sort > /packages.txt && \ 37 | mkdir -p /usr/libexec/ccache-wrappers && \ 38 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ 39 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 40 | 41 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 42 | ENV LANG "en_US.UTF-8" 43 | -------------------------------------------------------------------------------- /ci/containers/opensuse-leap-15.Dockerfile: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | FROM registry.opensuse.org/opensuse/leap:15.6 8 | 9 | RUN zypper update -y && \ 10 | zypper addrepo -fc https://download.opensuse.org/update/leap/15.6/backports/openSUSE:Backports:SLE-15-SP6:Update.repo && \ 11 | zypper install -y \ 12 | ca-certificates \ 13 | cargo \ 14 | ccache \ 15 | clang-devel \ 16 | gcc \ 17 | git \ 18 | glibc-locale \ 19 | libvirt-devel \ 20 | pkgconfig \ 21 | rust && \ 22 | zypper clean --all && \ 23 | rpm -qa | sort > /packages.txt && \ 24 | mkdir -p /usr/libexec/ccache-wrappers && \ 25 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ 26 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 27 | 28 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 29 | ENV LANG "en_US.UTF-8" 30 | -------------------------------------------------------------------------------- /ci/containers/opensuse-tumbleweed.Dockerfile: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | FROM registry.opensuse.org/opensuse/tumbleweed:latest 8 | 9 | RUN zypper dist-upgrade -y && \ 10 | zypper install -y \ 11 | ca-certificates \ 12 | cargo \ 13 | ccache \ 14 | clang-devel \ 15 | gcc \ 16 | git \ 17 | glibc-locale \ 18 | libvirt-devel \ 19 | pkgconfig \ 20 | rust && \ 21 | zypper clean --all && \ 22 | rpm -qa | sort > /packages.txt && \ 23 | mkdir -p /usr/libexec/ccache-wrappers && \ 24 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ 25 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 26 | 27 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 28 | ENV LANG "en_US.UTF-8" 29 | -------------------------------------------------------------------------------- /ci/containers/ubuntu-2204.Dockerfile: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | FROM docker.io/library/ubuntu:22.04 8 | 9 | RUN export DEBIAN_FRONTEND=noninteractive && \ 10 | apt-get update && \ 11 | apt-get install -y eatmydata && \ 12 | eatmydata apt-get dist-upgrade -y && \ 13 | eatmydata apt-get install --no-install-recommends -y \ 14 | ca-certificates \ 15 | cargo \ 16 | ccache \ 17 | gcc \ 18 | git \ 19 | libclang-dev \ 20 | libstd-rust-dev \ 21 | libvirt-dev \ 22 | locales \ 23 | pkgconf \ 24 | rust-clippy \ 25 | rustc && \ 26 | eatmydata apt-get autoremove -y && \ 27 | eatmydata apt-get autoclean -y && \ 28 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ 29 | dpkg-reconfigure locales && \ 30 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ 31 | mkdir -p /usr/libexec/ccache-wrappers && \ 32 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ 33 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 34 | 35 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 36 | ENV LANG "en_US.UTF-8" 37 | -------------------------------------------------------------------------------- /ci/containers/ubuntu-2404.Dockerfile: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | FROM docker.io/library/ubuntu:24.04 8 | 9 | RUN export DEBIAN_FRONTEND=noninteractive && \ 10 | apt-get update && \ 11 | apt-get install -y eatmydata && \ 12 | eatmydata apt-get dist-upgrade -y && \ 13 | eatmydata apt-get install --no-install-recommends -y \ 14 | ca-certificates \ 15 | cargo \ 16 | ccache \ 17 | gcc \ 18 | git \ 19 | libclang-dev \ 20 | libstd-rust-dev \ 21 | libvirt-dev \ 22 | locales \ 23 | pkgconf \ 24 | rust-clippy \ 25 | rustc && \ 26 | eatmydata apt-get autoremove -y && \ 27 | eatmydata apt-get autoclean -y && \ 28 | sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ 29 | dpkg-reconfigure locales && \ 30 | dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ 31 | mkdir -p /usr/libexec/ccache-wrappers && \ 32 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ 33 | ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc 34 | 35 | ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 36 | ENV LANG "en_US.UTF-8" 37 | -------------------------------------------------------------------------------- /ci/gitlab.yml: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | 8 | # Variables that can be set to control the behaviour of 9 | # pipelines that are run 10 | # 11 | # - RUN_PIPELINE - force creation of a CI pipeline when 12 | # pushing to a branch in a forked repository. Official 13 | # CI pipelines are triggered when merge requests are 14 | # created/updated. Setting this variable allows CI 15 | # testing prior to opening a merge request. A value 16 | # of "0" will create the pipeline but leave all jobs 17 | # to be manually started, while "1" will immediately 18 | # run all default jobs. 19 | # 20 | # - RUN_PIPELINE_UPSTREAM_ENV - same semantics as RUN_PIPELINE, 21 | # but uses the CI environment (containers) from the upstream project 22 | # rather than creating and updating a throwaway environment 23 | # Should not be used if the pushed branch includes CI container 24 | # changes. 25 | # 26 | # - RUN_CONTAINER_BUILDS - CI pipelines in upstream only 27 | # publish containers if CI file changes are detected. 28 | # Setting this variable to a non-empty value will force 29 | # re-publishing, even when no file changes are detected. 30 | # Typically to use from a scheduled job once a month. 31 | # 32 | # - RUN_UPSTREAM_NAMESPACE - the upstream namespace is 33 | # configured to default to 'libvirt'. When testing 34 | # changes to CI it might be useful to use a different 35 | # upstream. Setting this variable will override the 36 | # namespace considered to be upstream. 37 | # 38 | # These can be set as git push options 39 | # 40 | # $ git push -o ci.variable=RUN_PIPELINE=1 41 | # 42 | # Aliases can be set for common usage 43 | # 44 | # $ git config --local alias.push-ci "push -o ci.variable=RUN_PIPELINE=0" 45 | # $ git config --local alias.push-ci-now "push -o ci.variable=RUN_PIPELINE=1" 46 | # 47 | # Allowing the less verbose invocation 48 | # 49 | # $ git push-ci (create pipeline but don't start jobs) 50 | # $ git push-ci-now (create pipeline and start default jobs) 51 | # 52 | # Pipeline variables can also be set in the repository 53 | # pipeline config globally, or set against scheduled pipelines 54 | 55 | 56 | variables: 57 | RUN_UPSTREAM_NAMESPACE: libvirt 58 | CONTAINER_UPSTREAM_NAMESPACE: libvirt 59 | FF_SCRIPT_SECTIONS: 1 60 | 61 | 62 | workflow: 63 | rules: 64 | # upstream+forks: Avoid duplicate pipelines on pushes, if a MR is open 65 | - if: '$CI_PIPELINE_SOURCE == "push" && $CI_OPEN_MERGE_REQUESTS' 66 | when: never 67 | 68 | # upstream+forks: Avoid pipelines on tag pushes 69 | - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_TAG' 70 | when: never 71 | 72 | # upstream+forks: Allow pipelines in scenarios we've figured out job rules 73 | - if: '$CI_PIPELINE_SOURCE =~ /^(push|merge_request_event|api|web|schedule)$/' 74 | when: always 75 | 76 | # upstream+forks: Avoid all other pipelines 77 | - when: never 78 | 79 | 80 | debug: 81 | image: docker.io/library/alpine:3 82 | stage: sanity_checks 83 | interruptible: true 84 | needs: [] 85 | script: 86 | - printenv | sort 87 | rules: 88 | - if: '$RUN_DEBUG' 89 | when: always 90 | 91 | include: 92 | - local: '/ci/gitlab/container-templates.yml' 93 | - local: '/ci/gitlab/build-templates.yml' 94 | - local: '/ci/gitlab/sanity-checks.yml' 95 | - local: '/ci/gitlab/containers.yml' 96 | - local: '/ci/gitlab/builds.yml' 97 | -------------------------------------------------------------------------------- /ci/gitlab/builds.yml: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | 8 | # Native build jobs 9 | 10 | x86_64-alpine-320: 11 | extends: .native_build_job 12 | needs: 13 | - job: x86_64-alpine-320-container 14 | optional: true 15 | allow_failure: false 16 | variables: 17 | NAME: alpine-320 18 | TARGET_BASE_IMAGE: docker.io/library/alpine:3.20 19 | 20 | 21 | x86_64-alpine-edge: 22 | extends: .native_build_job 23 | needs: 24 | - job: x86_64-alpine-edge-container 25 | optional: true 26 | allow_failure: true 27 | variables: 28 | NAME: alpine-edge 29 | TARGET_BASE_IMAGE: docker.io/library/alpine:edge 30 | 31 | 32 | x86_64-almalinux-9: 33 | extends: .native_build_job 34 | needs: 35 | - job: x86_64-almalinux-9-container 36 | optional: true 37 | allow_failure: false 38 | variables: 39 | NAME: almalinux-9 40 | TARGET_BASE_IMAGE: docker.io/library/almalinux:9 41 | 42 | 43 | x86_64-almalinux-9-git: 44 | extends: .native_git_build_job 45 | needs: 46 | - job: x86_64-almalinux-9-container 47 | optional: true 48 | allow_failure: false 49 | variables: 50 | NAME: almalinux-9 51 | TARGET_BASE_IMAGE: docker.io/library/almalinux:9 52 | 53 | 54 | x86_64-centos-stream-9: 55 | extends: .native_build_job 56 | needs: 57 | - job: x86_64-centos-stream-9-container 58 | optional: true 59 | allow_failure: false 60 | variables: 61 | NAME: centos-stream-9 62 | TARGET_BASE_IMAGE: quay.io/centos/centos:stream9 63 | 64 | 65 | x86_64-debian-12: 66 | extends: .native_build_job 67 | needs: 68 | - job: x86_64-debian-12-container 69 | optional: true 70 | allow_failure: false 71 | variables: 72 | NAME: debian-12 73 | TARGET_BASE_IMAGE: docker.io/library/debian:12-slim 74 | 75 | 76 | x86_64-debian-sid: 77 | extends: .native_build_job 78 | needs: 79 | - job: x86_64-debian-sid-container 80 | optional: true 81 | allow_failure: true 82 | variables: 83 | NAME: debian-sid 84 | TARGET_BASE_IMAGE: docker.io/library/debian:sid-slim 85 | 86 | 87 | x86_64-fedora-40: 88 | extends: .native_build_job 89 | needs: 90 | - job: x86_64-fedora-40-container 91 | optional: true 92 | allow_failure: false 93 | variables: 94 | NAME: fedora-40 95 | TARGET_BASE_IMAGE: registry.fedoraproject.org/fedora:40 96 | 97 | 98 | x86_64-fedora-41: 99 | extends: .native_build_job 100 | needs: 101 | - job: x86_64-fedora-41-container 102 | optional: true 103 | allow_failure: false 104 | variables: 105 | CLIPPY: enable 106 | DOC: enable 107 | NAME: fedora-41 108 | TARGET_BASE_IMAGE: registry.fedoraproject.org/fedora:41 109 | 110 | 111 | x86_64-fedora-rawhide: 112 | extends: .native_build_job 113 | needs: 114 | - job: x86_64-fedora-rawhide-container 115 | optional: true 116 | allow_failure: true 117 | variables: 118 | NAME: fedora-rawhide 119 | TARGET_BASE_IMAGE: registry.fedoraproject.org/fedora:rawhide 120 | 121 | 122 | x86_64-opensuse-leap-15: 123 | extends: .native_build_job 124 | needs: 125 | - job: x86_64-opensuse-leap-15-container 126 | optional: true 127 | allow_failure: false 128 | variables: 129 | NAME: opensuse-leap-15 130 | TARGET_BASE_IMAGE: registry.opensuse.org/opensuse/leap:15.6 131 | 132 | 133 | x86_64-opensuse-tumbleweed: 134 | extends: .native_build_job 135 | needs: 136 | - job: x86_64-opensuse-tumbleweed-container 137 | optional: true 138 | allow_failure: true 139 | variables: 140 | NAME: opensuse-tumbleweed 141 | TARGET_BASE_IMAGE: registry.opensuse.org/opensuse/tumbleweed:latest 142 | 143 | 144 | x86_64-ubuntu-2204: 145 | extends: .native_build_job 146 | needs: 147 | - job: x86_64-ubuntu-2204-container 148 | optional: true 149 | allow_failure: false 150 | variables: 151 | NAME: ubuntu-2204 152 | TARGET_BASE_IMAGE: docker.io/library/ubuntu:22.04 153 | 154 | 155 | x86_64-ubuntu-2404: 156 | extends: .native_build_job 157 | needs: 158 | - job: x86_64-ubuntu-2404-container 159 | optional: true 160 | allow_failure: false 161 | variables: 162 | NAME: ubuntu-2404 163 | TARGET_BASE_IMAGE: docker.io/library/ubuntu:24.04 164 | 165 | 166 | 167 | # Cross build jobs 168 | 169 | aarch64-debian-12: 170 | extends: .cross_build_job 171 | needs: 172 | - job: aarch64-debian-12-container 173 | optional: true 174 | allow_failure: false 175 | variables: 176 | CROSS: aarch64 177 | NAME: debian-12 178 | TARGET_BASE_IMAGE: docker.io/library/debian:12-slim 179 | 180 | 181 | armv6l-debian-12: 182 | extends: .cross_build_job 183 | needs: 184 | - job: armv6l-debian-12-container 185 | optional: true 186 | allow_failure: false 187 | variables: 188 | CROSS: armv6l 189 | NAME: debian-12 190 | TARGET_BASE_IMAGE: docker.io/library/debian:12-slim 191 | 192 | 193 | armv7l-debian-12: 194 | extends: .cross_build_job 195 | needs: 196 | - job: armv7l-debian-12-container 197 | optional: true 198 | allow_failure: false 199 | variables: 200 | CROSS: armv7l 201 | NAME: debian-12 202 | TARGET_BASE_IMAGE: docker.io/library/debian:12-slim 203 | 204 | 205 | i686-debian-12: 206 | extends: .cross_build_job 207 | needs: 208 | - job: i686-debian-12-container 209 | optional: true 210 | allow_failure: false 211 | variables: 212 | CROSS: i686 213 | NAME: debian-12 214 | TARGET_BASE_IMAGE: docker.io/library/debian:12-slim 215 | 216 | 217 | mips64el-debian-12: 218 | extends: .cross_build_job 219 | needs: 220 | - job: mips64el-debian-12-container 221 | optional: true 222 | allow_failure: false 223 | variables: 224 | CROSS: mips64el 225 | NAME: debian-12 226 | TARGET_BASE_IMAGE: docker.io/library/debian:12-slim 227 | 228 | 229 | mipsel-debian-12: 230 | extends: .cross_build_job 231 | needs: 232 | - job: mipsel-debian-12-container 233 | optional: true 234 | allow_failure: false 235 | variables: 236 | CROSS: mipsel 237 | NAME: debian-12 238 | TARGET_BASE_IMAGE: docker.io/library/debian:12-slim 239 | 240 | 241 | ppc64le-debian-12: 242 | extends: .cross_build_job 243 | needs: 244 | - job: ppc64le-debian-12-container 245 | optional: true 246 | allow_failure: false 247 | variables: 248 | CROSS: ppc64le 249 | NAME: debian-12 250 | TARGET_BASE_IMAGE: docker.io/library/debian:12-slim 251 | 252 | 253 | s390x-debian-12: 254 | extends: .cross_build_job 255 | needs: 256 | - job: s390x-debian-12-container 257 | optional: true 258 | allow_failure: false 259 | variables: 260 | CROSS: s390x 261 | NAME: debian-12 262 | TARGET_BASE_IMAGE: docker.io/library/debian:12-slim 263 | 264 | 265 | # Native cirrus build jobs 266 | 267 | x86_64-freebsd-13: 268 | extends: .cirrus_build_job 269 | needs: [] 270 | allow_failure: 271 | exit_codes: 3 272 | variables: 273 | CIRRUS_VM_IMAGE_NAME: freebsd-13-4 274 | CIRRUS_VM_IMAGE_SELECTOR: image_family 275 | CIRRUS_VM_INSTANCE_TYPE: freebsd_instance 276 | INSTALL_COMMAND: pkg install -y 277 | NAME: freebsd-13 278 | UPDATE_COMMAND: pkg update 279 | UPGRADE_COMMAND: pkg upgrade -y 280 | 281 | 282 | x86_64-freebsd-14: 283 | extends: .cirrus_build_job 284 | needs: [] 285 | allow_failure: 286 | exit_codes: 3 287 | variables: 288 | CIRRUS_VM_IMAGE_NAME: freebsd-14-2 289 | CIRRUS_VM_IMAGE_SELECTOR: image_family 290 | CIRRUS_VM_INSTANCE_TYPE: freebsd_instance 291 | INSTALL_COMMAND: pkg install -y 292 | NAME: freebsd-14 293 | UPDATE_COMMAND: pkg update 294 | UPGRADE_COMMAND: pkg upgrade -y 295 | 296 | 297 | aarch64-macos-14: 298 | extends: .cirrus_build_job 299 | needs: [] 300 | allow_failure: 301 | exit_codes: 3 302 | variables: 303 | CIRRUS_VM_IMAGE_NAME: ghcr.io/cirruslabs/macos-runner:sonoma 304 | CIRRUS_VM_IMAGE_SELECTOR: image 305 | CIRRUS_VM_INSTANCE_TYPE: macos_instance 306 | INSTALL_COMMAND: brew install 307 | NAME: macos-14 308 | UPDATE_COMMAND: brew update 309 | UPGRADE_COMMAND: brew upgrade 310 | -------------------------------------------------------------------------------- /ci/gitlab/container-templates.yml: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | 8 | # We want to publish containers with tag 'latest': 9 | # 10 | # - In upstream, for push to default branch with CI changes. 11 | # - In upstream, on request, for scheduled/manual pipelines 12 | # against default branch 13 | # 14 | # Note: never publish from merge requests since they have non-committed code 15 | # 16 | .container_job: 17 | image: docker:latest 18 | stage: containers 19 | interruptible: false 20 | needs: [] 21 | services: 22 | - docker:dind 23 | before_script: 24 | - export TAG="$CI_REGISTRY_IMAGE/ci-$NAME:latest" 25 | - docker info 26 | - docker login "$CI_REGISTRY" -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" 27 | script: 28 | - docker build --tag "$TAG" -f "ci/containers/$NAME.Dockerfile" ci/containers ; 29 | - docker push "$TAG" 30 | after_script: 31 | - docker logout 32 | rules: 33 | # upstream: publish containers if there were CI changes on the default branch 34 | - if: '$CI_PROJECT_NAMESPACE == $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' 35 | when: on_success 36 | changes: 37 | - ci/gitlab/container-templates.yml 38 | - ci/containers/$NAME.Dockerfile 39 | 40 | # upstream: allow force re-publishing containers on default branch for web/api/scheduled pipelines 41 | - if: '$CI_PROJECT_NAMESPACE == $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE =~ /(web|api|schedule)/ && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH && $RUN_CONTAINER_BUILDS == "1"' 42 | when: on_success 43 | 44 | # upstream+forks: that's all folks 45 | - when: never 46 | -------------------------------------------------------------------------------- /ci/gitlab/containers.yml: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | 8 | # Native container jobs 9 | 10 | x86_64-alpine-320-container: 11 | extends: .container_job 12 | allow_failure: false 13 | variables: 14 | NAME: alpine-320 15 | 16 | 17 | x86_64-alpine-edge-container: 18 | extends: .container_job 19 | allow_failure: true 20 | variables: 21 | NAME: alpine-edge 22 | 23 | 24 | x86_64-almalinux-9-container: 25 | extends: .container_job 26 | allow_failure: false 27 | variables: 28 | NAME: almalinux-9 29 | 30 | 31 | x86_64-centos-stream-9-container: 32 | extends: .container_job 33 | allow_failure: false 34 | variables: 35 | NAME: centos-stream-9 36 | 37 | 38 | x86_64-debian-12-container: 39 | extends: .container_job 40 | allow_failure: false 41 | variables: 42 | NAME: debian-12 43 | 44 | 45 | x86_64-debian-sid-container: 46 | extends: .container_job 47 | allow_failure: true 48 | variables: 49 | NAME: debian-sid 50 | 51 | 52 | x86_64-fedora-40-container: 53 | extends: .container_job 54 | allow_failure: false 55 | variables: 56 | NAME: fedora-40 57 | 58 | 59 | x86_64-fedora-41-container: 60 | extends: .container_job 61 | allow_failure: false 62 | variables: 63 | NAME: fedora-41 64 | 65 | 66 | x86_64-fedora-rawhide-container: 67 | extends: .container_job 68 | allow_failure: true 69 | variables: 70 | NAME: fedora-rawhide 71 | 72 | 73 | x86_64-opensuse-leap-15-container: 74 | extends: .container_job 75 | allow_failure: false 76 | variables: 77 | NAME: opensuse-leap-15 78 | 79 | 80 | x86_64-opensuse-tumbleweed-container: 81 | extends: .container_job 82 | allow_failure: true 83 | variables: 84 | NAME: opensuse-tumbleweed 85 | 86 | 87 | x86_64-ubuntu-2204-container: 88 | extends: .container_job 89 | allow_failure: false 90 | variables: 91 | NAME: ubuntu-2204 92 | 93 | 94 | x86_64-ubuntu-2404-container: 95 | extends: .container_job 96 | allow_failure: false 97 | variables: 98 | NAME: ubuntu-2404 99 | 100 | 101 | 102 | # Cross container jobs 103 | 104 | aarch64-debian-12-container: 105 | extends: .container_job 106 | allow_failure: false 107 | variables: 108 | NAME: debian-12-cross-aarch64 109 | 110 | 111 | armv6l-debian-12-container: 112 | extends: .container_job 113 | allow_failure: false 114 | variables: 115 | NAME: debian-12-cross-armv6l 116 | 117 | 118 | armv7l-debian-12-container: 119 | extends: .container_job 120 | allow_failure: false 121 | variables: 122 | NAME: debian-12-cross-armv7l 123 | 124 | 125 | i686-debian-12-container: 126 | extends: .container_job 127 | allow_failure: false 128 | variables: 129 | NAME: debian-12-cross-i686 130 | 131 | 132 | mips64el-debian-12-container: 133 | extends: .container_job 134 | allow_failure: false 135 | variables: 136 | NAME: debian-12-cross-mips64el 137 | 138 | 139 | mipsel-debian-12-container: 140 | extends: .container_job 141 | allow_failure: false 142 | variables: 143 | NAME: debian-12-cross-mipsel 144 | 145 | 146 | ppc64le-debian-12-container: 147 | extends: .container_job 148 | allow_failure: false 149 | variables: 150 | NAME: debian-12-cross-ppc64le 151 | 152 | 153 | s390x-debian-12-container: 154 | extends: .container_job 155 | allow_failure: false 156 | variables: 157 | NAME: debian-12-cross-s390x 158 | -------------------------------------------------------------------------------- /ci/gitlab/sanity-checks.yml: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTO-GENERATED 2 | # 3 | # $ lcitool manifest ci/manifest.yml 4 | # 5 | # https://gitlab.com/libvirt/libvirt-ci 6 | 7 | 8 | check-dco: 9 | stage: sanity_checks 10 | needs: [] 11 | image: registry.gitlab.com/libvirt/libvirt-ci/check-dco:latest 12 | interruptible: true 13 | script: 14 | - /check-dco "$RUN_UPSTREAM_NAMESPACE" 15 | rules: 16 | # upstream+forks: Run pipelines on MR 17 | - if: '$CI_PIPELINE_SOURCE =~ "merge_request_event"' 18 | when: on_success 19 | 20 | # forks: pushes to branches with pipeline requested (including upstream env pipelines) 21 | - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH && $RUN_PIPELINE == "0"' 22 | when: manual 23 | - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH && $RUN_PIPELINE == "1"' 24 | when: on_success 25 | - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH && $RUN_PIPELINE_UPSTREAM_ENV == "0"' 26 | when: manual 27 | - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH && $RUN_PIPELINE_UPSTREAM_ENV == "1"' 28 | when: on_success 29 | 30 | # upstream+forks: that's all folks 31 | - when: never 32 | variables: 33 | GIT_DEPTH: 1000 34 | 35 | 36 | .code_format: 37 | stage: sanity_checks 38 | image: registry.gitlab.com/libvirt/libvirt-ci/$NAME:latest 39 | interruptible: true 40 | needs: [] 41 | script: 42 | - /$NAME 43 | rules: 44 | # upstream+forks: Run pipelines on MR, web, api & scheduled 45 | - if: '$CI_PIPELINE_SOURCE =~ /(web|api|schedule|merge_request_event)/' 46 | when: on_success 47 | 48 | # forks: pushes to branches with pipeline requested (including upstream env pipelines) 49 | - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH && $RUN_PIPELINE == "0"' 50 | when: manual 51 | - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH && $RUN_PIPELINE == "1"' 52 | when: on_success 53 | - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH && $RUN_PIPELINE_UPSTREAM_ENV == "0"' 54 | when: manual 55 | - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH && $RUN_PIPELINE_UPSTREAM_ENV == "1"' 56 | when: on_success 57 | 58 | # upstream+forks: that's all folks 59 | - when: never 60 | artifacts: 61 | paths: 62 | - $NAME.$EXT 63 | expire_in: 1 week 64 | when: on_failure 65 | 66 | 67 | cargo-fmt: 68 | extends: .code_format 69 | variables: 70 | EXT: txt 71 | NAME: cargo-fmt 72 | -------------------------------------------------------------------------------- /ci/lcitool/projects/libvirt-rust.yml: -------------------------------------------------------------------------------- 1 | --- 2 | packages: 3 | - cargo 4 | - ccache 5 | - clippy 6 | - gcc 7 | - libclang 8 | - pkg-config 9 | - rust 10 | - rust-std 11 | -------------------------------------------------------------------------------- /ci/manifest.yml: -------------------------------------------------------------------------------- 1 | projects: 2 | - libvirt-rust 3 | - https://gitlab.com/libvirt/libvirt/-/raw/master/ci/lcitool/projects/libvirt+dist.yml 4 | 5 | gitlab: 6 | namespace: libvirt 7 | project: libvirt-rust 8 | jobs: 9 | cargo-fmt: true 10 | 11 | targets: 12 | 13 | alpine-320: x86_64 14 | 15 | alpine-edge: 16 | jobs: 17 | - arch: x86_64 18 | allow-failure: true 19 | 20 | almalinux-9: 21 | projects: 22 | - libvirt-rust 23 | - https://gitlab.com/libvirt/libvirt/-/raw/master/ci/lcitool/projects/libvirt+minimal.yml 24 | - https://gitlab.com/libvirt/libvirt/-/raw/master/ci/lcitool/projects/libvirt+dist.yml 25 | 26 | jobs: 27 | - arch: x86_64 28 | - arch: x86_64 29 | template: .native_git_build_job 30 | suffix: -git 31 | 32 | centos-stream-9: x86_64 33 | 34 | debian-12: 35 | jobs: 36 | - arch: x86_64 37 | - arch: aarch64 38 | - arch: armv6l 39 | - arch: armv7l 40 | - arch: i686 41 | - arch: mips64el 42 | - arch: mipsel 43 | - arch: ppc64le 44 | - arch: s390x 45 | 46 | debian-sid: 47 | jobs: 48 | - arch: x86_64 49 | allow-failure: true 50 | 51 | fedora-40: x86_64 52 | 53 | fedora-41: 54 | jobs: 55 | - arch: x86_64 56 | variables: 57 | CLIPPY: enable 58 | DOC: enable 59 | 60 | fedora-rawhide: 61 | jobs: 62 | - arch: x86_64 63 | allow-failure: true 64 | 65 | freebsd-13: x86_64 66 | 67 | freebsd-14: x86_64 68 | 69 | opensuse-leap-15: x86_64 70 | 71 | opensuse-tumbleweed: 72 | jobs: 73 | - arch: x86_64 74 | allow-failure: true 75 | 76 | macos-14: aarch64 77 | 78 | ubuntu-2204: x86_64 79 | 80 | ubuntu-2404: x86_64 81 | -------------------------------------------------------------------------------- /examples/auth.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library. If not, see 14 | * . 15 | * 16 | * Sahid Orentino Ferdjaoui 17 | */ 18 | 19 | //! A trivial example to ilustract how to setup a connection auth 20 | //! hanlder. 21 | //! 22 | //! By default the program try to connect to 23 | //! 'test+tcp://127.0.0.1/default' 24 | //! 25 | //! An example of libvirtd configuration for sasl: 26 | //! 27 | //! ``` 28 | //! listen_tls=0 29 | //! listen_tcp=1 30 | //! auth_tcp=sasl 31 | //! listen_addr="127.0.0.1" 32 | //! ``` 33 | //! 34 | //! Then to create user nad password: 35 | //! 36 | //! ``` 37 | //! saslpasswd2 -a libvirt user 38 | //! ``` 39 | 40 | use std::{env, io}; 41 | 42 | use virt::connect::{Connect, ConnectAuth, ConnectCredential}; 43 | use virt::error::clear_error_callback; 44 | use virt::sys; 45 | 46 | fn main() { 47 | clear_error_callback(); 48 | 49 | let uri = env::args().nth(1); 50 | 51 | fn callback(creds: &mut Vec) { 52 | for cred in creds { 53 | let mut input = String::new(); 54 | 55 | println!("{}:", cred.prompt); 56 | match cred.typed as u32 { 57 | sys::VIR_CRED_AUTHNAME => { 58 | io::stdin().read_line(&mut input).expect(""); 59 | cred.result = Some(String::from(input.trim())); 60 | } 61 | sys::VIR_CRED_PASSPHRASE => { 62 | io::stdin().read_line(&mut input).expect(""); 63 | cred.result = Some(String::from(input.trim())); 64 | } 65 | _ => { 66 | panic!("Should not be here..."); 67 | } 68 | } 69 | } 70 | } 71 | let mut auth = ConnectAuth::new( 72 | vec![sys::VIR_CRED_AUTHNAME, sys::VIR_CRED_PASSPHRASE], 73 | callback, 74 | ); 75 | 76 | println!("Attempting to connect to hypervisor: '{:?}'...", uri); 77 | let mut conn = match Connect::open_auth(uri.as_deref(), &mut auth, 0) { 78 | Ok(c) => { 79 | println!("Connected"); 80 | c 81 | } 82 | Err(e) => panic!("Not connected: {}", e), 83 | }; 84 | if let Err(e) = conn.close() { 85 | panic!("Failed to disconnect from hypervisor: {}", e); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /examples/console-read.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library. If not, see 14 | * . 15 | * 16 | * Ryosuke Yasuoka 17 | */ 18 | 19 | //! This file contains trivial example code to output console log. This file 20 | //! connects to the running VM and waits for logs as a console client. 21 | //! 1st arg is URI, 2nd arg is the name of VM, and 3rd arg is a console name. 22 | //! If the console name is omitted, then the first console will be opened. 23 | //! 24 | //! Examples 25 | //! ``` 26 | //! $ cargo run --example console-read -- 'qemu:///system' 'mytestvm' 'serial0' 27 | //! ``` 28 | //! 29 | //! Largely inspired by libvirt-python/examples/consolecallback.py 30 | 31 | use std::env; 32 | use virt::{ 33 | connect::Connect, 34 | domain::Domain, 35 | error::clear_error_callback, 36 | stream::Stream, 37 | sys::{ 38 | virEventRegisterDefaultImpl, virEventRunDefaultImpl, virStreamEventType, 39 | VIR_DOMAIN_CONSOLE_FORCE, VIR_STREAM_EVENT_READABLE, VIR_STREAM_NONBLOCK, 40 | }, 41 | }; 42 | 43 | fn read_callback(stream: &Stream, event_type: virStreamEventType) { 44 | if event_type == VIR_STREAM_EVENT_READABLE { 45 | let mut buf = vec![0; 1024]; 46 | match stream.recv(buf.as_mut_slice()) { 47 | Ok(t) => { 48 | if let Ok(received_data) = std::str::from_utf8(&buf[..t]) { 49 | print!("{}", received_data); 50 | } else { 51 | eprint!("Invalid UTF-8 sequence received."); 52 | } 53 | } 54 | Err(e) => { 55 | println!("{}", e); 56 | } 57 | } 58 | } 59 | } 60 | 61 | fn event_register_default_impl() { 62 | unsafe { virEventRegisterDefaultImpl() }; 63 | } 64 | 65 | fn event_run_default_impl() { 66 | unsafe { virEventRunDefaultImpl() }; 67 | } 68 | 69 | fn main() { 70 | clear_error_callback(); 71 | event_register_default_impl(); 72 | 73 | let uri = env::args().nth(1); 74 | let name = env::args().nth(2).unwrap(); 75 | let dev_name = env::args().nth(3); 76 | 77 | let conn = Connect::open(uri.as_deref()).unwrap(); 78 | let dom = Domain::lookup_by_name(&conn, &name).unwrap(); 79 | let mut st = Stream::new(&conn, VIR_STREAM_NONBLOCK).unwrap(); 80 | dom.open_console(dev_name.as_deref(), &st, VIR_DOMAIN_CONSOLE_FORCE) 81 | .unwrap(); 82 | 83 | st.event_add_callback(VIR_STREAM_EVENT_READABLE, move |st, event_type| { 84 | read_callback(st, event_type) 85 | }) 86 | .unwrap(); 87 | 88 | loop { 89 | event_run_default_impl(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /examples/guest_agent.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use virt::connect::Connect; 3 | use virt::domain::Domain; 4 | use virt::sys; 5 | 6 | fn main() { 7 | let uri = env::args().nth(1); 8 | let name = env::args().nth(2).expect("Domain name requried"); 9 | 10 | let conn = Connect::open(uri.as_deref()).unwrap(); 11 | 12 | let domain = Domain::lookup_by_name(&conn, &name).unwrap(); 13 | let result = domain.qemu_agent_command( 14 | "{\"execute\": \"guest-info\"}", 15 | sys::VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK, 16 | 0, 17 | ); 18 | match result { 19 | Ok(r) => println!("Result: {}", r), 20 | Err(e) => eprintln!("Error: {}", e), 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/hello.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library. If not, see 14 | * . 15 | * 16 | * Sahid Orentino Ferdjaoui 17 | */ 18 | 19 | //! This file contains trivial example code to connect to the running 20 | //! hypervisor and gather a few bits of information about domains. 21 | //! Similar API's exist for storage pools, networks, and interfaces. 22 | //! 23 | //! Largely inspired by hellolibvirt.c 24 | 25 | use std::env; 26 | 27 | use virt::connect::Connect; 28 | use virt::error::{clear_error_callback, Error}; 29 | use virt::sys; 30 | 31 | fn show_hypervisor_info(conn: &Connect) -> Result<(), Error> { 32 | if let Ok(hv_type) = conn.get_type() { 33 | if let Ok(mut hv_ver) = conn.get_hyp_version() { 34 | let major = hv_ver / 1000000; 35 | hv_ver %= 1000000; 36 | let minor = hv_ver / 1000; 37 | let release = hv_ver % 1000; 38 | println!( 39 | "Hypervisor: '{}' version: {}.{}.{}", 40 | hv_type, major, minor, release 41 | ); 42 | return Ok(()); 43 | } 44 | } 45 | Err(Error::last_error()) 46 | } 47 | 48 | fn show_domains(conn: &Connect) -> Result<(), Error> { 49 | let flags = sys::VIR_CONNECT_LIST_DOMAINS_ACTIVE | sys::VIR_CONNECT_LIST_DOMAINS_INACTIVE; 50 | 51 | if let Ok(num_active_domains) = conn.num_of_domains() { 52 | if let Ok(num_inactive_domains) = conn.num_of_defined_domains() { 53 | println!( 54 | "There are {} active and {} inactive domains", 55 | num_active_domains, num_inactive_domains 56 | ); 57 | /* Return a list of all active and inactive domains. Using this API 58 | * instead of virConnectListDomains() and virConnectListDefinedDomains() 59 | * is preferred since it "solves" an inherit race between separated API 60 | * calls if domains are started or stopped between calls */ 61 | if let Ok(doms) = conn.list_all_domains(flags) { 62 | for dom in doms { 63 | let id = dom.get_id().unwrap_or(0); 64 | let name = dom.get_name().unwrap_or_else(|_| String::from("no-name")); 65 | let active = dom.is_active().unwrap_or(false); 66 | println!("ID: {}, Name: {}, Active: {}", id, name, active); 67 | if let Ok(dinfo) = dom.get_info() { 68 | println!("Domain info:"); 69 | println!(" State: {}", dinfo.state); 70 | println!(" Max Memory: {}", dinfo.max_mem); 71 | println!(" Memory: {}", dinfo.memory); 72 | println!(" CPUs: {}", dinfo.nr_virt_cpu); 73 | println!(" CPU Time: {}", dinfo.cpu_time); 74 | } 75 | if let Ok(memtune) = dom.get_memory_parameters(0) { 76 | println!("Memory tune:"); 77 | println!(" Hard Limit: {}", memtune.hard_limit.unwrap_or(0)); 78 | println!(" Soft Limit: {}", memtune.soft_limit.unwrap_or(0)); 79 | println!(" Min Guarantee: {}", memtune.min_guarantee.unwrap_or(0)); 80 | println!( 81 | " Swap Hard Limit: {}", 82 | memtune.swap_hard_limit.unwrap_or(0) 83 | ); 84 | } 85 | if let Ok(numa) = dom.get_numa_parameters(0) { 86 | println!("NUMA:"); 87 | println!(" Node Set: {}", numa.node_set.unwrap_or_default()); 88 | println!(" Mode: {}", numa.mode.unwrap_or(0)); 89 | } 90 | 91 | if let Ok((sched_type, nparams)) = dom.get_scheduler_type() { 92 | println!("SchedType: {}, nparams: {}", sched_type, nparams); 93 | } 94 | 95 | if let Ok(sched_info) = dom.get_scheduler_parameters() { 96 | println!("Schedule Information:"); 97 | println!("\tScheduler\t: {}", sched_info.scheduler_type); 98 | if let Some(shares) = sched_info.cpu_shares { 99 | println!("\tcpu_shares\t: {}", shares); 100 | } 101 | if let Some(period) = sched_info.vcpu_bw.period { 102 | println!("\tvcpu_period\t: {}", period); 103 | } 104 | if let Some(quota) = sched_info.vcpu_bw.quota { 105 | println!("\tvcpu_quota\t: {}", quota); 106 | } 107 | if let Some(period) = sched_info.emulator_bw.period { 108 | println!("\temulator_period\t: {}", period); 109 | } 110 | if let Some(quota) = sched_info.emulator_bw.quota { 111 | println!("\temulator_quota\t: {}", quota); 112 | } 113 | if let Some(period) = sched_info.global_bw.period { 114 | println!("\tglobal_period\t: {}", period); 115 | } 116 | if let Some(quota) = sched_info.global_bw.quota { 117 | println!("\tglobal_quota\t: {}", quota); 118 | } 119 | if let Some(period) = sched_info.global_bw.period { 120 | println!("\tiothread_period\t: {}", period); 121 | } 122 | if let Some(quota) = sched_info.global_bw.quota { 123 | println!("\tiothread_quota\t: {}", quota); 124 | } 125 | } 126 | } 127 | } 128 | return Ok(()); 129 | } 130 | } 131 | Err(Error::last_error()) 132 | } 133 | 134 | fn main() { 135 | clear_error_callback(); 136 | 137 | let uri = env::args().nth(1); 138 | println!("Attempting to connect to hypervisor: '{:?}'", uri); 139 | 140 | let conn = match Connect::open(uri.as_deref()) { 141 | Ok(c) => c, 142 | Err(e) => panic!("No connection to hypervisor: {}", e), 143 | }; 144 | 145 | match conn.get_uri() { 146 | Ok(u) => println!("Connected to hypervisor at '{}'", u), 147 | Err(e) => { 148 | disconnect(conn); 149 | panic!("Failed to get URI for hypervisor connection: {}", e); 150 | } 151 | }; 152 | 153 | if let Err(e) = show_hypervisor_info(&conn) { 154 | disconnect(conn); 155 | panic!("Failed to show hypervisor info: {}", e); 156 | } 157 | 158 | if let Err(e) = show_domains(&conn) { 159 | disconnect(conn); 160 | panic!("Failed to show domains info: {}", e); 161 | } 162 | 163 | fn disconnect(mut conn: Connect) { 164 | if let Err(e) = conn.close() { 165 | panic!("Failed to disconnect from hypervisor: {}", e); 166 | } 167 | println!("Disconnected from hypervisor"); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /examples/migrate.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library. If not, see 14 | * . 15 | * 16 | * Sahid Orentino Ferdjaoui 17 | */ 18 | 19 | //! An example of migrating domain 20 | 21 | use std::env; 22 | 23 | use virt::connect::Connect; 24 | use virt::domain::Domain; 25 | use virt::domain::MigrateParameters; 26 | use virt::error::clear_error_callback; 27 | use virt::sys; 28 | 29 | fn main() { 30 | clear_error_callback(); 31 | 32 | if env::args().len() < 4 { 33 | panic!( 34 | "Usage: {} ", 35 | env::args().next().unwrap() 36 | ); 37 | } 38 | 39 | let src_uri = env::args().nth(1); 40 | let dst_uri = env::args().nth(2); 41 | let dname = env::args().nth(3).unwrap(); 42 | 43 | println!( 44 | "Attempting to migrate domain '{}' from '{:?}' to '{:?}'...", 45 | dname, src_uri, dst_uri 46 | ); 47 | 48 | let mut conn = match Connect::open(src_uri.as_deref()) { 49 | Ok(c) => c, 50 | Err(e) => panic!("No connection to source hypervisor: {}", e), 51 | }; 52 | 53 | let mut dconn = match Connect::open(dst_uri.as_deref()) { 54 | Ok(c) => c, 55 | Err(e) => panic!("No connection to destination hypervisor: {}", e), 56 | }; 57 | 58 | if let Ok(dom) = Domain::lookup_by_name(&conn, &dname) { 59 | let flags = sys::VIR_MIGRATE_LIVE; 60 | let migrate_parameters = MigrateParameters { 61 | dest_name: Some(dname.clone()), 62 | ..Default::default() 63 | }; 64 | if let Ok(new_dom) = dom.migrate3(&dconn, migrate_parameters, flags) { 65 | if let Ok(job_stats) = new_dom.get_job_stats(sys::VIR_DOMAIN_JOB_STATS_COMPLETED) { 66 | println!( 67 | "Migration completed in {}ms", 68 | job_stats 69 | .time_elapsed 70 | .map(|time| time.to_string()) 71 | .unwrap_or("?".into()) 72 | ); 73 | } 74 | } 75 | } 76 | 77 | if let Err(e) = conn.close() { 78 | panic!("Failed to disconnect from source hypervisor: {}", e); 79 | } 80 | 81 | if let Err(e) = dconn.close() { 82 | panic!("Failed to disconnect from destination hypervisor: {}", e); 83 | } 84 | println!("Disconnected from source and destination hypervisors"); 85 | } 86 | -------------------------------------------------------------------------------- /examples/suspend.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library. If not, see 14 | * . 15 | * 16 | * Sahid Orentino Ferdjaoui 17 | */ 18 | 19 | //! This file contains trivial example code to suspend/resume domains 20 | //! 21 | //! Largely inspired by libvirt/examples/suspend.c 22 | 23 | use std::{env, thread, time}; 24 | 25 | use virt::connect::Connect; 26 | use virt::domain::Domain; 27 | use virt::error::{clear_error_callback, Error}; 28 | use virt::sys; 29 | 30 | fn suspend_and_resume(conn: &Connect, name: &str, sec: u64) -> Result<(), Error> { 31 | if let Ok(dom) = Domain::lookup_by_name(conn, name) { 32 | if dom.suspend().is_ok() { 33 | println!("Domain '{:?}' suspended, info: {:?}", name, dom.get_info()); 34 | thread::sleep(time::Duration::from_millis(sec * 1000)); 35 | 36 | if dom.resume().is_ok() { 37 | println!("Domain '{:?}' resumed, info: {:?}", name, dom.get_info()); 38 | return Ok(()); 39 | } 40 | } 41 | } 42 | Err(Error::last_error()) 43 | } 44 | 45 | fn fetch_domains(conn: &Connect) -> Result<(), Error> { 46 | let flags = sys::VIR_CONNECT_LIST_DOMAINS_ACTIVE; 47 | if let Ok(doms) = conn.list_all_domains(flags) { 48 | println!("Running domains:"); 49 | println!("----------------"); 50 | for dom in doms { 51 | println!( 52 | "{}", 53 | dom.get_name().unwrap_or_else(|_| String::from("no-name")) 54 | ); 55 | } 56 | return Ok(()); 57 | } 58 | Err(Error::last_error()) 59 | } 60 | 61 | fn main() { 62 | clear_error_callback(); 63 | 64 | let uri = env::args().nth(1); 65 | let name = env::args().nth(2).unwrap_or_default(); 66 | 67 | println!("Attempting to connect to hypervisor: '{:?}'", uri); 68 | let mut conn = match Connect::open(uri.as_deref()) { 69 | Ok(c) => c, 70 | Err(e) => panic!("No connection to hypervisor: {}", e), 71 | }; 72 | 73 | if name.is_empty() { 74 | if let Err(e) = fetch_domains(&conn) { 75 | println!("Failed to fetch domains: {}", e); 76 | } 77 | } else if let Err(e) = suspend_and_resume(&conn, &name, 1) { 78 | println!("Failed to suspend/resume: {}", e); 79 | } 80 | 81 | if let Err(e) = conn.close() { 82 | panic!("Failed to disconnect from hypervisor: {}", e); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/domain_snapshot.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library. If not, see 14 | * . 15 | * 16 | * Sahid Orentino Ferdjaoui 17 | */ 18 | 19 | use std::ffi::CString; 20 | use std::{ptr, str}; 21 | 22 | use crate::connect::Connect; 23 | use crate::domain::Domain; 24 | use crate::error::Error; 25 | 26 | /// Provides APIs for the management of domain snapshots. 27 | /// 28 | /// See 29 | #[derive(Debug)] 30 | pub struct DomainSnapshot { 31 | ptr: Option, 32 | } 33 | 34 | unsafe impl Send for DomainSnapshot {} 35 | unsafe impl Sync for DomainSnapshot {} 36 | 37 | impl Drop for DomainSnapshot { 38 | fn drop(&mut self) { 39 | if self.ptr.is_some() { 40 | if let Err(e) = self.free() { 41 | panic!("Unable to drop memory for DomainSnapshot: {}", e) 42 | } 43 | } 44 | } 45 | } 46 | 47 | impl Clone for DomainSnapshot { 48 | /// Creates a copy of a domain snapshot. 49 | /// 50 | /// Increments the internal reference counter on the given 51 | /// snapshot. For each call to this method, there shall be a 52 | /// corresponding call to [`free()`]. 53 | /// 54 | /// [`free()`]: DomainSnapshot::free 55 | fn clone(&self) -> Self { 56 | self.add_ref().unwrap() 57 | } 58 | } 59 | 60 | impl DomainSnapshot { 61 | /// # Safety 62 | /// 63 | /// The caller must ensure that the pointer is valid. 64 | pub unsafe fn from_ptr(ptr: sys::virDomainSnapshotPtr) -> DomainSnapshot { 65 | DomainSnapshot { ptr: Some(ptr) } 66 | } 67 | 68 | fn add_ref(&self) -> Result { 69 | unsafe { 70 | if sys::virDomainSnapshotRef(self.as_ptr()) == -1 { 71 | return Err(Error::last_error()); 72 | } 73 | } 74 | 75 | Ok(unsafe { DomainSnapshot::from_ptr(self.as_ptr()) }) 76 | } 77 | 78 | pub fn as_ptr(&self) -> sys::virDomainSnapshotPtr { 79 | self.ptr.unwrap() 80 | } 81 | 82 | pub fn get_connect(&self) -> Result { 83 | let ptr = unsafe { sys::virDomainSnapshotGetConnect(self.as_ptr()) }; 84 | if ptr.is_null() { 85 | return Err(Error::last_error()); 86 | } 87 | Ok(unsafe { Connect::from_ptr(ptr) }) 88 | } 89 | 90 | pub fn get_domain(&self) -> Result { 91 | let ptr = unsafe { sys::virDomainSnapshotGetDomain(self.as_ptr()) }; 92 | if ptr.is_null() { 93 | return Err(Error::last_error()); 94 | } 95 | Ok(unsafe { Domain::from_ptr(ptr) }) 96 | } 97 | 98 | pub fn get_name(&self) -> Result { 99 | let n = unsafe { sys::virDomainSnapshotGetName(self.as_ptr()) }; 100 | if n.is_null() { 101 | return Err(Error::last_error()); 102 | } 103 | Ok(unsafe { c_chars_to_string!(n, nofree) }) 104 | } 105 | 106 | /// Get a handle to a named snapshot. 107 | pub fn lookup_by_name(dom: &Domain, name: &str, flags: u32) -> Result { 108 | let name_buf = CString::new(name).unwrap(); 109 | let ptr = unsafe { 110 | sys::virDomainSnapshotLookupByName( 111 | dom.as_ptr(), 112 | name_buf.as_ptr(), 113 | flags as libc::c_uint, 114 | ) 115 | }; 116 | if ptr.is_null() { 117 | return Err(Error::last_error()); 118 | } 119 | Ok(unsafe { DomainSnapshot::from_ptr(ptr) }) 120 | } 121 | 122 | /// Dump the XML of a snapshot. 123 | pub fn get_xml_desc(&self, flags: u32) -> Result { 124 | let xml = unsafe { sys::virDomainSnapshotGetXMLDesc(self.as_ptr(), flags as libc::c_uint) }; 125 | if xml.is_null() { 126 | return Err(Error::last_error()); 127 | } 128 | Ok(unsafe { c_chars_to_string!(xml) }) 129 | } 130 | 131 | pub fn create_xml(dom: &Domain, xml: &str, flags: u32) -> Result { 132 | let xml_buf = CString::new(xml).unwrap(); 133 | let ptr = unsafe { 134 | sys::virDomainSnapshotCreateXML(dom.as_ptr(), xml_buf.as_ptr(), flags as libc::c_uint) 135 | }; 136 | if ptr.is_null() { 137 | return Err(Error::last_error()); 138 | } 139 | Ok(unsafe { DomainSnapshot::from_ptr(ptr) }) 140 | } 141 | 142 | /// Get a handle to the current snapshot 143 | pub fn current(dom: &Domain, flags: u32) -> Result { 144 | let ptr = unsafe { sys::virDomainSnapshotCurrent(dom.as_ptr(), flags as libc::c_uint) }; 145 | if ptr.is_null() { 146 | return Err(Error::last_error()); 147 | } 148 | Ok(unsafe { DomainSnapshot::from_ptr(ptr) }) 149 | } 150 | 151 | /// Get a handle to the parent snapshot, if one exists. 152 | pub fn get_parent(&self, flags: u32) -> Result { 153 | let ptr = unsafe { sys::virDomainSnapshotGetParent(self.as_ptr(), flags as libc::c_uint) }; 154 | if ptr.is_null() { 155 | return Err(Error::last_error()); 156 | } 157 | Ok(unsafe { DomainSnapshot::from_ptr(ptr) }) 158 | } 159 | 160 | /// Revert a snapshot. 161 | pub fn revert(&self, flags: u32) -> Result<(), Error> { 162 | let ret = unsafe { sys::virDomainRevertToSnapshot(self.as_ptr(), flags as libc::c_uint) }; 163 | if ret == -1 { 164 | return Err(Error::last_error()); 165 | } 166 | Ok(()) 167 | } 168 | 169 | /// Delete a snapshot. 170 | pub fn delete(&self, flags: u32) -> Result<(), Error> { 171 | let ret = unsafe { sys::virDomainSnapshotDelete(self.as_ptr(), flags as libc::c_uint) }; 172 | if ret == -1 { 173 | return Err(Error::last_error()); 174 | } 175 | Ok(()) 176 | } 177 | 178 | /// Return the number of snapshots for this domain. 179 | pub fn num(dom: &Domain, flags: u32) -> Result { 180 | let ret = unsafe { sys::virDomainSnapshotNum(dom.as_ptr(), flags as libc::c_uint) }; 181 | if ret == -1 { 182 | return Err(Error::last_error()); 183 | } 184 | Ok(ret as u32) 185 | } 186 | 187 | /// Return the number of child snapshots for this snapshot. 188 | pub fn num_children(&self, flags: u32) -> Result { 189 | let ret = 190 | unsafe { sys::virDomainSnapshotNumChildren(self.as_ptr(), flags as libc::c_uint) }; 191 | if ret == -1 { 192 | return Err(Error::last_error()); 193 | } 194 | Ok(ret as u32) 195 | } 196 | 197 | /// Determine if a snapshot is the current snapshot of its domain. 198 | pub fn is_current(&self, flags: u32) -> Result { 199 | let ret = unsafe { sys::virDomainSnapshotIsCurrent(self.as_ptr(), flags as libc::c_uint) }; 200 | if ret == -1 { 201 | return Err(Error::last_error()); 202 | } 203 | Ok(ret == 1) 204 | } 205 | 206 | /// Determine if a snapshot has associated libvirt metadata that 207 | /// would prevent the deletion of its domain. 208 | pub fn has_metadata(&self, flags: u32) -> Result { 209 | let ret = 210 | unsafe { sys::virDomainSnapshotHasMetadata(self.as_ptr(), flags as libc::c_uint) }; 211 | if ret == -1 { 212 | return Err(Error::last_error()); 213 | } 214 | Ok(ret == 1) 215 | } 216 | 217 | /// Get all snapshot object children for this snapshot. 218 | pub fn list_all_children(&self, flags: u32) -> Result, Error> { 219 | let mut snaps: *mut sys::virDomainSnapshotPtr = ptr::null_mut(); 220 | let size = unsafe { 221 | sys::virDomainSnapshotListAllChildren(self.as_ptr(), &mut snaps, flags as libc::c_uint) 222 | }; 223 | if size == -1 { 224 | return Err(Error::last_error()); 225 | } 226 | 227 | let mut array: Vec = Vec::new(); 228 | for x in 0..size as isize { 229 | array.push(unsafe { DomainSnapshot::from_ptr(*snaps.offset(x)) }); 230 | } 231 | unsafe { libc::free(snaps as *mut libc::c_void) }; 232 | 233 | Ok(array) 234 | } 235 | 236 | pub fn free(&mut self) -> Result<(), Error> { 237 | let ret = unsafe { sys::virDomainSnapshotFree(self.as_ptr()) }; 238 | if ret == -1 { 239 | return Err(Error::last_error()); 240 | } 241 | self.ptr = None; 242 | Ok(()) 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /src/enumutil.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_enum { 2 | (enum: $type:ty, raw: $raw:ty, match: { $($match_arms:tt)* }) => { 3 | impl std::fmt::Display for $type { 4 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 5 | $crate::enumutil::impl_enum_display!(self, f, $($match_arms)*) 6 | } 7 | } 8 | 9 | impl $type { 10 | /// Converts libvirt C enum constant to Rust enum. 11 | pub fn from_raw(raw: $raw) -> Self { 12 | $crate::enumutil::impl_enum_from!(raw, $($match_arms)*) 13 | } 14 | 15 | /// Converts Rust enum to libvirt C enum constant. 16 | pub fn to_raw(self) -> $raw { 17 | $crate::enumutil::impl_enum_to!(self, $($match_arms)*) 18 | } 19 | } 20 | }; 21 | } 22 | 23 | macro_rules! impl_enum_display { 24 | (@acc ($e:expr, $f:expr, _ => $type:ident => $_raw:path,) -> ($($body:tt)*)) => { 25 | $crate::enumutil::impl_enum_display!(@final ($e) -> ($($body)* Self::$type => write!($f, "{}", stringify!($type).to_lowercase()),)) 26 | }; 27 | (@acc ($e:expr, $f:expr, _ => $type:ident,) -> ($($body:tt)*)) => { 28 | $crate::enumutil::impl_enum_display!(@final ($e) -> ($($body)* )) 29 | }; 30 | (@acc ($e:expr, $f:expr, $(#[$attr:meta])* $raw:path => $type:ident, $($match_arms:tt)*) -> ($($body:tt)*)) => { 31 | $crate::enumutil::impl_enum_display!(@acc ($e, $f, $($match_arms)*) -> ($($body)* $(#[$attr])* Self::$type => write!($f, "{}", stringify!($type).to_lowercase()),)) 32 | }; 33 | (@final ($e:expr) -> ($($body:tt)*)) => { 34 | match $e { $($body)* } 35 | }; 36 | ($e:expr, $f:expr, $($match_arms:tt)*) => { 37 | $crate::enumutil::impl_enum_display!(@acc ($e, $f, $($match_arms)*) -> ()) 38 | }; 39 | } 40 | 41 | macro_rules! impl_enum_from { 42 | (@acc ($e:expr, _ => $type:ident => $_raw:path,) -> ($($body:tt)*)) => { 43 | $crate::enumutil::impl_enum_from!(@final ($e) -> ($($body)* _ => Self::$type,)) 44 | }; 45 | (@acc ($e:expr, _ => $type:ident,) -> ($($body:tt)*)) => { 46 | $crate::enumutil::impl_enum_from!(@final ($e) -> ($($body)* _ => Self::$type,)) 47 | }; 48 | (@acc ($e:expr, $(#[$attr:meta])* $raw:path => $type:ident, $($match_arms:tt)*) -> ($($body:tt)*)) => { 49 | $crate::enumutil::impl_enum_from!(@acc ($e, $($match_arms)*) -> ($($body)* $(#[$attr])* $raw => Self::$type,)) 50 | }; 51 | (@final ($e:expr) -> ($($body:tt)*)) => { 52 | match $e { $($body)* } 53 | }; 54 | ($e:expr, $($match_arms:tt)*) => { 55 | $crate::enumutil::impl_enum_from!(@acc ($e, $($match_arms)*) -> ()) 56 | }; 57 | } 58 | 59 | macro_rules! impl_enum_to { 60 | (@acc ($e:expr, _ => $type:ident => $raw:path,) -> ($($body:tt)*)) => { 61 | $crate::enumutil::impl_enum_to!(@final ($e) -> ($($body)* Self::$type => $raw,)) 62 | }; 63 | (@acc ($e:expr, _ => $_type:ident,) -> ($($body:tt)*)) => { 64 | $crate::enumutil::impl_enum_to!(@final ($e) -> ($($body)*)) 65 | }; 66 | (@acc ($e:expr, $(#[$attr:meta])* $raw:path => $type:ident, $($match_arms:tt)*) -> ($($body:tt)*)) => { 67 | $crate::enumutil::impl_enum_to!(@acc ($e, $($match_arms)*) -> ($($body)* $(#[$attr])* Self::$type => $raw,)) 68 | }; 69 | (@final ($e:expr) -> ($($body:tt)*)) => { 70 | match $e { $($body)* } 71 | }; 72 | ($e:expr, $($match_arms:tt)*) => { 73 | $crate::enumutil::impl_enum_to!(@acc ($e, $($match_arms)*) -> ()) 74 | }; 75 | } 76 | 77 | pub(crate) use impl_enum; 78 | pub(crate) use impl_enum_display; 79 | pub(crate) use impl_enum_from; 80 | pub(crate) use impl_enum_to; 81 | 82 | #[cfg(test)] 83 | mod tests { 84 | use super::*; 85 | 86 | const FOO: u32 = 0; 87 | const BAR: u32 = 1; 88 | const BAZ: u32 = 2; 89 | 90 | #[derive(Debug, PartialEq, Clone, Copy)] 91 | enum WithoutLast { 92 | Foo, 93 | Bar, 94 | Baz, 95 | } 96 | 97 | #[derive(Debug, PartialEq, Clone, Copy)] 98 | enum WithLast { 99 | Foo, 100 | Bar, 101 | Baz, 102 | Last, 103 | } 104 | 105 | impl_enum! { 106 | enum: WithoutLast, 107 | raw: u32, 108 | match: { 109 | FOO => Foo, 110 | BAR => Bar, 111 | BAZ => Baz, 112 | _ => Foo, 113 | } 114 | } 115 | 116 | impl_enum! { 117 | enum: WithLast, 118 | raw: u32, 119 | match: { 120 | FOO => Foo, 121 | BAR => Bar, 122 | BAZ => Baz, 123 | _ => Last => FOO, 124 | } 125 | } 126 | 127 | #[test] 128 | fn test_enum_without_last_from_raw() { 129 | let inputs = [ 130 | (FOO, WithoutLast::Foo), 131 | (BAR, WithoutLast::Bar), 132 | (BAZ, WithoutLast::Baz), 133 | (10, WithoutLast::Foo), 134 | ]; 135 | 136 | for &(raw, expected) in inputs.iter() { 137 | assert_eq!(WithoutLast::from_raw(raw), expected); 138 | } 139 | } 140 | 141 | #[test] 142 | fn test_enum_without_last_to_raw() { 143 | let inputs = [ 144 | (WithoutLast::Foo, FOO, "foo"), 145 | (WithoutLast::Bar, BAR, "bar"), 146 | (WithoutLast::Baz, BAZ, "baz"), 147 | ]; 148 | 149 | for &(variant, expected, estr) in inputs.iter() { 150 | assert_eq!(variant.to_raw(), expected); 151 | assert_eq!(variant.to_string(), estr); 152 | } 153 | } 154 | 155 | #[test] 156 | fn test_enum_with_last_from_raw() { 157 | let inputs = [ 158 | (FOO, WithLast::Foo), 159 | (BAR, WithLast::Bar), 160 | (BAZ, WithLast::Baz), 161 | (10, WithLast::Last), 162 | ]; 163 | 164 | for &(raw, expected) in inputs.iter() { 165 | assert_eq!(WithLast::from_raw(raw), expected); 166 | } 167 | } 168 | 169 | #[test] 170 | fn test_enum_with_last_to_raw() { 171 | let inputs = [ 172 | (WithLast::Foo, FOO, "foo"), 173 | (WithLast::Bar, BAR, "bar"), 174 | (WithLast::Baz, BAZ, "baz"), 175 | (WithLast::Last, FOO, "last"), 176 | ]; 177 | 178 | for &(variant, expected, estr) in inputs.iter() { 179 | assert_eq!(variant.to_raw(), expected); 180 | assert_eq!(variant.to_string(), estr); 181 | } 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /src/interface.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library. If not, see 14 | * . 15 | * 16 | * Sahid Orentino Ferdjaoui 17 | */ 18 | 19 | use std::ffi::CString; 20 | use std::str; 21 | 22 | use crate::connect::Connect; 23 | use crate::error::Error; 24 | 25 | /// Provides APIs for the management of interfaces. 26 | /// 27 | /// See 28 | #[derive(Debug)] 29 | pub struct Interface { 30 | ptr: Option, 31 | } 32 | 33 | unsafe impl Send for Interface {} 34 | unsafe impl Sync for Interface {} 35 | 36 | impl Drop for Interface { 37 | fn drop(&mut self) { 38 | if self.ptr.is_some() { 39 | if let Err(e) = self.free() { 40 | panic!("Unable to drop memory for Interface: {}", e) 41 | } 42 | } 43 | } 44 | } 45 | 46 | impl Clone for Interface { 47 | /// Creates a copy of a interface. 48 | /// 49 | /// Increments the internal reference counter on the given 50 | /// interface. For each call to this method, there shall be a 51 | /// corresponding call to [`free()`]. 52 | /// 53 | /// [`free()`]: Interface::free 54 | fn clone(&self) -> Self { 55 | self.add_ref().unwrap() 56 | } 57 | } 58 | 59 | impl Interface { 60 | /// # Safety 61 | /// 62 | /// The caller must ensure that the pointer is valid. 63 | pub unsafe fn from_ptr(ptr: sys::virInterfacePtr) -> Interface { 64 | Interface { ptr: Some(ptr) } 65 | } 66 | 67 | fn add_ref(&self) -> Result { 68 | unsafe { 69 | if sys::virInterfaceRef(self.as_ptr()) == -1 { 70 | return Err(Error::last_error()); 71 | } 72 | } 73 | 74 | Ok(unsafe { Interface::from_ptr(self.as_ptr()) }) 75 | } 76 | 77 | pub fn as_ptr(&self) -> sys::virInterfacePtr { 78 | self.ptr.unwrap() 79 | } 80 | 81 | pub fn get_connect(&self) -> Result { 82 | let ptr = unsafe { sys::virInterfaceGetConnect(self.as_ptr()) }; 83 | if ptr.is_null() { 84 | return Err(Error::last_error()); 85 | } 86 | Ok(unsafe { Connect::from_ptr(ptr) }) 87 | } 88 | 89 | pub fn lookup_by_name(conn: &Connect, id: &str) -> Result { 90 | let id_buf = CString::new(id).unwrap(); 91 | let ptr = unsafe { sys::virInterfaceLookupByName(conn.as_ptr(), id_buf.as_ptr()) }; 92 | if ptr.is_null() { 93 | return Err(Error::last_error()); 94 | } 95 | Ok(unsafe { Interface::from_ptr(ptr) }) 96 | } 97 | 98 | pub fn define_xml(conn: &Connect, xml: &str, flags: u32) -> Result { 99 | let xml_buf = CString::new(xml).unwrap(); 100 | let ptr = unsafe { 101 | sys::virInterfaceDefineXML(conn.as_ptr(), xml_buf.as_ptr(), flags as libc::c_uint) 102 | }; 103 | if ptr.is_null() { 104 | return Err(Error::last_error()); 105 | } 106 | Ok(unsafe { Interface::from_ptr(ptr) }) 107 | } 108 | 109 | pub fn lookup_by_mac_string(conn: &Connect, id: &str) -> Result { 110 | let id_buf = CString::new(id).unwrap(); 111 | let ptr = unsafe { sys::virInterfaceLookupByMACString(conn.as_ptr(), id_buf.as_ptr()) }; 112 | if ptr.is_null() { 113 | return Err(Error::last_error()); 114 | } 115 | Ok(unsafe { Interface::from_ptr(ptr) }) 116 | } 117 | 118 | pub fn get_name(&self) -> Result { 119 | let n = unsafe { sys::virInterfaceGetName(self.as_ptr()) }; 120 | if n.is_null() { 121 | return Err(Error::last_error()); 122 | } 123 | Ok(unsafe { c_chars_to_string!(n, nofree) }) 124 | } 125 | 126 | pub fn get_mac_string(&self) -> Result { 127 | let mac = unsafe { sys::virInterfaceGetMACString(self.as_ptr()) }; 128 | if mac.is_null() { 129 | return Err(Error::last_error()); 130 | } 131 | Ok(unsafe { c_chars_to_string!(mac, nofree) }) 132 | } 133 | 134 | pub fn get_xml_desc(&self, flags: sys::virInterfaceXMLFlags) -> Result { 135 | let xml = unsafe { sys::virInterfaceGetXMLDesc(self.as_ptr(), flags) }; 136 | if xml.is_null() { 137 | return Err(Error::last_error()); 138 | } 139 | Ok(unsafe { c_chars_to_string!(xml) }) 140 | } 141 | 142 | pub fn create(&self, flags: sys::virInterfaceXMLFlags) -> Result { 143 | let ret = unsafe { sys::virInterfaceCreate(self.as_ptr(), flags) }; 144 | if ret == -1 { 145 | return Err(Error::last_error()); 146 | } 147 | Ok(ret as u32) 148 | } 149 | 150 | pub fn destroy(&self, flags: u32) -> Result<(), Error> { 151 | let ret = unsafe { sys::virInterfaceDestroy(self.as_ptr(), flags) }; 152 | if ret == -1 { 153 | return Err(Error::last_error()); 154 | } 155 | Ok(()) 156 | } 157 | 158 | pub fn undefine(&self) -> Result<(), Error> { 159 | let ret = unsafe { sys::virInterfaceUndefine(self.as_ptr()) }; 160 | if ret == -1 { 161 | return Err(Error::last_error()); 162 | } 163 | Ok(()) 164 | } 165 | 166 | pub fn free(&mut self) -> Result<(), Error> { 167 | let ret = unsafe { sys::virInterfaceFree(self.as_ptr()) }; 168 | if ret == -1 { 169 | return Err(Error::last_error()); 170 | } 171 | self.ptr = None; 172 | Ok(()) 173 | } 174 | 175 | pub fn is_active(&self) -> Result { 176 | let ret = unsafe { sys::virInterfaceIsActive(self.as_ptr()) }; 177 | if ret == -1 { 178 | return Err(Error::last_error()); 179 | } 180 | Ok(ret == 1) 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library. If not, see 14 | * . 15 | * 16 | * Sahid Orentino Ferdjaoui 17 | */ 18 | 19 | //! A Rust bindings for libvirt. 20 | //! 21 | //! Libvirt is a portable toolkit to interact with the virtualisation 22 | //! capabilities of Linux, Solaris and other operating systems. 23 | //! 24 | //! The binding tries to be a fairly direct mapping of the underling C 25 | //! API with some differences to respect Rust conventions. So for 26 | //! example C functions related to a domain like: `virDomainCreate` 27 | //! will be mapped in the binding like `dom.create()` or 28 | //! `virDomainPinVcpu` as `dom.pin_vcpu`. 29 | //! 30 | //! The binding uses standard errors handling from Rust. Each method 31 | //! (there are some exceptions) is returning a type `Option` or 32 | //! `Result`. 33 | //! 34 | //! ``` 35 | //! use virt::connect::Connect; 36 | //! 37 | //! if let Ok(mut conn) = Connect::open(Some("test:///default")) { 38 | //! assert_eq!(Ok(0), conn.close()); 39 | //! } 40 | //! ``` 41 | //! 42 | //! Most of the structs are automatically release their references by 43 | //! implemementing `Drop` trait but for structs which are reference 44 | //! counted at C level, it is still possible to explicitly release the 45 | //! reference at Rust level. For instance if a Rust method returns a 46 | //! *Domain, it is possible to call `free` on it when no longer 47 | //! required. 48 | //! 49 | //! ``` 50 | //! use virt::connect::Connect; 51 | //! use virt::domain::Domain; 52 | //! 53 | //! if let Ok(mut conn) = Connect::open(Some("test:///default")) { 54 | //! if let Ok(mut dom) = Domain::lookup_by_name(&conn, "myguest") { 55 | //! assert_eq!(Ok(()), dom.free()); // Explicitly releases memory at Rust level. 56 | //! assert_eq!(Ok(0), conn.close()); 57 | //! } 58 | //! } 59 | //! ``` 60 | //! 61 | //! For each methods accepting or returning a virTypedParameter array 62 | //! a new Rust struct has been defined where each attribute is 63 | //! handling a type Option. 64 | //! 65 | //! ``` 66 | //! use virt::connect::Connect; 67 | //! use virt::domain::Domain; 68 | //! 69 | //! if let Ok(mut conn) = Connect::open(Some("test://default")) { 70 | //! if let Ok(dom) = Domain::lookup_by_name(&conn, "myguest") { 71 | //! if let Ok(memp) = dom.get_memory_parameters(0) { 72 | //! if memp.hard_limit.is_some() { 73 | //! println!("hard limit: {}", memp.hard_limit.unwrap()) 74 | //! } 75 | //! } 76 | //! } 77 | //! assert_eq!(Ok(0), conn.close()); 78 | //! } 79 | //! ``` 80 | 81 | pub extern crate virt_sys as sys; 82 | 83 | macro_rules! c_chars_to_string { 84 | ($x:expr) => {{ 85 | let ret = ::std::ffi::CStr::from_ptr($x) 86 | .to_string_lossy() 87 | .into_owned(); 88 | libc::free($x as *mut libc::c_void); 89 | ret 90 | }}; 91 | 92 | ($x:expr, nofree) => {{ 93 | ::std::ffi::CStr::from_ptr($x) 94 | .to_string_lossy() 95 | .into_owned() 96 | }}; 97 | } 98 | 99 | // The caller must do 'let _ptr_cleanup = CString::from_raw(ptr)' 100 | // to release the memory associated with the returned pointer. 101 | // Also note it is not valid to use C's free(ptr) call, it must 102 | // be released via the CString API. 103 | macro_rules! string_to_mut_c_chars { 104 | ($x:expr) => { 105 | ::std::ffi::CString::new($x).unwrap().into_raw() as *mut libc::c_char 106 | }; 107 | } 108 | 109 | // To be used when handling Option<&str> parameters which need 110 | // to be passed to libvirt. General usage pattern is: 111 | // 112 | // pub fn something(foo: Option<&str>) -> Result { 113 | // let foo_buf = some_string_to_cstring!(foo); 114 | // unsafe { 115 | // sys::virConnectSomething(self.as_ptr(), 116 | // some_cstring_to_c_chars!(foo_buf)); 117 | // } 118 | // ... 119 | // 120 | macro_rules! some_string_to_cstring { 121 | ($x:expr) => { 122 | $x.map(|s| CString::new(s).unwrap()) 123 | }; 124 | } 125 | 126 | macro_rules! some_cstring_to_c_chars { 127 | ($x:expr) => { 128 | $x.as_ref().map_or_else(|| ptr::null(), |s| s.as_ptr()) 129 | }; 130 | } 131 | 132 | macro_rules! typed_params_release_c_chars { 133 | ($x:expr) => { 134 | for p in $x { 135 | if p.type_ == sys::VIR_TYPED_PARAM_STRING as libc::c_int { 136 | let _cleanup = CString::from_raw(p.value.s); 137 | } 138 | } 139 | }; 140 | } 141 | 142 | mod enumutil; 143 | mod typedparams; 144 | mod util; 145 | 146 | pub mod connect; 147 | pub mod domain; 148 | pub mod domain_snapshot; 149 | pub mod error; 150 | pub mod interface; 151 | pub mod network; 152 | pub mod nodedev; 153 | pub mod nwfilter; 154 | pub mod secret; 155 | pub mod storage_pool; 156 | pub mod storage_vol; 157 | pub mod stream; 158 | -------------------------------------------------------------------------------- /src/network.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library. If not, see 14 | * . 15 | * 16 | * Sahid Orentino Ferdjaoui 17 | */ 18 | 19 | use std::ffi::CString; 20 | use std::str; 21 | 22 | use uuid::Uuid; 23 | 24 | use crate::connect::Connect; 25 | use crate::error::Error; 26 | 27 | /// Provides APIs for the management of networks. 28 | /// 29 | /// See 30 | #[derive(Debug)] 31 | pub struct Network { 32 | ptr: Option, 33 | } 34 | 35 | unsafe impl Send for Network {} 36 | unsafe impl Sync for Network {} 37 | 38 | impl Drop for Network { 39 | fn drop(&mut self) { 40 | if self.ptr.is_some() { 41 | if let Err(e) = self.free() { 42 | panic!("Unable to drop memory for Network: {}", e) 43 | } 44 | } 45 | } 46 | } 47 | 48 | impl Clone for Network { 49 | /// Creates a copy of a network. 50 | /// 51 | /// Increments the internal reference counter on the given 52 | /// network. For each call to this method, there shall be a 53 | /// corresponding call to [`free()`]. 54 | /// 55 | /// [`free()`]: Network::free 56 | fn clone(&self) -> Self { 57 | self.add_ref().unwrap() 58 | } 59 | } 60 | 61 | impl Network { 62 | /// # Safety 63 | /// 64 | /// The caller must ensure that the pointer is valid. 65 | pub unsafe fn from_ptr(ptr: sys::virNetworkPtr) -> Network { 66 | Network { ptr: Some(ptr) } 67 | } 68 | 69 | fn add_ref(&self) -> Result { 70 | unsafe { 71 | if sys::virNetworkRef(self.as_ptr()) == -1 { 72 | return Err(Error::last_error()); 73 | } 74 | } 75 | 76 | Ok(unsafe { Network::from_ptr(self.as_ptr()) }) 77 | } 78 | 79 | pub fn as_ptr(&self) -> sys::virNetworkPtr { 80 | self.ptr.unwrap() 81 | } 82 | 83 | pub fn get_connect(&self) -> Result { 84 | let ptr = unsafe { sys::virNetworkGetConnect(self.as_ptr()) }; 85 | if ptr.is_null() { 86 | return Err(Error::last_error()); 87 | } 88 | Ok(unsafe { Connect::from_ptr(ptr) }) 89 | } 90 | 91 | pub fn lookup_by_name(conn: &Connect, id: &str) -> Result { 92 | let id_buf = CString::new(id).unwrap(); 93 | let ptr = unsafe { sys::virNetworkLookupByName(conn.as_ptr(), id_buf.as_ptr()) }; 94 | if ptr.is_null() { 95 | return Err(Error::last_error()); 96 | } 97 | Ok(unsafe { Network::from_ptr(ptr) }) 98 | } 99 | 100 | pub fn lookup_by_uuid(conn: &Connect, uuid: Uuid) -> Result { 101 | let ptr = unsafe { sys::virNetworkLookupByUUID(conn.as_ptr(), uuid.as_bytes().as_ptr()) }; 102 | if ptr.is_null() { 103 | return Err(Error::last_error()); 104 | } 105 | Ok(unsafe { Network::from_ptr(ptr) }) 106 | } 107 | 108 | pub fn lookup_by_uuid_string(conn: &Connect, uuid: &str) -> Result { 109 | let uuid_buf = CString::new(uuid).unwrap(); 110 | let ptr = unsafe { sys::virNetworkLookupByUUIDString(conn.as_ptr(), uuid_buf.as_ptr()) }; 111 | if ptr.is_null() { 112 | return Err(Error::last_error()); 113 | } 114 | Ok(unsafe { Network::from_ptr(ptr) }) 115 | } 116 | 117 | pub fn get_name(&self) -> Result { 118 | let n = unsafe { sys::virNetworkGetName(self.as_ptr()) }; 119 | if n.is_null() { 120 | return Err(Error::last_error()); 121 | } 122 | Ok(unsafe { c_chars_to_string!(n, nofree) }) 123 | } 124 | 125 | pub fn get_uuid(&self) -> Result { 126 | let mut uuid: [libc::c_uchar; sys::VIR_UUID_BUFLEN as usize] = 127 | [0; sys::VIR_UUID_BUFLEN as usize]; 128 | let ret = unsafe { sys::virNetworkGetUUID(self.as_ptr(), uuid.as_mut_ptr()) }; 129 | if ret == -1 { 130 | return Err(Error::last_error()); 131 | } 132 | Ok(Uuid::from_bytes(uuid)) 133 | } 134 | 135 | pub fn get_uuid_string(&self) -> Result { 136 | let mut uuid: [libc::c_char; sys::VIR_UUID_STRING_BUFLEN as usize] = 137 | [0; sys::VIR_UUID_STRING_BUFLEN as usize]; 138 | let ret = unsafe { sys::virNetworkGetUUIDString(self.as_ptr(), uuid.as_mut_ptr()) }; 139 | if ret == -1 { 140 | return Err(Error::last_error()); 141 | } 142 | Ok(unsafe { c_chars_to_string!(uuid.as_ptr(), nofree) }) 143 | } 144 | 145 | pub fn get_bridge_name(&self) -> Result { 146 | let n = unsafe { sys::virNetworkGetBridgeName(self.as_ptr()) }; 147 | if n.is_null() { 148 | return Err(Error::last_error()); 149 | } 150 | Ok(unsafe { c_chars_to_string!(n) }) 151 | } 152 | 153 | pub fn get_xml_desc(&self, flags: sys::virNetworkXMLFlags) -> Result { 154 | let xml = unsafe { sys::virNetworkGetXMLDesc(self.as_ptr(), flags) }; 155 | if xml.is_null() { 156 | return Err(Error::last_error()); 157 | } 158 | Ok(unsafe { c_chars_to_string!(xml) }) 159 | } 160 | 161 | pub fn create(&self) -> Result { 162 | let ret = unsafe { sys::virNetworkCreate(self.as_ptr()) }; 163 | if ret == -1 { 164 | return Err(Error::last_error()); 165 | } 166 | Ok(ret as u32) 167 | } 168 | 169 | pub fn define_xml(conn: &Connect, xml: &str) -> Result { 170 | let xml_buf = CString::new(xml).unwrap(); 171 | let ptr = unsafe { sys::virNetworkDefineXML(conn.as_ptr(), xml_buf.as_ptr()) }; 172 | if ptr.is_null() { 173 | return Err(Error::last_error()); 174 | } 175 | Ok(unsafe { Network::from_ptr(ptr) }) 176 | } 177 | 178 | pub fn create_xml(conn: &Connect, xml: &str) -> Result { 179 | let xml_buf = CString::new(xml).unwrap(); 180 | let ptr = unsafe { sys::virNetworkCreateXML(conn.as_ptr(), xml_buf.as_ptr()) }; 181 | if ptr.is_null() { 182 | return Err(Error::last_error()); 183 | } 184 | Ok(unsafe { Network::from_ptr(ptr) }) 185 | } 186 | 187 | pub fn destroy(&self) -> Result<(), Error> { 188 | let ret = unsafe { sys::virNetworkDestroy(self.as_ptr()) }; 189 | if ret == -1 { 190 | return Err(Error::last_error()); 191 | } 192 | Ok(()) 193 | } 194 | 195 | pub fn undefine(&self) -> Result<(), Error> { 196 | let ret = unsafe { sys::virNetworkUndefine(self.as_ptr()) }; 197 | if ret == -1 { 198 | return Err(Error::last_error()); 199 | } 200 | Ok(()) 201 | } 202 | 203 | pub fn free(&mut self) -> Result<(), Error> { 204 | let ret = unsafe { sys::virNetworkFree(self.as_ptr()) }; 205 | if ret == -1 { 206 | return Err(Error::last_error()); 207 | } 208 | self.ptr = None; 209 | Ok(()) 210 | } 211 | 212 | pub fn is_active(&self) -> Result { 213 | let ret = unsafe { sys::virNetworkIsActive(self.as_ptr()) }; 214 | if ret == -1 { 215 | return Err(Error::last_error()); 216 | } 217 | Ok(ret == 1) 218 | } 219 | 220 | pub fn is_persistent(&self) -> Result { 221 | let ret = unsafe { sys::virNetworkIsPersistent(self.as_ptr()) }; 222 | if ret == -1 { 223 | return Err(Error::last_error()); 224 | } 225 | Ok(ret == 1) 226 | } 227 | 228 | pub fn get_autostart(&self) -> Result { 229 | let mut auto = 0; 230 | let ret = unsafe { sys::virNetworkGetAutostart(self.as_ptr(), &mut auto) }; 231 | if ret == -1 { 232 | return Err(Error::last_error()); 233 | } 234 | Ok(auto == 1) 235 | } 236 | 237 | pub fn set_autostart(&self, autostart: bool) -> Result { 238 | let ret = unsafe { sys::virNetworkSetAutostart(self.as_ptr(), autostart as libc::c_int) }; 239 | if ret == -1 { 240 | return Err(Error::last_error()); 241 | } 242 | Ok(ret as u32) 243 | } 244 | 245 | pub fn update( 246 | &self, 247 | cmd: sys::virNetworkUpdateCommand, 248 | section: sys::virNetworkUpdateSection, 249 | index: i32, 250 | xml: &str, 251 | flags: sys::virNetworkUpdateFlags, 252 | ) -> Result<(), Error> { 253 | let xml_buf = CString::new(xml).unwrap(); 254 | let ret = unsafe { 255 | sys::virNetworkUpdate( 256 | self.as_ptr(), 257 | cmd, 258 | section, 259 | index as libc::c_int, 260 | xml_buf.as_ptr(), 261 | flags, 262 | ) 263 | }; 264 | if ret == -1 { 265 | return Err(Error::last_error()); 266 | } 267 | Ok(()) 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /src/nodedev.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library. If not, see 14 | * . 15 | * 16 | * Sahid Orentino Ferdjaoui 17 | */ 18 | 19 | use std::ffi::CString; 20 | use std::{ptr, str}; 21 | 22 | use crate::connect::Connect; 23 | use crate::error::Error; 24 | 25 | /// Provides APIs for the management of nodedevs. 26 | /// 27 | /// See 28 | #[derive(Debug)] 29 | pub struct NodeDevice { 30 | ptr: Option, 31 | } 32 | 33 | unsafe impl Send for NodeDevice {} 34 | unsafe impl Sync for NodeDevice {} 35 | 36 | impl Drop for NodeDevice { 37 | fn drop(&mut self) { 38 | if self.ptr.is_some() { 39 | if let Err(e) = self.free() { 40 | panic!("Unable to drop memory for NodeDevice: {}", e) 41 | } 42 | } 43 | } 44 | } 45 | 46 | impl Clone for NodeDevice { 47 | /// Creates a copy of a node device. 48 | /// 49 | /// Increments the internal reference counter on the given 50 | /// device. For each call to this method, there shall be a 51 | /// corresponding call to [`free()`]. 52 | /// 53 | /// [`free()`]: NodeDevice::free 54 | fn clone(&self) -> Self { 55 | self.add_ref().unwrap() 56 | } 57 | } 58 | 59 | impl NodeDevice { 60 | /// # Safety 61 | /// 62 | /// The caller must ensure that the pointer is valid. 63 | pub unsafe fn from_ptr(ptr: sys::virNodeDevicePtr) -> NodeDevice { 64 | NodeDevice { ptr: Some(ptr) } 65 | } 66 | 67 | fn add_ref(&self) -> Result { 68 | unsafe { 69 | if sys::virNodeDeviceRef(self.as_ptr()) == -1 { 70 | return Err(Error::last_error()); 71 | } 72 | } 73 | 74 | Ok(unsafe { NodeDevice::from_ptr(self.as_ptr()) }) 75 | } 76 | 77 | pub fn as_ptr(&self) -> sys::virNodeDevicePtr { 78 | self.ptr.unwrap() 79 | } 80 | 81 | pub fn lookup_by_name(conn: &Connect, id: &str) -> Result { 82 | let id_buf = CString::new(id).unwrap(); 83 | let ptr = unsafe { sys::virNodeDeviceLookupByName(conn.as_ptr(), id_buf.as_ptr()) }; 84 | if ptr.is_null() { 85 | return Err(Error::last_error()); 86 | } 87 | Ok(unsafe { NodeDevice::from_ptr(ptr) }) 88 | } 89 | 90 | pub fn lookup_scsi_host_by_www( 91 | conn: &Connect, 92 | wwnn: &str, 93 | wwpn: &str, 94 | flags: u32, 95 | ) -> Result { 96 | let wwnn_buf = CString::new(wwnn).unwrap(); 97 | let wwpn_buf = CString::new(wwpn).unwrap(); 98 | let ptr = unsafe { 99 | sys::virNodeDeviceLookupSCSIHostByWWN( 100 | conn.as_ptr(), 101 | wwnn_buf.as_ptr(), 102 | wwpn_buf.as_ptr(), 103 | flags as libc::c_uint, 104 | ) 105 | }; 106 | if ptr.is_null() { 107 | return Err(Error::last_error()); 108 | } 109 | Ok(unsafe { NodeDevice::from_ptr(ptr) }) 110 | } 111 | 112 | pub fn create_xml(conn: &Connect, xml: &str, flags: u32) -> Result { 113 | let xml_buf = CString::new(xml).unwrap(); 114 | let ptr = unsafe { 115 | sys::virNodeDeviceCreateXML(conn.as_ptr(), xml_buf.as_ptr(), flags as libc::c_uint) 116 | }; 117 | if ptr.is_null() { 118 | return Err(Error::last_error()); 119 | } 120 | Ok(unsafe { NodeDevice::from_ptr(ptr) }) 121 | } 122 | 123 | pub fn get_name(&self) -> Result { 124 | let n = unsafe { sys::virNodeDeviceGetName(self.as_ptr()) }; 125 | if n.is_null() { 126 | return Err(Error::last_error()); 127 | } 128 | Ok(unsafe { c_chars_to_string!(n, nofree) }) 129 | } 130 | 131 | pub fn get_parent(&self) -> Result { 132 | let n = unsafe { sys::virNodeDeviceGetParent(self.as_ptr()) }; 133 | if n.is_null() { 134 | return Err(Error::last_error()); 135 | } 136 | Ok(unsafe { c_chars_to_string!(n, nofree) }) 137 | } 138 | 139 | pub fn get_xml_desc(&self, flags: u32) -> Result { 140 | let xml = unsafe { sys::virNodeDeviceGetXMLDesc(self.as_ptr(), flags as libc::c_uint) }; 141 | if xml.is_null() { 142 | return Err(Error::last_error()); 143 | } 144 | Ok(unsafe { c_chars_to_string!(xml) }) 145 | } 146 | 147 | pub fn destroy(&self) -> Result { 148 | let ret = unsafe { sys::virNodeDeviceDestroy(self.as_ptr()) }; 149 | if ret == -1 { 150 | return Err(Error::last_error()); 151 | } 152 | Ok(ret as u32) 153 | } 154 | 155 | pub fn detach(&self) -> Result { 156 | let ret = unsafe { sys::virNodeDeviceDettach(self.as_ptr()) }; 157 | if ret == -1 { 158 | return Err(Error::last_error()); 159 | } 160 | Ok(ret as u32) 161 | } 162 | 163 | pub fn reset(&self) -> Result { 164 | let ret = unsafe { sys::virNodeDeviceReset(self.as_ptr()) }; 165 | if ret == -1 { 166 | return Err(Error::last_error()); 167 | } 168 | Ok(ret as u32) 169 | } 170 | 171 | pub fn reattach(&self) -> Result { 172 | let ret = unsafe { sys::virNodeDeviceReAttach(self.as_ptr()) }; 173 | if ret == -1 { 174 | return Err(Error::last_error()); 175 | } 176 | Ok(ret as u32) 177 | } 178 | 179 | pub fn detach_flags(&self, driver: Option<&str>, flags: u32) -> Result { 180 | let driver_buf = some_string_to_cstring!(driver); 181 | let ret = unsafe { 182 | sys::virNodeDeviceDetachFlags( 183 | self.as_ptr(), 184 | some_cstring_to_c_chars!(driver_buf), 185 | flags as libc::c_uint, 186 | ) 187 | }; 188 | if ret == -1 { 189 | return Err(Error::last_error()); 190 | } 191 | Ok(ret as u32) 192 | } 193 | 194 | pub fn free(&mut self) -> Result<(), Error> { 195 | let ret = unsafe { sys::virNodeDeviceFree(self.as_ptr()) }; 196 | if ret == -1 { 197 | return Err(Error::last_error()); 198 | } 199 | self.ptr = None; 200 | Ok(()) 201 | } 202 | 203 | pub fn num_of_devices(conn: &Connect, cap: Option<&str>, flags: u32) -> Result { 204 | let cap_buf = some_string_to_cstring!(cap); 205 | let num = unsafe { 206 | sys::virNodeNumOfDevices( 207 | conn.as_ptr(), 208 | some_cstring_to_c_chars!(cap_buf), 209 | flags as libc::c_uint, 210 | ) 211 | }; 212 | if num == -1 { 213 | return Err(Error::last_error()); 214 | } 215 | Ok(num as u32) 216 | } 217 | 218 | pub fn num_of_caps(&self) -> Result { 219 | let num = unsafe { sys::virNodeDeviceNumOfCaps(self.as_ptr()) }; 220 | if num == -1 { 221 | return Err(Error::last_error()); 222 | } 223 | Ok(num as u32) 224 | } 225 | 226 | #[allow(clippy::needless_range_loop)] 227 | pub fn list_caps(&self) -> Result, Error> { 228 | let mut names: [*mut libc::c_char; 1024] = [ptr::null_mut(); 1024]; 229 | let size = unsafe { sys::virNodeDeviceListCaps(self.as_ptr(), names.as_mut_ptr(), 1024) }; 230 | if size == -1 { 231 | return Err(Error::last_error()); 232 | } 233 | 234 | let mut array: Vec = Vec::new(); 235 | for x in 0..size as usize { 236 | array.push(unsafe { c_chars_to_string!(names[x]) }); 237 | } 238 | Ok(array) 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /src/nwfilter.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library. If not, see 14 | * . 15 | * 16 | * Sahid Orentino Ferdjaoui 17 | */ 18 | 19 | use std::ffi::CString; 20 | use std::str; 21 | 22 | use uuid::Uuid; 23 | 24 | use crate::connect::Connect; 25 | use crate::error::Error; 26 | 27 | /// Provides APIs for the management for network filters. 28 | /// 29 | /// See 30 | #[derive(Debug)] 31 | pub struct NWFilter { 32 | ptr: Option, 33 | } 34 | 35 | unsafe impl Send for NWFilter {} 36 | unsafe impl Sync for NWFilter {} 37 | 38 | impl Drop for NWFilter { 39 | fn drop(&mut self) { 40 | if self.ptr.is_some() { 41 | if let Err(e) = self.free() { 42 | panic!("Unable to drop memory for NWFilter: {}", e) 43 | } 44 | } 45 | } 46 | } 47 | 48 | impl Clone for NWFilter { 49 | /// Creates a copy of a network filter. 50 | /// 51 | /// Increments the internal reference counter on the given 52 | /// filter. For each call to this method, there shall be a 53 | /// corresponding call to [`free()`]. 54 | /// 55 | /// [`free()`]: NWFilter::free 56 | fn clone(&self) -> Self { 57 | self.add_ref().unwrap() 58 | } 59 | } 60 | 61 | impl NWFilter { 62 | /// # Safety 63 | /// 64 | /// The caller must ensure that the pointer is valid. 65 | pub unsafe fn from_ptr(ptr: sys::virNWFilterPtr) -> NWFilter { 66 | NWFilter { ptr: Some(ptr) } 67 | } 68 | 69 | fn add_ref(&self) -> Result { 70 | unsafe { 71 | if sys::virNWFilterRef(self.as_ptr()) == -1 { 72 | return Err(Error::last_error()); 73 | } 74 | } 75 | 76 | Ok(unsafe { NWFilter::from_ptr(self.as_ptr()) }) 77 | } 78 | 79 | pub fn as_ptr(&self) -> sys::virNWFilterPtr { 80 | self.ptr.unwrap() 81 | } 82 | 83 | pub fn lookup_by_name(conn: &Connect, id: &str) -> Result { 84 | let id_buf = CString::new(id).unwrap(); 85 | let ptr = unsafe { sys::virNWFilterLookupByName(conn.as_ptr(), id_buf.as_ptr()) }; 86 | if ptr.is_null() { 87 | return Err(Error::last_error()); 88 | } 89 | Ok(unsafe { NWFilter::from_ptr(ptr) }) 90 | } 91 | 92 | pub fn lookup_by_uuid(conn: &Connect, uuid: Uuid) -> Result { 93 | let ptr = unsafe { sys::virNWFilterLookupByUUID(conn.as_ptr(), uuid.as_bytes().as_ptr()) }; 94 | if ptr.is_null() { 95 | return Err(Error::last_error()); 96 | } 97 | Ok(unsafe { NWFilter::from_ptr(ptr) }) 98 | } 99 | 100 | pub fn lookup_by_uuid_string(conn: &Connect, uuid: &str) -> Result { 101 | let uuid_buf = CString::new(uuid).unwrap(); 102 | let ptr = unsafe { sys::virNWFilterLookupByUUIDString(conn.as_ptr(), uuid_buf.as_ptr()) }; 103 | if ptr.is_null() { 104 | return Err(Error::last_error()); 105 | } 106 | Ok(unsafe { NWFilter::from_ptr(ptr) }) 107 | } 108 | 109 | pub fn get_name(&self) -> Result { 110 | let n = unsafe { sys::virNWFilterGetName(self.as_ptr()) }; 111 | if n.is_null() { 112 | return Err(Error::last_error()); 113 | } 114 | Ok(unsafe { c_chars_to_string!(n, nofree) }) 115 | } 116 | 117 | pub fn get_uuid(&self) -> Result { 118 | let mut uuid: [libc::c_uchar; sys::VIR_UUID_BUFLEN as usize] = 119 | [0; sys::VIR_UUID_BUFLEN as usize]; 120 | let ret = unsafe { sys::virNWFilterGetUUID(self.as_ptr(), uuid.as_mut_ptr()) }; 121 | if ret == -1 { 122 | return Err(Error::last_error()); 123 | } 124 | Ok(Uuid::from_bytes(uuid)) 125 | } 126 | 127 | pub fn get_uuid_string(&self) -> Result { 128 | let mut uuid: [libc::c_char; sys::VIR_UUID_STRING_BUFLEN as usize] = 129 | [0; sys::VIR_UUID_STRING_BUFLEN as usize]; 130 | let ret = unsafe { sys::virNWFilterGetUUIDString(self.as_ptr(), uuid.as_mut_ptr()) }; 131 | if ret == -1 { 132 | return Err(Error::last_error()); 133 | } 134 | Ok(unsafe { c_chars_to_string!(uuid.as_ptr(), nofree) }) 135 | } 136 | 137 | pub fn get_xml_desc(&self, flags: u32) -> Result { 138 | let xml = unsafe { sys::virNWFilterGetXMLDesc(self.as_ptr(), flags as libc::c_uint) }; 139 | if xml.is_null() { 140 | return Err(Error::last_error()); 141 | } 142 | Ok(unsafe { c_chars_to_string!(xml) }) 143 | } 144 | 145 | pub fn define_xml(conn: &Connect, xml: &str) -> Result { 146 | let xml_buf = CString::new(xml).unwrap(); 147 | let ptr = unsafe { sys::virNWFilterDefineXML(conn.as_ptr(), xml_buf.as_ptr()) }; 148 | if ptr.is_null() { 149 | return Err(Error::last_error()); 150 | } 151 | Ok(unsafe { NWFilter::from_ptr(ptr) }) 152 | } 153 | 154 | pub fn undefine(&self) -> Result<(), Error> { 155 | let ret = unsafe { sys::virNWFilterUndefine(self.as_ptr()) }; 156 | if ret == -1 { 157 | return Err(Error::last_error()); 158 | } 159 | Ok(()) 160 | } 161 | 162 | pub fn free(&mut self) -> Result<(), Error> { 163 | let ret = unsafe { sys::virNWFilterFree(self.as_ptr()) }; 164 | if ret == -1 { 165 | return Err(Error::last_error()); 166 | } 167 | self.ptr = None; 168 | Ok(()) 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /src/secret.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library. If not, see 14 | * . 15 | * 16 | * Sahid Orentino Ferdjaoui 17 | */ 18 | 19 | use std::ffi::CString; 20 | 21 | use uuid::Uuid; 22 | 23 | use crate::connect::Connect; 24 | use crate::error::Error; 25 | 26 | /// Provides APIs for the management of secrets. 27 | /// 28 | /// See 29 | #[derive(Debug)] 30 | pub struct Secret { 31 | ptr: Option, 32 | } 33 | 34 | unsafe impl Send for Secret {} 35 | unsafe impl Sync for Secret {} 36 | 37 | impl Drop for Secret { 38 | fn drop(&mut self) { 39 | if self.ptr.is_some() { 40 | if let Err(e) = self.free() { 41 | panic!("Unable to drop memory for Secret: {}", e) 42 | } 43 | } 44 | } 45 | } 46 | 47 | impl Clone for Secret { 48 | /// Creates a copy of a secret. 49 | /// 50 | /// Increments the internal reference counter on the given 51 | /// secret. For each call to this method, there shall be a 52 | /// corresponding call to [`free()`]. 53 | /// 54 | /// [`free()`]: Secret::free 55 | fn clone(&self) -> Self { 56 | self.add_ref().unwrap() 57 | } 58 | } 59 | 60 | impl Secret { 61 | /// # Safety 62 | /// 63 | /// The caller must ensure that the pointer is valid. 64 | pub unsafe fn from_ptr(ptr: sys::virSecretPtr) -> Secret { 65 | Secret { ptr: Some(ptr) } 66 | } 67 | 68 | fn add_ref(&self) -> Result { 69 | unsafe { 70 | if sys::virSecretRef(self.as_ptr()) == -1 { 71 | return Err(Error::last_error()); 72 | } 73 | } 74 | 75 | Ok(unsafe { Secret::from_ptr(self.as_ptr()) }) 76 | } 77 | 78 | pub fn as_ptr(&self) -> sys::virSecretPtr { 79 | self.ptr.unwrap() 80 | } 81 | 82 | pub fn get_connect(&self) -> Result { 83 | let ptr = unsafe { sys::virSecretGetConnect(self.as_ptr()) }; 84 | if ptr.is_null() { 85 | return Err(Error::last_error()); 86 | } 87 | Ok(unsafe { Connect::from_ptr(ptr) }) 88 | } 89 | 90 | pub fn define_xml(conn: &Connect, xml: &str, flags: u32) -> Result { 91 | let xml_buf = CString::new(xml).unwrap(); 92 | let ptr = unsafe { 93 | sys::virSecretDefineXML(conn.as_ptr(), xml_buf.as_ptr(), flags as libc::c_uint) 94 | }; 95 | if ptr.is_null() { 96 | return Err(Error::last_error()); 97 | } 98 | Ok(unsafe { Secret::from_ptr(ptr) }) 99 | } 100 | 101 | pub fn lookup_by_uuid(conn: &Connect, uuid: Uuid) -> Result { 102 | let ptr = unsafe { sys::virSecretLookupByUUID(conn.as_ptr(), uuid.as_bytes().as_ptr()) }; 103 | if ptr.is_null() { 104 | return Err(Error::last_error()); 105 | } 106 | Ok(unsafe { Secret::from_ptr(ptr) }) 107 | } 108 | 109 | pub fn lookup_by_uuid_string(conn: &Connect, uuid: &str) -> Result { 110 | let uuid_buf = CString::new(uuid).unwrap(); 111 | let ptr = unsafe { sys::virSecretLookupByUUIDString(conn.as_ptr(), uuid_buf.as_ptr()) }; 112 | if ptr.is_null() { 113 | return Err(Error::last_error()); 114 | } 115 | Ok(unsafe { Secret::from_ptr(ptr) }) 116 | } 117 | 118 | pub fn lookup_by_usage(conn: &Connect, usagetype: i32, usageid: &str) -> Result { 119 | let usageid_buf = CString::new(usageid).unwrap(); 120 | let ptr = unsafe { 121 | sys::virSecretLookupByUsage( 122 | conn.as_ptr(), 123 | usagetype as libc::c_int, 124 | usageid_buf.as_ptr(), 125 | ) 126 | }; 127 | if ptr.is_null() { 128 | return Err(Error::last_error()); 129 | } 130 | Ok(unsafe { Secret::from_ptr(ptr) }) 131 | } 132 | 133 | pub fn get_usage_id(&self) -> Result { 134 | let n = unsafe { sys::virSecretGetUsageID(self.as_ptr()) }; 135 | if n.is_null() { 136 | return Err(Error::last_error()); 137 | } 138 | Ok(unsafe { c_chars_to_string!(n) }) 139 | } 140 | 141 | pub fn get_usage_type(&self) -> Result { 142 | let t = unsafe { sys::virSecretGetUsageType(self.as_ptr()) }; 143 | if t == -1 { 144 | return Err(Error::last_error()); 145 | } 146 | Ok(t as u32) 147 | } 148 | 149 | pub fn get_uuid(&self) -> Result { 150 | let mut uuid: [libc::c_uchar; sys::VIR_UUID_BUFLEN as usize] = 151 | [0; sys::VIR_UUID_BUFLEN as usize]; 152 | let ret = unsafe { sys::virSecretGetUUID(self.as_ptr(), uuid.as_mut_ptr()) }; 153 | if ret == -1 { 154 | return Err(Error::last_error()); 155 | } 156 | Ok(Uuid::from_bytes(uuid)) 157 | } 158 | 159 | pub fn get_uuid_string(&self) -> Result { 160 | let mut uuid: [libc::c_char; sys::VIR_UUID_STRING_BUFLEN as usize] = 161 | [0; sys::VIR_UUID_STRING_BUFLEN as usize]; 162 | let ret = unsafe { sys::virSecretGetUUIDString(self.as_ptr(), uuid.as_mut_ptr()) }; 163 | if ret == -1 { 164 | return Err(Error::last_error()); 165 | } 166 | Ok(unsafe { c_chars_to_string!(uuid.as_ptr(), nofree) }) 167 | } 168 | 169 | pub fn get_xml_desc(&self, flags: u32) -> Result { 170 | let xml = unsafe { sys::virSecretGetXMLDesc(self.as_ptr(), flags) }; 171 | if xml.is_null() { 172 | return Err(Error::last_error()); 173 | } 174 | Ok(unsafe { c_chars_to_string!(xml) }) 175 | } 176 | 177 | pub fn set_value(&self, value: &[u8], flags: u32) -> Result<(), Error> { 178 | let ret = 179 | unsafe { sys::virSecretSetValue(self.as_ptr(), value.as_ptr(), value.len(), flags) }; 180 | if ret == -1 { 181 | return Err(Error::last_error()); 182 | } 183 | Ok(()) 184 | } 185 | 186 | pub fn get_value(&self, flags: u32) -> Result, Error> { 187 | let mut size: usize = 0; 188 | let n = unsafe { sys::virSecretGetValue(self.as_ptr(), &mut size, flags as libc::c_uint) }; 189 | if n.is_null() { 190 | return Err(Error::last_error()); 191 | } 192 | 193 | let mut array: Vec = Vec::new(); 194 | for x in 0..size { 195 | array.push(unsafe { *n.add(x) }) 196 | } 197 | Ok(array) 198 | } 199 | 200 | pub fn undefine(&self) -> Result<(), Error> { 201 | let ret = unsafe { sys::virSecretUndefine(self.as_ptr()) }; 202 | if ret == -1 { 203 | return Err(Error::last_error()); 204 | } 205 | Ok(()) 206 | } 207 | 208 | pub fn free(&mut self) -> Result<(), Error> { 209 | let ret = unsafe { sys::virSecretFree(self.as_ptr()) }; 210 | if ret == -1 { 211 | return Err(Error::last_error()); 212 | } 213 | self.ptr = None; 214 | Ok(()) 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /src/stream.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library. If not, see 14 | * . 15 | * 16 | * Sahid Orentino Ferdjaoui 17 | */ 18 | 19 | use std::convert::TryFrom; 20 | 21 | use crate::connect::Connect; 22 | use crate::error::Error; 23 | 24 | // wrapper for callbacks 25 | extern "C" fn event_callback(c: sys::virStreamPtr, flags: libc::c_int, opaque: *mut libc::c_void) { 26 | let flags = flags as sys::virStreamFlags; 27 | let shadow_self = unsafe { &mut *(opaque as *mut Stream) }; 28 | if let Some(callback) = &mut shadow_self.callback { 29 | callback( 30 | unsafe { 31 | sys::virStreamRef(c); 32 | &Stream::from_ptr(c) 33 | }, 34 | flags, 35 | ); 36 | } 37 | } 38 | 39 | extern "C" fn event_free(_opaque: *mut libc::c_void) {} 40 | 41 | type StreamCallback = dyn FnMut(&Stream, sys::virStreamEventType); 42 | 43 | // #[derive(Debug)] 44 | pub struct Stream { 45 | ptr: Option, 46 | callback: Option>, 47 | } 48 | 49 | unsafe impl Send for Stream {} 50 | unsafe impl Sync for Stream {} 51 | 52 | impl Drop for Stream { 53 | fn drop(&mut self) { 54 | if self.callback.is_some() { 55 | if let Err(e) = self.event_remove_callback() { 56 | panic!("Unable to remove event callback for Stream: {}", e) 57 | } 58 | } 59 | if self.ptr.is_some() { 60 | if let Err(e) = self.free() { 61 | panic!("Unable to drop memory for Stream: {}", e) 62 | } 63 | } 64 | } 65 | } 66 | 67 | impl Clone for Stream { 68 | /// Creates a copy of a stream. 69 | /// 70 | /// Increments the internal reference counter on the given 71 | /// stream. For each call to this method, there shall be a 72 | /// corresponding call to [`free()`]. 73 | /// 74 | /// [`free()`]: Stream::free 75 | fn clone(&self) -> Self { 76 | self.add_ref().unwrap() 77 | } 78 | } 79 | 80 | impl Stream { 81 | pub fn new(conn: &Connect, flags: sys::virStreamFlags) -> Result { 82 | let ptr = unsafe { sys::virStreamNew(conn.as_ptr(), flags as libc::c_uint) }; 83 | if ptr.is_null() { 84 | return Err(Error::last_error()); 85 | } 86 | Ok(unsafe { Stream::from_ptr(ptr) }) 87 | } 88 | 89 | fn add_ref(&self) -> Result { 90 | unsafe { 91 | if sys::virStreamRef(self.as_ptr()) == -1 { 92 | return Err(Error::last_error()); 93 | } 94 | } 95 | 96 | Ok(unsafe { Stream::from_ptr(self.as_ptr()) }) 97 | } 98 | 99 | unsafe fn from_ptr(ptr: sys::virStreamPtr) -> Stream { 100 | Stream { 101 | ptr: Some(ptr), 102 | callback: None, 103 | } 104 | } 105 | 106 | pub fn as_ptr(&self) -> sys::virStreamPtr { 107 | self.ptr.unwrap() 108 | } 109 | 110 | pub fn free(&mut self) -> Result<(), Error> { 111 | let ret = unsafe { sys::virStreamFree(self.as_ptr()) }; 112 | if ret == -1 { 113 | return Err(Error::last_error()); 114 | } 115 | self.ptr = None; 116 | Ok(()) 117 | } 118 | 119 | pub fn finish(self) -> Result<(), Error> { 120 | let ret = unsafe { sys::virStreamFinish(self.as_ptr()) }; 121 | if ret == -1 { 122 | return Err(Error::last_error()); 123 | } 124 | Ok(()) 125 | } 126 | 127 | pub fn abort(self) -> Result<(), Error> { 128 | let ret = unsafe { sys::virStreamAbort(self.as_ptr()) }; 129 | if ret == -1 { 130 | return Err(Error::last_error()); 131 | } 132 | Ok(()) 133 | } 134 | 135 | pub fn send(&self, data: &[u8]) -> Result { 136 | let ret = unsafe { 137 | sys::virStreamSend( 138 | self.as_ptr(), 139 | data.as_ptr() as *mut libc::c_char, 140 | data.len(), 141 | ) 142 | }; 143 | usize::try_from(ret).map_err(|_| Error::last_error()) 144 | } 145 | 146 | pub fn recv(&self, buf: &mut [u8]) -> Result { 147 | let ret = unsafe { 148 | sys::virStreamRecv( 149 | self.as_ptr(), 150 | buf.as_mut_ptr() as *mut libc::c_char, 151 | buf.len(), 152 | ) 153 | }; 154 | usize::try_from(ret).map_err(|_| Error::last_error()) 155 | } 156 | 157 | pub fn event_add_callback( 158 | &mut self, 159 | events: sys::virStreamEventType, 160 | cb: F, 161 | ) -> Result<(), Error> { 162 | let ret = unsafe { 163 | let ptr = self as *mut _ as *mut _; 164 | sys::virStreamEventAddCallback( 165 | self.as_ptr(), 166 | events as libc::c_int, 167 | Some(event_callback), 168 | ptr, 169 | Some(event_free), 170 | ) 171 | }; 172 | if ret == -1 { 173 | return Err(Error::last_error()); 174 | } 175 | self.callback = Some(Box::new(cb)); 176 | Ok(()) 177 | } 178 | 179 | pub fn event_update_callback(&self, events: sys::virStreamEventType) -> Result<(), Error> { 180 | let ret = 181 | unsafe { sys::virStreamEventUpdateCallback(self.as_ptr(), events as libc::c_int) }; 182 | if ret == -1 { 183 | return Err(Error::last_error()); 184 | } 185 | Ok(()) 186 | } 187 | 188 | pub fn event_remove_callback(&self) -> Result<(), Error> { 189 | let ret = unsafe { sys::virStreamEventRemoveCallback(self.as_ptr()) }; 190 | if ret == -1 { 191 | return Err(Error::last_error()); 192 | } 193 | Ok(()) 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /src/util.rs: -------------------------------------------------------------------------------- 1 | #[cfg(all(target_pointer_width = "64", not(windows)))] 2 | pub fn c_ulong_to_u64(val: ::libc::c_ulong) -> u64 { 3 | val 4 | } 5 | 6 | #[cfg(not(all(target_pointer_width = "64", not(windows))))] 7 | pub fn c_ulong_to_u64(val: ::libc::c_ulong) -> u64 { 8 | val as u64 9 | } 10 | -------------------------------------------------------------------------------- /tests/common/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library. If not, see 14 | * . 15 | * 16 | * Sahid Orentino Ferdjaoui 17 | */ 18 | 19 | // The rustc is complaining about dead code because only used when 20 | // ignored tests are executed. 21 | #![allow(dead_code)] 22 | 23 | use virt::connect::Connect; 24 | use virt::domain::Domain; 25 | use virt::error::Error; 26 | use virt::interface::Interface; 27 | use virt::network::Network; 28 | use virt::storage_pool::StoragePool; 29 | use virt::storage_vol::StorageVol; 30 | 31 | pub fn conn() -> Connect { 32 | Connect::open(Some("test:///default")).unwrap() 33 | } 34 | 35 | pub fn qemu_conn() -> Connect { 36 | Connect::open(Some("qemu:///system")).unwrap() 37 | } 38 | 39 | pub fn close(mut conn: Connect) { 40 | assert_eq!(Ok(0), conn.close(), "close(), expected 0") 41 | } 42 | 43 | pub fn clean(mut dom: Domain) { 44 | let _ = dom.destroy(); 45 | let _ = dom.undefine(); 46 | assert_eq!(Ok(()), dom.free()) 47 | } 48 | 49 | pub fn clean_iface(mut iface: Interface) { 50 | let _ = iface.destroy(0); 51 | let _ = iface.undefine(); 52 | assert_eq!(Ok(()), iface.free()) 53 | } 54 | 55 | pub fn clean_pool(mut pool: StoragePool) { 56 | let _ = pool.destroy(); 57 | let _ = pool.undefine(); 58 | assert_eq!(Ok(()), pool.free()) 59 | } 60 | 61 | pub fn clean_net(mut net: Network) { 62 | let _ = net.destroy(); 63 | let _ = net.undefine(); 64 | assert_eq!(Ok(()), net.free()) 65 | } 66 | 67 | pub fn clean_vol(mut vol: StorageVol) { 68 | let _ = vol.delete(0); 69 | assert_eq!(Ok(()), vol.free()) 70 | } 71 | 72 | pub fn build_qemu_domain(conn: &Connect, name: &str, transient: bool) -> Domain { 73 | let name = format!("libvirt-rs-test-{}", name); 74 | 75 | if let Ok(dom) = Domain::lookup_by_name(conn, &name) { 76 | clean(dom); 77 | } 78 | 79 | let xml = format!( 80 | " 81 | {} 82 | 128 83 | 84 | 85 | 86 | 87 | 88 | hvm 89 | 90 | ", 91 | name 92 | ); 93 | 94 | let result: Result = if transient { 95 | Domain::create_xml(conn, &xml, 0) 96 | } else { 97 | Domain::define_xml(conn, &xml) 98 | }; 99 | 100 | result.unwrap() 101 | } 102 | 103 | pub fn build_test_domain(conn: &Connect, name: &str, transient: bool) -> Domain { 104 | let name = format!("libvirt-rs-test-{}", name); 105 | 106 | if let Ok(dom) = Domain::lookup_by_name(conn, &name) { 107 | clean(dom); 108 | } 109 | 110 | let xml = format!( 111 | " 112 | {} 113 | 128 114 | 115 | 116 | 117 | 118 | 119 | hvm 120 | 121 | ", 122 | name 123 | ); 124 | 125 | let result: Result = if transient { 126 | Domain::create_xml(conn, &xml, 0) 127 | } else { 128 | Domain::define_xml(conn, &xml) 129 | }; 130 | 131 | result.unwrap() 132 | } 133 | 134 | pub fn build_storage_pool(conn: &Connect, name: &str, transient: bool) -> StoragePool { 135 | let name = format!("libvirt-rs-test-{}", name); 136 | 137 | if let Ok(pool) = StoragePool::lookup_by_name(conn, &name) { 138 | clean_pool(pool); 139 | } 140 | 141 | let xml = format!( 142 | " 143 | {} 144 | 145 | /var/lib/libvirt/images 146 | 147 | ", 148 | name 149 | ); 150 | 151 | let result: Result = if transient { 152 | StoragePool::create_xml(conn, &xml, 0) 153 | } else { 154 | StoragePool::define_xml(conn, &xml, 0) 155 | }; 156 | 157 | result.unwrap() 158 | } 159 | 160 | pub fn build_storage_vol(pool: &StoragePool, name: &str, size: u64) -> StorageVol { 161 | if let Ok(vol) = StorageVol::lookup_by_name(pool, name) { 162 | return vol; 163 | } 164 | 165 | let xml = format!( 166 | " 167 | {} 168 | {} 169 | {} 170 | ", 171 | name, size, size 172 | ); 173 | StorageVol::create_xml(pool, &xml, 0).unwrap() 174 | } 175 | 176 | pub fn build_network(conn: &Connect, name: &str, transient: bool) -> Network { 177 | let name = format!("libvirt-rs-test-{}", name); 178 | 179 | if let Ok(net) = Network::lookup_by_name(conn, &name) { 180 | clean_net(net); 181 | } 182 | 183 | let xml = format!( 184 | " 185 | {} 186 | 187 | 188 | 189 | ", 190 | name 191 | ); 192 | 193 | let result: Result = if transient { 194 | Network::create_xml(conn, &xml) 195 | } else { 196 | Network::define_xml(conn, &xml) 197 | }; 198 | 199 | result.unwrap() 200 | } 201 | 202 | pub fn build_interface(conn: &Connect, name: &str) -> Interface { 203 | let name = format!("libvirt-rs-test-{}", name); 204 | 205 | if let Ok(iface) = Interface::lookup_by_name(conn, &name) { 206 | clean_iface(iface); 207 | } 208 | 209 | let xml = format!( 210 | " 211 | 212 | ", 213 | name 214 | ); 215 | 216 | Interface::define_xml(conn, &xml, 0).unwrap() 217 | } 218 | -------------------------------------------------------------------------------- /tests/connect.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library. If not, see 14 | * . 15 | * 16 | * Sahid Orentino Ferdjaoui 17 | */ 18 | 19 | mod common; 20 | 21 | use virt::connect::Connect; 22 | 23 | #[test] 24 | fn test_version() { 25 | let version = Connect::get_version().unwrap_or(0); 26 | assert!(version != 0, "Version was 0") 27 | } 28 | 29 | #[test] 30 | fn test_connection() { 31 | match Connect::open(Some("test:///default")) { 32 | Err(e) => panic!("Build connection failed: {}", e), 33 | Ok(conn) => common::close(conn), 34 | } 35 | } 36 | 37 | #[test] 38 | fn test_read_only_connection() { 39 | match Connect::open_read_only(Some("test:///default")) { 40 | Err(e) => panic!("Build connection failed: {}", e), 41 | Ok(conn) => common::close(conn), 42 | } 43 | } 44 | 45 | #[test] 46 | #[should_panic] 47 | fn test_connection_invalid() { 48 | match Connect::open_read_only(Some("invalid")) { 49 | Err(e) => panic!("Build connection failed: {}", e), 50 | Ok(conn) => common::close(conn), 51 | } 52 | } 53 | 54 | #[test] 55 | fn test_get_type() { 56 | let c = common::conn(); 57 | assert!(!c.get_type().unwrap_or_default().is_empty()); 58 | common::close(c) 59 | } 60 | 61 | #[test] 62 | fn test_get_uri() { 63 | let c = common::conn(); 64 | assert_eq!("test:///default", c.get_uri().unwrap_or_default()); 65 | common::close(c); 66 | } 67 | 68 | #[test] 69 | fn test_is_alive() { 70 | let c = common::conn(); 71 | assert!(c.is_alive().unwrap_or(false)); 72 | common::close(c); 73 | } 74 | 75 | #[test] 76 | fn test_is_encrypted() { 77 | let c = common::conn(); 78 | assert!( 79 | !c.is_encrypted().unwrap_or(true), 80 | "Test driver should not be encrypted" 81 | ); 82 | common::close(c); 83 | } 84 | 85 | #[test] 86 | fn test_is_secure() { 87 | let c = common::conn(); 88 | assert!( 89 | c.is_secure().unwrap_or(false), 90 | "Test driver should be secure" 91 | ); 92 | common::close(c); 93 | } 94 | 95 | #[test] 96 | fn test_capabilities() { 97 | let c = common::conn(); 98 | assert!( 99 | "" != c.get_capabilities().unwrap_or_default(), 100 | "Capabilities should not be empty" 101 | ); 102 | common::close(c); 103 | } 104 | 105 | #[test] 106 | fn test_domain_capabilities() { 107 | let c = common::conn(); 108 | 109 | /* Libvirt's test driver implemented domcaps in 9.8.0. Allow test to 110 | * run gracefully on older versions. */ 111 | match c.get_domain_capabilities(None, None, None, None, 0) { 112 | Ok(domcaps) => assert!( 113 | !domcaps.is_empty(), 114 | "Domain capabilities should not be empty" 115 | ), 116 | Err(e) => assert!( 117 | e.level() == virt::error::ErrorLevel::Error 118 | && e.code() == virt::error::ErrorNumber::NoSupport 119 | && e.domain() == virt::error::ErrorDomain::Domain, 120 | "Unexpected error" 121 | ), 122 | } 123 | common::close(c); 124 | } 125 | 126 | #[test] 127 | fn test_get_node_info() { 128 | let c = common::conn(); 129 | match c.get_node_info() { 130 | Ok(info) => assert_eq!("i686", info.model), 131 | Err(_) => panic!("should have a node info"), 132 | } 133 | common::close(c); 134 | } 135 | 136 | #[test] 137 | fn test_hostname() { 138 | let c = common::conn(); 139 | assert!(!c.get_hostname().unwrap_or_default().is_empty()); 140 | common::close(c); 141 | } 142 | 143 | /* 144 | #[test] 145 | fn test_get_free_memory() { 146 | let c = common::conn(); 147 | assert!( 148 | 0 != c.get_free_memory().unwrap_or(0), 149 | "Version was 0"); 150 | common::close(c); 151 | } 152 | */ 153 | 154 | #[test] 155 | fn test_lib_version() { 156 | let c = common::conn(); 157 | assert!(0 != c.get_lib_version().unwrap_or(0), "Version was 0"); 158 | common::close(c); 159 | } 160 | 161 | #[test] 162 | fn test_list_domains() { 163 | let c = common::conn(); 164 | assert!( 165 | !c.list_domains().unwrap_or_default().is_empty(), 166 | "At least one domain should exist" 167 | ); 168 | common::close(c); 169 | } 170 | 171 | #[test] 172 | fn test_list_interfaces() { 173 | let c = common::conn(); 174 | assert!( 175 | !c.list_interfaces().unwrap_or_default().is_empty(), 176 | "At least one interface should exist" 177 | ); 178 | common::close(c); 179 | } 180 | 181 | #[test] 182 | fn test_list_networks() { 183 | let c = common::conn(); 184 | assert!( 185 | !c.list_networks().unwrap_or_default().is_empty(), 186 | "At least one networks should exist" 187 | ); 188 | common::close(c); 189 | } 190 | 191 | #[test] 192 | fn test_list_storage_pools() { 193 | let c = common::conn(); 194 | assert!( 195 | !c.list_storage_pools().unwrap_or_default().is_empty(), 196 | "At least one storage pool should exist" 197 | ); 198 | common::close(c); 199 | } 200 | 201 | #[test] 202 | fn test_list_all_domains() { 203 | let c = common::conn(); 204 | let v = c.list_all_domains(0).unwrap_or_default(); 205 | assert!(!v.is_empty(), "At least one domain should exist"); 206 | drop(v); 207 | common::close(c); 208 | } 209 | 210 | /* Travis is failing on this test 211 | #[test] 212 | fn test_get_cpu_models_names() { 213 | let c = common::conn(); 214 | let mcpus = c.get_cpu_models_names("i686", 0).unwrap_or(vec![]); 215 | assert!(0 < mcpus.len(), "At least one cpu model should exist"); 216 | common::close(c); 217 | } 218 | */ 219 | 220 | #[test] 221 | fn test_get_max_vcpus() { 222 | let c = common::conn(); 223 | let m = c.get_max_vcpus(None).unwrap_or(0); 224 | assert!(0 < m, "At least one cpu should exist"); 225 | common::close(c); 226 | } 227 | 228 | #[test] 229 | fn test_get_cells_free_memory() { 230 | let c = common::conn(); 231 | let free = c.get_cells_free_memory(0, 2).unwrap_or_default(); 232 | assert!(free.len() == 2, "Expected two NUMA nodes"); 233 | assert!(free[0] == 2097152, "Invalid free pages for NUMA node 0"); 234 | assert!(free[1] == 4194304, "Invalid free pages for NUMA node 1"); 235 | common::close(c); 236 | } 237 | -------------------------------------------------------------------------------- /tests/integration_qemu.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library. If not, see 14 | * . 15 | * 16 | * Sahid Orentino Ferdjaoui 17 | */ 18 | 19 | //! Integration tests using a real qemu:///system connection they are 20 | //! all ignored by default. 21 | 22 | mod common; 23 | 24 | use virt::connect::{Connect, ConnectAuth, ConnectCredential}; 25 | use virt::sys; 26 | 27 | #[test] 28 | #[ignore] 29 | fn test_create_domain_with_flags() { 30 | let c = common::qemu_conn(); 31 | let d = common::build_qemu_domain(&c, "create", false); 32 | assert_eq!(Ok(0), d.create_with_flags(0)); 33 | assert_eq!(Ok((sys::VIR_DOMAIN_START_PAUSED, 1)), d.get_state()); 34 | assert_eq!(Ok(String::from("libvirt-rs-test-create")), d.get_name()); 35 | common::clean(d); 36 | common::close(c); 37 | } 38 | 39 | #[test] 40 | #[ignore] 41 | fn test_create_storage_pool_and_vols() { 42 | let c = common::qemu_conn(); 43 | let p = common::build_storage_pool(&c, "create", false); 44 | assert_eq!(Ok(0), p.create(0)); 45 | assert_eq!(Ok(String::from("libvirt-rs-test-create")), p.get_name()); 46 | let v = common::build_storage_vol(&p, "vol1", 8); 47 | assert_eq!(Ok(String::from("vol1")), v.get_name()); 48 | assert_eq!( 49 | Ok(String::from("/var/lib/libvirt/images/vol1")), 50 | v.get_path() 51 | ); 52 | assert_eq!( 53 | Ok(String::from("/var/lib/libvirt/images/vol1")), 54 | v.get_key() 55 | ); 56 | if let Ok(info) = v.get_info() { 57 | assert_eq!(0, info.kind); 58 | assert_eq!(8192, info.allocation); 59 | assert_eq!(8192, info.capacity); 60 | } else { 61 | common::clean_vol(v); 62 | common::clean_pool(p); 63 | common::close(c); 64 | panic!("should not be here") 65 | } 66 | assert_eq!(Ok(0), v.resize(10240, 0)); 67 | if let Ok(info) = v.get_info() { 68 | assert_eq!(0, info.kind); 69 | assert_eq!(8192, info.allocation); 70 | assert_eq!(10240, info.capacity); 71 | } else { 72 | common::clean_vol(v); 73 | common::clean_pool(p); 74 | common::close(c); 75 | panic!("should not be here") 76 | } 77 | if let Ok(info) = p.get_info() { 78 | assert_eq!(2, info.state); 79 | assert_eq!(0, info.capacity - (info.allocation + info.available)); 80 | } else { 81 | common::clean_vol(v); 82 | common::clean_pool(p); 83 | common::close(c); 84 | panic!("should not be here") 85 | } 86 | common::clean_vol(v); 87 | common::clean_pool(p); 88 | common::close(c); 89 | } 90 | 91 | #[test] 92 | #[ignore] 93 | fn test_connection_with_auth() { 94 | fn callback(creds: &mut Vec) { 95 | for cred in creds { 96 | match cred.typed as u32 { 97 | sys::VIR_CRED_AUTHNAME => { 98 | cred.result = Some(String::from("user")); 99 | } 100 | sys::VIR_CRED_PASSPHRASE => { 101 | cred.result = Some(String::from("pass")); 102 | } 103 | _ => { 104 | panic!("Should not be here..."); 105 | } 106 | } 107 | } 108 | } 109 | 110 | let mut auth = ConnectAuth::new( 111 | vec![sys::VIR_CRED_AUTHNAME, sys::VIR_CRED_PASSPHRASE], 112 | callback, 113 | ); 114 | let c = Connect::open_auth(Some("test+tcp://127.0.0.1/default"), &mut auth, 0); 115 | assert!(c.is_ok()); 116 | common::close(c.unwrap()); 117 | } 118 | 119 | #[test] 120 | #[ignore] 121 | fn test_connection_with_auth_wrong() { 122 | fn callback(creds: &mut Vec) { 123 | for cred in creds { 124 | match cred.typed as u32 { 125 | sys::VIR_CRED_AUTHNAME => { 126 | cred.result = Some(String::from("user")); 127 | } 128 | sys::VIR_CRED_PASSPHRASE => { 129 | cred.result = Some(String::from("passwrong")); 130 | } 131 | _ => { 132 | panic!("Should not be here..."); 133 | } 134 | } 135 | } 136 | } 137 | 138 | let mut auth = ConnectAuth::new( 139 | vec![sys::VIR_CRED_AUTHNAME, sys::VIR_CRED_PASSPHRASE], 140 | callback, 141 | ); 142 | let c = Connect::open_auth(Some("test+tcp://127.0.0.1/default"), &mut auth, 0); 143 | assert!(c.is_err()); 144 | } 145 | 146 | #[test] 147 | #[ignore] 148 | fn test_reset() { 149 | let c = common::qemu_conn(); 150 | let d = common::build_qemu_domain(&c, "reset", false); 151 | assert_eq!(Ok(0), d.create_with_flags(0)); 152 | assert_eq!(Ok((sys::VIR_DOMAIN_RUNNING, 1)), d.get_state()); 153 | assert_eq!(Ok(0), d.reset()); 154 | // TODO assert something showing reset has the intended side effect 155 | common::clean(d); 156 | common::close(c); 157 | } 158 | 159 | #[test] 160 | #[ignore] 161 | fn test_domain_memory_stats() { 162 | let c = common::qemu_conn(); 163 | let d = common::build_qemu_domain(&c, "memory_stats", false); 164 | assert_eq!(Ok(0), d.create_with_flags(0)); 165 | assert_eq!( 166 | Ok(String::from("libvirt-rs-test-memory_stats")), 167 | d.get_name() 168 | ); 169 | for stat in d.memory_stats(0).unwrap() { 170 | match stat.tag { 171 | sys::VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON => assert_eq!(1024, stat.val), 172 | sys::VIR_DOMAIN_MEMORY_STAT_LAST_UPDATE => assert_eq!(0, stat.val), 173 | sys::VIR_DOMAIN_MEMORY_STAT_RSS => assert!(stat.val > 0), 174 | _ => assert!(stat.tag <= sys::VIR_DOMAIN_MEMORY_STAT_NR), 175 | } 176 | } 177 | common::clean(d); 178 | common::close(c); 179 | } 180 | -------------------------------------------------------------------------------- /tests/interface.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library. If not, see 14 | * . 15 | * 16 | * Sahid Orentino Ferdjaoui 17 | */ 18 | 19 | mod common; 20 | 21 | #[test] 22 | fn test_create() { 23 | let c = common::conn(); 24 | let n = common::build_interface(&c, "wipes"); 25 | assert_eq!(Ok(0), n.create(0)); 26 | assert_eq!(Ok(String::from("libvirt-rs-test-wipes")), n.get_name()); 27 | assert!(!n.get_mac_string().unwrap_or_default().is_empty()); 28 | assert!(!n.get_xml_desc(0).unwrap_or_default().is_empty()); 29 | common::clean_iface(n); 30 | common::close(c); 31 | } 32 | 33 | #[test] 34 | fn test_active() { 35 | let c = common::conn(); 36 | let n = common::build_interface(&c, "active"); 37 | assert_eq!(Ok(false), n.is_active()); 38 | assert_eq!(Ok(0), n.create(0)); 39 | assert_eq!(Ok(true), n.is_active()); 40 | common::clean_iface(n); 41 | common::close(c); 42 | } 43 | 44 | #[test] 45 | fn test_lookup_interface_by_name() { 46 | let c = common::conn(); 47 | let v = c.list_interfaces().unwrap_or_default(); 48 | assert!(!v.is_empty(), "At least one interface should exist"); 49 | common::close(c); 50 | } 51 | -------------------------------------------------------------------------------- /tests/libvirtd.conf: -------------------------------------------------------------------------------- 1 | listen_tls = 0 2 | listen_tcp = 1 3 | tcp_port = "16509" 4 | listen_addr = "127.0.0.1" 5 | auth_unix_rw = "none" 6 | auth_tcp = "sasl" 7 | -------------------------------------------------------------------------------- /tests/libvirtd.sasl: -------------------------------------------------------------------------------- 1 | mech_list: digest-md5 2 | sasldb_path: /etc/libvirt/passwd.db 3 | -------------------------------------------------------------------------------- /tests/network.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library. If not, see 14 | * . 15 | * 16 | * Sahid Orentino Ferdjaoui 17 | */ 18 | 19 | mod common; 20 | 21 | #[test] 22 | fn test_create() { 23 | let c = common::conn(); 24 | let n = common::build_network(&c, "wipes", false); 25 | assert_eq!(Ok(0), n.create()); 26 | assert_eq!(Ok(String::from("libvirt-rs-test-wipes")), n.get_name()); 27 | assert!(n.get_uuid().is_ok()); 28 | assert!(!n.get_uuid_string().unwrap_or_default().is_empty()); 29 | assert!(!n.get_xml_desc(0).unwrap_or_default().is_empty()); 30 | common::clean_net(n); 31 | common::close(c); 32 | } 33 | 34 | #[test] 35 | fn test_active() { 36 | let c = common::conn(); 37 | let n = common::build_network(&c, "active", false); 38 | assert_eq!(Ok(false), n.is_active()); 39 | assert_eq!(Ok(0), n.create()); 40 | assert_eq!(Ok(true), n.is_active()); 41 | common::clean_net(n); 42 | common::close(c); 43 | } 44 | 45 | #[test] 46 | fn test_auto_start() { 47 | let c = common::conn(); 48 | let n = common::build_network(&c, "autostart", false); 49 | assert_eq!(Ok(0), n.create()); 50 | assert_eq!(Ok(false), n.get_autostart()); 51 | assert_eq!(Ok(0), n.set_autostart(true)); 52 | assert_eq!(Ok(true), n.get_autostart()); 53 | common::clean_net(n); 54 | common::close(c); 55 | } 56 | 57 | #[test] 58 | fn test_lookup_network_by_name() { 59 | let c = common::conn(); 60 | let v = c.list_networks().unwrap_or_default(); 61 | assert!(!v.is_empty(), "At least one network should exist"); 62 | common::close(c); 63 | } 64 | -------------------------------------------------------------------------------- /tests/storage_pool.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library. If not, see 14 | * . 15 | * 16 | * Sahid Orentino Ferdjaoui 17 | */ 18 | 19 | use virt::connect::Connect; 20 | use virt::storage_pool::StoragePool; 21 | 22 | mod common; 23 | 24 | #[test] 25 | fn exercices() { 26 | match Connect::open(Some("test:///default")) { 27 | Ok(mut conn) => { 28 | let sp = conn.list_storage_pools().unwrap_or_default(); 29 | assert!(!sp.is_empty(), "At least one storage_pool should exist"); 30 | match StoragePool::lookup_by_name(&conn, &sp[0]) { 31 | Ok(storage_pool) => { 32 | assert!(!storage_pool.get_name().unwrap_or_default().is_empty()); 33 | assert!(!storage_pool 34 | .get_uuid_string() 35 | .unwrap_or_default() 36 | .is_empty()); 37 | assert!(storage_pool.get_uuid().is_ok()); 38 | assert!(!storage_pool.get_xml_desc(0).unwrap_or_default().is_empty()); 39 | } 40 | Err(e) => panic!("{}", e), 41 | } 42 | assert_eq!(0, conn.close().unwrap_or(-1)); 43 | } 44 | Err(e) => panic!("{}", e), 45 | } 46 | } 47 | 48 | #[test] 49 | fn test_lookup_storage_pool_by_name() { 50 | let c = common::conn(); 51 | let v = c.list_storage_pools().unwrap_or_default(); 52 | assert!(!v.is_empty(), "At least one storage_pool should exist"); 53 | match StoragePool::lookup_by_name(&c, &v[0]) { 54 | Ok(mut s) => s.free().unwrap_or(()), 55 | Err(e) => panic!("{}", e), 56 | } 57 | common::close(c); 58 | } 59 | -------------------------------------------------------------------------------- /tests/stream.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library. If not, see 14 | * . 15 | * 16 | * Sahid Orentino Ferdjaoui 17 | */ 18 | 19 | mod common; 20 | 21 | use virt::stream::Stream; 22 | use virt::sys; 23 | 24 | #[test] 25 | fn test_create_blocking() { 26 | let c = common::conn(); 27 | let s = Stream::new(&c, 0).unwrap(); 28 | drop(s); 29 | common::close(c); 30 | } 31 | 32 | #[test] 33 | fn test_create_non_blocking() { 34 | let c = common::conn(); 35 | let s = Stream::new(&c, sys::VIR_STREAM_NONBLOCK).unwrap(); 36 | drop(s); 37 | common::close(c); 38 | } 39 | -------------------------------------------------------------------------------- /tools/api_tests.py: -------------------------------------------------------------------------------- 1 | # Just tool to help finding what is implemented and what is missing 2 | 3 | import os 4 | import glob 5 | import xml.etree.ElementTree 6 | import sys 7 | 8 | 9 | LIBVIRT_API_FILE = "/usr/share/libvirt/api/libvirt-api.xml" 10 | MY_PATH = os.path.dirname(os.path.realpath(__file__)) 11 | SRC_PATH = MY_PATH + "/../src" 12 | 13 | 14 | def get_api_symbols(doc): 15 | funcs = doc.iter('function') 16 | macros = doc.iter('macro') 17 | enums = doc.iter('enum') 18 | return funcs, macros, enums 19 | 20 | 21 | def get_sources(): 22 | return glob.glob(SRC_PATH + "/*.rs") 23 | 24 | 25 | def match(el, content): 26 | return content.find(el) >= 0 27 | 28 | 29 | def main(): 30 | filter_by = "" 31 | if len(sys.argv) > 1: 32 | filter_by = sys.argv[1] 33 | 34 | doc = xml.etree.ElementTree.parse(LIBVIRT_API_FILE).getroot() 35 | 36 | implemented = set([]) 37 | missing = set([]) 38 | for el in doc.iter('function'): 39 | 40 | if el.get('name').startswith(filter_by): # What I'm looking for 41 | 42 | status = False 43 | for source in get_sources(): 44 | f = open(source) 45 | if match(el.get('name'), f.read()): 46 | status = True 47 | break 48 | if status: 49 | implemented.add(el) 50 | else: 51 | missing.add(el) 52 | 53 | print("missing: %s, implemented: %s" % (len(missing), len(implemented))) 54 | print("missing:") 55 | for x in missing: 56 | print(x.attrib) 57 | # print "implemented:" 58 | # for x in implemented: 59 | # print x.attrib 60 | 61 | 62 | if __name__ == '__main__': 63 | main() 64 | -------------------------------------------------------------------------------- /virt-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "virt-sys" 3 | version = "0.3.0" 4 | edition = "2021" 5 | authors = ["Wim de With ",] 6 | license = "LGPL-2.1" 7 | description = "Native bindings to the libvirt C library" 8 | repository = "https://gitlab.com/libvirt/libvirt-rust" 9 | homepage = "https://libvirt.org/" 10 | categories = ["external-ffi-bindings",] 11 | links = "virt" 12 | 13 | [dependencies] 14 | libc = "0.2.122" 15 | 16 | [build-dependencies] 17 | bindgen = { version = "0.69.2", optional = true } 18 | pkg-config = "0.3.25" 19 | 20 | [features] 21 | qemu = [] 22 | bindgen_regenerate = ["bindgen"] 23 | -------------------------------------------------------------------------------- /virt-sys/build.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::fs; 3 | use std::path::PathBuf; 4 | use std::{env, process}; 5 | 6 | const LIBVIRT_VERSION: &str = "6.0.0"; 7 | 8 | fn main() { 9 | match run() { 10 | Ok(()) => {} 11 | Err(e) => { 12 | eprintln!("error: {}", e); 13 | process::exit(1); 14 | } 15 | } 16 | } 17 | 18 | #[cfg(feature = "bindgen_regenerate")] 19 | fn bindgen_regenerate(bindgen_out_file: &PathBuf) -> Result<(), Box> { 20 | 21 | // We want to make sure that the generated bindings.rs file includes all libvirt APIs, 22 | // including the ones that are QEMU-specific 23 | if !cfg!(feature = "qemu") { 24 | return Err("qemu must be enabled along with bindgen_regenerate".into()) 25 | } 26 | 27 | let bindings = bindgen::builder() 28 | .header("wrapper.h") 29 | .allowlist_var("^(VIR_|vir).*") 30 | .allowlist_type("^vir.*") 31 | .allowlist_function("^vir.*") 32 | // this is only false on esoteric platforms which libvirt does not support 33 | .size_t_is_usize(true) 34 | .generate_comments(false) 35 | .prepend_enum_name(false) 36 | .generate_cstr(true) 37 | .ctypes_prefix("::libc") 38 | .formatter(bindgen::Formatter::Prettyplease); 39 | 40 | bindings 41 | .generate() 42 | .map_err(|_| String::from("could not generate bindings"))? 43 | .write_to_file(bindgen_out_file)?; 44 | 45 | Ok(()) 46 | } 47 | 48 | #[cfg(not(feature = "bindgen_regenerate"))] 49 | fn bindgen_regenerate(_: &PathBuf) -> Result<(), Box> { 50 | 51 | // We haven't been asked to regenerate bindings.rs, so nothing to do here 52 | Ok(()) 53 | } 54 | 55 | fn run() -> Result<(), Box> { 56 | println!("cargo:rerun-if-changed=wrapper.h"); 57 | 58 | let mut config = pkg_config::Config::new(); 59 | 60 | // Normally we would make the calls to probe() fatal by not ignoring their return value, but we 61 | // want to be able to build the documentation for the library even when the libvirt header 62 | // files are not present. This is necessary so that docs.rs can build and publish the API 63 | // documentation for libvirt-rust. If any of these calls fail, then we'll still get an error 64 | // when attempting to link against libvirt (e.g. when building the test suite). 65 | let _ = config 66 | .atleast_version(LIBVIRT_VERSION) 67 | .probe("libvirt"); 68 | 69 | if cfg!(feature = "qemu") { 70 | let _ = config 71 | .atleast_version(LIBVIRT_VERSION) 72 | .probe("libvirt-qemu"); 73 | } 74 | 75 | let bindgen_in_dir = PathBuf::from("bindgen"); 76 | let bindgen_in_file = bindgen_in_dir.join("bindings.rs"); 77 | let bindgen_out_dir = PathBuf::from(env::var("OUT_DIR")?); 78 | let bindgen_out_file = bindgen_out_dir.join("bindings.rs"); 79 | 80 | bindgen_regenerate(&bindgen_in_file)?; 81 | 82 | fs::copy(bindgen_in_file, bindgen_out_file)?; 83 | 84 | Ok(()) 85 | } 86 | -------------------------------------------------------------------------------- /virt-sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_camel_case_types, non_snake_case, non_upper_case_globals)] 2 | 3 | // Bindgen generated tests dereference null pointers for struct layout testing. 4 | #![cfg_attr(test, allow(unknown_lints, deref_nullptr))] 5 | 6 | pub type _virTypedParameterValue = _virTypedParameter__bindgen_ty_1; 7 | 8 | include!(concat!(env!("OUT_DIR"), "/bindings.rs")); 9 | -------------------------------------------------------------------------------- /virt-sys/wrapper.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | --------------------------------------------------------------------------------