Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Factory:Rebuild
krunvm
krunvm-0.2.3+git12dac81.obscpio
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File krunvm-0.2.3+git12dac81.obscpio of Package krunvm
07070100000000000041ED000000000000000000000001636923F100000000000000000000000000000000000000000000002000000000krunvm-0.2.3+git12dac81/.github07070100000001000041ED000000000000000000000001636923F100000000000000000000000000000000000000000000002A00000000krunvm-0.2.3+git12dac81/.github/workflows07070100000002000081A4000000000000000000000001636923F100000378000000000000000000000000000000000000003B00000000krunvm-0.2.3+git12dac81/.github/workflows/code_quality.ymlname: Code Quality (rustfmt and clippy) on: [pull_request, create] jobs: build: if: github.event_name == 'pull_request' name: Code Quality (clippy, rustfmt) runs-on: ubuntu-latest strategy: matrix: rust: - stable target: - x86_64-unknown-linux-gnu steps: - name: Code checkout uses: actions/checkout@v2 - name: Install Rust toolchain (${{ matrix.rust }}) uses: actions-rs/toolchain@v1 with: toolchain: ${{ matrix.rust }} target: ${{ matrix.target }} override: true components: rustfmt, clippy - name: Install asciidoctor run: sudo apt-get install -y asciidoctor - name: Formatting (rustfmt) run: cargo fmt -- --check - name: Clippy (all features) run: cargo clippy --all-targets --all-features 07070100000003000081A4000000000000000000000001636923F100000038000000000000000000000000000000000000002300000000krunvm-0.2.3+git12dac81/.gitignore/build/ target *.rs.bk *.iml .idea __pycache__ *.pyc *~ 07070100000004000081A4000000000000000000000001636923F1000000BD000000000000000000000000000000000000002B00000000krunvm-0.2.3+git12dac81/CODE-OF-CONDUCT.md## The krunvm Project Community Code of Conduct The krunvm Project follows the [Containers Community Code of Conduct](https://github.com/containers/common/blob/master/CODE-OF-CONDUCT.md). 07070100000005000081A4000000000000000000000001636923F10000229E000000000000000000000000000000000000002300000000krunvm-0.2.3+git12dac81/Cargo.lock# This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "ansi_term" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" dependencies = [ "winapi", ] [[package]] name = "arrayref" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" [[package]] name = "arrayvec" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", "winapi", ] [[package]] name = "autocfg" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "base64" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "blake2b_simd" version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" dependencies = [ "arrayref", "arrayvec", "constant_time_eq", ] [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" version = "2.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" dependencies = [ "ansi_term", "atty", "bitflags", "strsim", "textwrap", "unicode-width", "vec_map", ] [[package]] name = "confy" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2913470204e9e8498a0f31f17f90a0de801ae92c8c5ac18c49af4819e6786697" dependencies = [ "directories", "serde", "toml", ] [[package]] name = "constant_time_eq" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "crossbeam-utils" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" dependencies = [ "autocfg", "cfg-if 1.0.0", "lazy_static", ] [[package]] name = "directories" version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" dependencies = [ "cfg-if 0.1.10", "dirs-sys", ] [[package]] name = "dirs-sys" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" dependencies = [ "libc", "redox_users", "winapi", ] [[package]] name = "getrandom" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ "cfg-if 1.0.0", "libc", "wasi", ] [[package]] name = "hermit-abi" version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" dependencies = [ "libc", ] [[package]] name = "krunvm" version = "0.2.3" dependencies = [ "clap", "confy", "libc", "serde", "serde_derive", "text_io", ] [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba4aede83fc3617411dc6993bc8c70919750c1c257c6ca6a502aed6e0e2394ae" [[package]] name = "proc-macro2" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ "unicode-xid", ] [[package]] name = "quote" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "redox_users" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" dependencies = [ "getrandom", "redox_syscall", "rust-argon2", ] [[package]] name = "rust-argon2" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" dependencies = [ "base64", "blake2b_simd", "constant_time_eq", "crossbeam-utils", ] [[package]] name = "serde" version = "1.0.124" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f" [[package]] name = "serde_derive" version = "1.0.124" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "strsim" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "syn" version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] [[package]] name = "text_io" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6cb170b4f47dc48835fbc56259c12d8963e542b05a24be2e3a1f5a6c320fd2d4" [[package]] name = "textwrap" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" dependencies = [ "unicode-width", ] [[package]] name = "toml" version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" dependencies = [ "serde", ] [[package]] name = "unicode-width" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" [[package]] name = "unicode-xid" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[package]] name = "vec_map" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 07070100000006000081A4000000000000000000000001636923F100000174000000000000000000000000000000000000002300000000krunvm-0.2.3+git12dac81/Cargo.toml[package] name = "krunvm" version = "0.2.3" authors = ["Sergio Lopez <slp@redhat.com>"] description = "Create microVMs from OCI images" repository = "https://github.com/containers/krunvm" license = "Apache-2.0" edition = "2018" build = "build.rs" [dependencies] clap = "2.33.3" confy = "0.4.0" libc = "0.2.82" serde = "1.0.120" serde_derive = "1.0.120" text_io = "0.1.8" 07070100000007000081A4000000000000000000000001636923F100002C5E000000000000000000000000000000000000002000000000krunvm-0.2.3+git12dac81/LICENSE Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 07070100000008000081A4000000000000000000000001636923F10000022A000000000000000000000000000000000000002100000000krunvm-0.2.3+git12dac81/MakefileOS = $(shell uname -s) KRUNVM_RELEASE = target/release/krunvm KRUNVM_DEBUG = target/debug/krunvm INIT_BINARY = init/init ifeq ($(PREFIX),) PREFIX := /usr/local endif .PHONY: install clean all: $(KRUNVM_RELEASE) debug: $(KRUNVM_DEBUG) $(KRUNVM_RELEASE): cargo build --release ifeq ($(OS),Darwin) codesign --entitlements krunvm.entitlements --force -s - $@ endif $(KRUNVM_DEBUG): cargo build --debug install: $(KRUNVM_RELEASE) install -d $(DESTDIR)$(PREFIX)/bin install -m 755 $(KRUNVM_RELEASE) $(DESTDIR)$(PREFIX)/bin clean: cargo clean 07070100000009000081A4000000000000000000000001636923F10000042B000000000000000000000000000000000000002200000000krunvm-0.2.3+git12dac81/README.md# krunvm ```krunvm``` is a CLI-based utility for creating microVMs from OCI images, using [libkrun](https://github.com/containers/libkrun) and [buildah](https://github.com/containers/buildah). ## Features * Minimal footprint * Fast boot time * Zero disk image maintenance * Zero network configuration * Support for mapping host volumes into the guest * Support for exposing guest ports to the host ## Demo [![asciicast](https://asciinema.org/a/CGtTS93VsdzWwUfkY1kqVnaik.svg)](https://asciinema.org/a/CGtTS93VsdzWwUfkY1kqVnaik) ## Supported platforms - Linux/KVM on x86_64. - Linux/KVM on AArch64. - macOS/Hypervisor.framework on ARM64. ## Installation ### macOS ``` brew tap slp/krun brew install krunvm ``` ### Fedora ``` dnf copr enable -y slp/libkrunfw dnf copr enable -y slp/libkrun dnf copr enable -y slp/krunvm dnf install -y krunvm ``` ### Building from sources #### Dependencies * Rust Toolchain * [libkrun](https://github.com/containers/libkrun) * [buildah](https://github.com/containers/buildah) #### Building ``` cargo build --release ``` 0707010000000A000081A4000000000000000000000001636923F1000000EE000000000000000000000000000000000000002400000000krunvm-0.2.3+git12dac81/SECURITY.md## Security and Disclosure Information Policy for the krunvm Project The krunvm Project follows the [Security and Disclosure Information Policy](https://github.com/containers/common/blob/master/SECURITY.md) for the Containers Projects. 0707010000000B000081A4000000000000000000000001636923F1000006A0000000000000000000000000000000000000002100000000krunvm-0.2.3+git12dac81/build.rsuse std::path::Path; use std::{env, fs, io, process}; const COMMANDS: [&str; 7] = [ "krunvm", "krunvm-changevm", "krunvm-create", "krunvm-config", "krunvm-delete", "krunvm-list", "krunvm-start", ]; fn main() { let outdir = match env::var_os("OUT_DIR") { Some(outdir) => outdir, None => { panic!("OUT_DIR environment variable not defined."); } }; fs::create_dir_all(&outdir).unwrap(); for command in COMMANDS { if let Err(err) = generate_man_page(&outdir, command) { panic!("failed to generate man page: {}", err); } } #[cfg(target_os = "macos")] println!("cargo:rustc-link-search=/opt/homebrew/lib"); } fn generate_man_page<P: AsRef<Path>>(outdir: P, command: &str) -> io::Result<()> { // If asciidoctor isn't installed, fallback to asciidoc. if let Err(err) = process::Command::new("asciidoctor").output() { eprintln!("Error from running 'asciidoctor': {}", err); return Err(err); } let outdir = outdir.as_ref(); let outfile = outdir.join(format!("{}.1", command)); let cwd = env::current_dir()?; let txt_path = cwd.join("docs").join(format!("{}.1.txt", command)); let result = process::Command::new("asciidoctor") .arg("--doctype") .arg("manpage") .arg("--backend") .arg("manpage") .arg("--out-file") .arg(&outfile) .arg(&txt_path) .spawn()? .wait()?; if !result.success() { let msg = format!("'asciidoctor' failed with exit code {:?}", result.code()); return Err(io::Error::new(io::ErrorKind::Other, msg)); } Ok(()) } 0707010000000C000041ED000000000000000000000001636923F100000000000000000000000000000000000000000000001D00000000krunvm-0.2.3+git12dac81/docs0707010000000D000081A4000000000000000000000001636923F1000006AD000000000000000000000000000000000000003300000000krunvm-0.2.3+git12dac81/docs/krunvm-changevm.1.txtkrunvm-changevm(1) ================== NAME ---- krunvm-changevm - Change the configuration of a microVM SYNOPSIS -------- *krunvm changevm* [_OPTIONS_] _microVM_ DESCRIPTION ----------- *krunvm changevm* changes the configuration of an existing microVM. When run without any _OPTIONS_, it displays the current configuration of the microVM. OPTIONS ------- *--remove-ports*:: Removes all port mappings. *--remote-volumes*:: Removes all volume mappings. *--cpus* _NUM_:: Changes the number of vCPUs that will be created for this microVM. *--mem* _NUM_:: Changes the amount of RAM, in MiB, that will be available to this microVM. + The memory configured for the microVM will not be reserved immediately. Instead, it will be provided as the guest demands it, and both the guest and libkrun (acting as the Virtual Machine Monitor) will attempt to return as many pages as possible to the host. *--name* _NAME_:: Assigns a new name to the microVM. *-p, --port* _HOST_PORT:GUEST_PORT_:: Exposes a port in the guest running in the microVM through a port in the host. + This option can be specified multiple times to expose as many guest ports as desired. *-v, --volume* _HOST_PATH:GUEST_PATH_:: Makes _HOST_PATH_ visible in the guest running in the microVM through _GUEST_PATH_. + This option can be specified multiple times to make more paths in the host visible in the guest. *-w, --workdir* _GUEST_PATH_:: Configures _GUEST_PATH_ as the working directory for the first binary executed in the microVM. + An empty string ("") tells krunvm to not set a working directory explicitly, letting libkrun decide which one should be set. SEE ALSO -------- *krunvm(1)*, *krunvm-create(1)* 0707010000000E000081A4000000000000000000000001636923F1000002F2000000000000000000000000000000000000003100000000krunvm-0.2.3+git12dac81/docs/krunvm-config.1.txtkrunvm-config(1) ================ NAME ---- krunvm-config - Configure default values SYNOPSIS -------- *krunvm config* [_OPTIONS_] DESCRIPTION ----------- *krunvm config* configures the default values that will be used for newly created microVMs when a explicit value has not been passed to *krunvm-create(1)* When run without any _OPTIONS_ it displays the current default values. OPTIONS ------- *--cpus* _NUM_:: Sets the default number of vCPUs that will be configured for newly created microVMs. *--dns* _IP_:: Sets the default IP that will be configured as DNS for newly created microVMs. *--mem* _NUM_:: Sets the default mount of RAM, in MiB, that will be configured for newly created microVMs. SEE ALSO -------- *krunvm(1)* 0707010000000F000081A4000000000000000000000001636923F10000066F000000000000000000000000000000000000003100000000krunvm-0.2.3+git12dac81/docs/krunvm-create.1.txtkrunvm-create(1) ================ NAME ---- krunvm-create - Create a new microVM from an OCI image SYNOPSIS -------- *krunvm create* [_OPTIONS_] _IMAGE_ DESCRIPTION ----------- *krunvm create* creates a new microVM from the OCI image specified by _IMAGE_. Please refer to buildah-from(1) for information about the format supported by the _IMAGE_ argument. OPTIONS ------- *--cpus* _NUM_:: The number of vCPUs that will be created for this microVM. *--mem* _NUM_:: The amount of RAM, in MiB, that will be available to this microVM. + The memory configured for the microVM will not be reserved immediately. Instead, it will be provided as the guest demands it, and both the guest and libkrun (acting as the Virtual Machine Monitor) will attempt to return as many pages as possible to the host. *--name* _NAME_:: The name to be assigned to this microVM. *-p, --port* _HOST_PORT:GUEST_PORT_:: Exposes a port in the guest running in the microVM through a port in the host. + This option can be specified multiple times to expose as many guest ports as desired. *-v, --volume* _HOST_PATH:GUEST_PATH_:: Makes _HOST_PATH_ visible in the guest running in the microVM through _GUEST_PATH_. + This option can be specified multiple times to make more paths in the host visible in the guest. *-w, --workdir* _GUEST_PATH_:: Configures _GUEST_PATH_ as the working directory for the first binary executed in the microVM. + An empty string ("") tells krunvm to not set a working directory explicitly, letting libkrun decide which one should be set. SEE ALSO -------- *buildah(1)*, *buildah-from(1)*, *krunvm(1)*, *krunvm-changevm(1)* 07070100000010000081A4000000000000000000000001636923F10000015D000000000000000000000000000000000000003100000000krunvm-0.2.3+git12dac81/docs/krunvm-delete.1.txtkrunvm-delete(1) ================ NAME ---- krunvm-delete - Deletes an existing microVM SYNOPSIS -------- *krunvm delete* _microVM_ DESCRIPTION ----------- *krunvm delete* deletes an existing microVM configuration and requests to buildah(1) to unmount and remove the OCI image that was backing it. SEE ALSO -------- *buildah(1)*, *krunvm(1)* 07070100000011000081A4000000000000000000000001636923F100000148000000000000000000000000000000000000002F00000000krunvm-0.2.3+git12dac81/docs/krunvm-list.1.txtkrunvm-list(1) ============== NAME ---- krunvm-list - Lists the existing microVMs SYNOPSIS -------- *krunvm list* DESCRIPTION ----------- *krunvm list* lists the microVMs created by *krunvm-create(1)* that have not been removed by *krunvm-delete(1)*. SEE ALSO -------- *krunvm(1)*, *krunvm-create(1)*, *krunvm-delete(1)* 07070100000012000081A4000000000000000000000001636923F100000398000000000000000000000000000000000000003000000000krunvm-0.2.3+git12dac81/docs/krunvm-start.1.txtkrunvm-start(1) =============== NAME ---- krunvm-start - Starts an existing microVM SYNOPSIS -------- *krunvm start* [_OPTIONS_] _microVM_ [_COMMAND_] [-- ARGS] DESCRIPTION ----------- *krunvm start* starts an existing microVM created by krunvm-create(1) and attaches stdin/stdout to its virtio-console providing a seamless experience for interacting with the guest running inside it. _COMMAND_ is the first binary to be executed in the microVM. If it's not present in the command line, krunvm-start(1) lets libkrun decide which binary will be executed. Additional arguments for _COMMAND_ can be specified in the command line by appending _--_ followed by _ARGS_. OPTIONS ------- *--cpus* _NUM_:: Override the number of vCPUs configured for this microVM. *--mem* _NUM_:: Override amount of RAM, in MiB, configured for this microVM. SEE ALSO -------- *krunvm(1)*, *krunvm-create(1)*, *krunvm-changevm(1)* 07070100000013000081A4000000000000000000000001636923F1000005C5000000000000000000000000000000000000002A00000000krunvm-0.2.3+git12dac81/docs/krunvm.1.txtkrunvm(1) ========= NAME ---- krunvm - Create microVMs from OCI images SYNOPSIS -------- *krunvm* [_GLOBAL_OPTIONS_] *command* DESCRIPTION ----------- krunvm is a CLI utility to create, manage and start microVMs which are generated from OCI images, providing an interface that resembles operating on conventional containers. krunvm uses buildah(1) to download the OCI image and mount it into a local directory, and libkrun to launch the microVM. The local directory where the OCI image has been mounted is used as the root filesystem for the microVM, serviced by a virtio-fs device/server bundled into libkrun. krunvm supports mounting additional local directories into the microVM and exposing ports from the guest to the host (and the networks connected to it). Networking to the guest running in the microVM is provided by libkrun's TSI (Transparent Socket Impersonation), enabling a seamless experience that doesn't require network bridges nor other explicit network configuration. GLOBAL OPTIONS -------------- *-v* _NUM_:: Sets the verbosity level, from the lowest (0) to the highest (5). COMMANDS -------- |=== |Command | Description |krunvm-changevm(1) | Change the configuration of a microVM |krunvm-config(1) | Configure global values |krunvm-create(1) | Create a new microVM |krunvm-delete(1) | Delete an existing microVM |krunvm-list(1) | List the existing microVMs |krunvm-start(1) | Start an existing microVM |=== SEE ALSO -------- *buildah(1)* 07070100000014000081A4000000000000000000000001636923F100000136000000000000000000000000000000000000002C00000000krunvm-0.2.3+git12dac81/krunvm.entitlements<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.security.hypervisor</key> <true/> <key>com.apple.security.cs.disable-library-validationr</key> <true/> </dict> </plist> 07070100000015000041ED000000000000000000000001636923F100000000000000000000000000000000000000000000001C00000000krunvm-0.2.3+git12dac81/src07070100000016000081A4000000000000000000000001636923F10000036F000000000000000000000000000000000000002800000000krunvm-0.2.3+git12dac81/src/bindings.rs// Copyright 2021 Red Hat, Inc. // SPDX-License-Identifier: Apache-2.0 #[link(name = "krun")] extern "C" { pub fn krun_set_log_level(level: u32) -> i32; pub fn krun_create_ctx() -> i32; pub fn krun_free_ctx(ctx: u32) -> i32; pub fn krun_set_vm_config(ctx: u32, num_vcpus: u8, ram_mib: u32) -> i32; pub fn krun_set_root(ctx: u32, root_path: *const i8) -> i32; pub fn krun_set_mapped_volumes(ctx: u32, mapped_volumes: *const *const i8) -> i32; pub fn krun_set_port_map(ctx: u32, port_map: *const *const i8) -> i32; pub fn krun_set_workdir(ctx: u32, workdir_path: *const i8) -> i32; pub fn krun_set_exec( ctx: u32, exec_path: *const i8, argv: *const *const i8, envp: *const *const i8, ) -> i32; pub fn krun_set_env(ctx: u32, envp: *const *const i8) -> i32; pub fn krun_start_enter(ctx: u32) -> i32; } 07070100000017000081A4000000000000000000000001636923F100000DAB000000000000000000000000000000000000002800000000krunvm-0.2.3+git12dac81/src/changevm.rs// Copyright 2021 Red Hat, Inc. // SPDX-License-Identifier: Apache-2.0 use std::collections::HashMap; use crate::{ArgMatches, KrunvmConfig, APP_NAME}; use super::list::printvm; use super::utils::{parse_mapped_ports, parse_mapped_volumes}; pub fn changevm(cfg: &mut KrunvmConfig, matches: &ArgMatches) { let mut cfg_changed = false; let name = matches.value_of("NAME").unwrap(); let mut vmcfg = if let Some(new_name) = matches.value_of("new-name") { if cfg.vmconfig_map.contains_key(new_name) { println!("A VM with name {} already exists", new_name); std::process::exit(-1); } let mut vmcfg = match cfg.vmconfig_map.remove(name) { None => { println!("No VM found with name {}", name); std::process::exit(-1); } Some(vmcfg) => vmcfg, }; cfg_changed = true; let name = new_name.to_string(); vmcfg.name = name.clone(); cfg.vmconfig_map.insert(name.clone(), vmcfg); cfg.vmconfig_map.get_mut(&name).unwrap() } else { match cfg.vmconfig_map.get_mut(name) { None => { println!("No VM found with name {}", name); std::process::exit(-1); } Some(vmcfg) => vmcfg, } }; if let Some(cpus_str) = matches.value_of("cpus") { match cpus_str.parse::<u32>() { Err(_) => println!("Invalid value for \"cpus\""), Ok(cpus) => { if cpus > 8 { println!("Error: the maximum number of CPUs supported is 8"); } else { vmcfg.cpus = cpus; cfg_changed = true; } } } } if let Some(mem_str) = matches.value_of("mem") { match mem_str.parse::<u32>() { Err(_) => println!("Invalid value for \"mem\""), Ok(mem) => { if mem > 16384 { println!("Error: the maximum amount of RAM supported is 16384 MiB"); } else { vmcfg.mem = mem; cfg_changed = true; } } } } if matches.is_present("remove-volumes") { vmcfg.mapped_volumes = HashMap::new(); cfg_changed = true; } else { let volume_matches = if matches.is_present("volume") { matches.values_of("volume").unwrap().collect() } else { vec![] }; let mapped_volumes = parse_mapped_volumes(volume_matches); if !mapped_volumes.is_empty() { vmcfg.mapped_volumes = mapped_volumes; cfg_changed = true; } } if matches.is_present("remove-ports") { vmcfg.mapped_ports = HashMap::new(); cfg_changed = true; } else { let port_matches = if matches.is_present("port") { matches.values_of("port").unwrap().collect() } else { vec![] }; let mapped_ports = parse_mapped_ports(port_matches); if !mapped_ports.is_empty() { vmcfg.mapped_ports = mapped_ports; cfg_changed = true; } } if let Some(workdir) = matches.value_of("workdir") { vmcfg.workdir = workdir.to_string(); cfg_changed = true; } println!(); printvm(vmcfg); println!(); if cfg_changed { confy::store(APP_NAME, &cfg).unwrap(); } } 07070100000018000081A4000000000000000000000001636923F100000699000000000000000000000000000000000000002600000000krunvm-0.2.3+git12dac81/src/config.rs// Copyright 2021 Red Hat, Inc. // SPDX-License-Identifier: Apache-2.0 use crate::{ArgMatches, KrunvmConfig, APP_NAME}; pub fn config(cfg: &mut KrunvmConfig, matches: &ArgMatches) { let mut cfg_changed = false; if let Some(cpus_str) = matches.value_of("cpus") { match cpus_str.parse::<u32>() { Err(_) => println!("Invalid value for \"cpus\""), Ok(cpus) => { if cpus > 8 { println!("Error: the maximum number of CPUs supported is 8"); } else { cfg.default_cpus = cpus; cfg_changed = true; } } } } if let Some(mem_str) = matches.value_of("mem") { match mem_str.parse::<u32>() { Err(_) => println!("Invalid value for \"mem\""), Ok(mem) => { if mem > 16384 { println!("Error: the maximum amount of RAM supported is 16384 MiB"); } else { cfg.default_mem = mem; cfg_changed = true; } } } } if let Some(dns) = matches.value_of("dns") { cfg.default_dns = dns.to_string(); cfg_changed = true; } if cfg_changed { confy::store(APP_NAME, &cfg).unwrap(); } println!("Global configuration:"); println!( "Default number of CPUs for newly created VMs: {}", cfg.default_cpus ); println!( "Default amount of RAM (MiB) for newly created VMs: {}", cfg.default_mem ); println!( "Default DNS server for newly created VMs: {}", cfg.default_dns ); } 07070100000019000081A4000000000000000000000001636923F10000191D000000000000000000000000000000000000002600000000krunvm-0.2.3+git12dac81/src/create.rs// Copyright 2021 Red Hat, Inc. // SPDX-License-Identifier: Apache-2.0 use std::fs; use std::io::Write; #[cfg(target_os = "macos")] use std::path::Path; use std::process::Command; use super::utils::{ get_buildah_args, mount_container, parse_mapped_ports, parse_mapped_volumes, umount_container, BuildahCommand, }; use crate::{ArgMatches, KrunvmConfig, VmConfig, APP_NAME}; #[cfg(target_os = "macos")] const KRUNVM_ROSETTA_FILE: &str = ".krunvm-rosetta"; fn fix_resolv_conf(rootfs: &str, dns: &str) -> Result<(), std::io::Error> { let resolvconf_dir = format!("{}/etc/", rootfs); fs::create_dir_all(resolvconf_dir)?; let resolvconf = format!("{}/etc/resolv.conf", rootfs); let mut file = fs::File::create(resolvconf)?; file.write_all(b"options use-vc\nnameserver ")?; file.write_all(dns.as_bytes())?; file.write_all(b"\n")?; Ok(()) } fn export_container_config( cfg: &KrunvmConfig, rootfs: &str, image: &str, ) -> Result<(), std::io::Error> { let mut args = get_buildah_args(cfg, BuildahCommand::Inspect); args.push(image.to_string()); let output = match Command::new("buildah") .args(&args) .stderr(std::process::Stdio::inherit()) .output() { Ok(output) => output, Err(err) => { if err.kind() == std::io::ErrorKind::NotFound { println!("{} requires buildah to manage the OCI images, and it wasn't found on this system.", APP_NAME); } else { println!("Error executing buildah: {}", err); } std::process::exit(-1); } }; let exit_code = output.status.code().unwrap_or(-1); if exit_code != 0 { println!( "buildah returned an error: {}", std::str::from_utf8(&output.stdout).unwrap() ); std::process::exit(-1); } let mut file = fs::File::create(format!("{}/.krun_config.json", rootfs))?; file.write_all(&output.stdout)?; Ok(()) } pub fn create(cfg: &mut KrunvmConfig, matches: &ArgMatches) { let mut cpus = match matches.value_of("cpus") { Some(c) => match c.parse::<u32>() { Err(_) => { println!("Invalid value for \"cpus\""); std::process::exit(-1); } Ok(cpus) => cpus, }, None => cfg.default_cpus, }; let mem = match matches.value_of("mem") { Some(m) => match m.parse::<u32>() { Err(_) => { println!("Invalid value for \"mem\""); std::process::exit(-1); } Ok(mem) => mem, }, None => cfg.default_mem, }; let dns = match matches.value_of("dns") { Some(d) => d, None => &cfg.default_dns, }; let workdir = matches.value_of("workdir").unwrap(); let volume_matches = if matches.is_present("volume") { matches.values_of("volume").unwrap().collect() } else { vec![] }; let mapped_volumes = parse_mapped_volumes(volume_matches); let port_matches = if matches.is_present("port") { matches.values_of("port").unwrap().collect() } else { vec![] }; let mapped_ports = parse_mapped_ports(port_matches); let image = matches.value_of("IMAGE").unwrap(); let name = matches.value_of("name"); if let Some(name) = name { if cfg.vmconfig_map.contains_key(name) { println!("A VM with this name already exists"); std::process::exit(-1); } } let mut args = get_buildah_args(cfg, BuildahCommand::From); #[cfg(target_os = "macos")] let force_x86 = matches.is_present("x86"); #[cfg(target_os = "macos")] if force_x86 { let home = match std::env::var("HOME") { Err(e) => { println!("Error reading \"HOME\" enviroment variable: {}", e); std::process::exit(-1); } Ok(home) => home, }; let path = format!("{}/{}", home, KRUNVM_ROSETTA_FILE); if !Path::new(&path).is_file() { println!( " To use Rosetta for Linux you need to create the file... {} ...with the contents that the \"rosetta\" binary expects to be served from its specific ioctl. For more information, please refer to this post: https://threedots.ovh/blog/2022/06/quick-look-at-rosetta-on-linux/ ", path ); std::process::exit(-1); } if cpus != 1 { println!("x86 microVMs on Aarch64 are restricted to 1 CPU"); cpus = 1; } args.push("--arch".to_string()); args.push("x86_64".to_string()); } args.push(image.to_string()); let output = match Command::new("buildah") .args(&args) .stderr(std::process::Stdio::inherit()) .output() { Ok(output) => output, Err(err) => { if err.kind() == std::io::ErrorKind::NotFound { println!("{} requires buildah to manage the OCI images, and it wasn't found on this system.", APP_NAME); } else { println!("Error executing buildah: {}", err); } std::process::exit(-1); } }; let exit_code = output.status.code().unwrap_or(-1); if exit_code != 0 { println!( "buildah returned an error: {}", std::str::from_utf8(&output.stdout).unwrap() ); std::process::exit(-1); } let container = std::str::from_utf8(&output.stdout).unwrap().trim(); let name = if let Some(name) = name { name.to_string() } else { container.to_string() }; let vmcfg = VmConfig { name: name.clone(), cpus, mem, dns: dns.to_string(), container: container.to_string(), workdir: workdir.to_string(), mapped_volumes, mapped_ports, }; let rootfs = mount_container(cfg, &vmcfg).unwrap(); export_container_config(cfg, &rootfs, image).unwrap(); fix_resolv_conf(&rootfs, dns).unwrap(); #[cfg(target_os = "macos")] if force_x86 { _ = fs::create_dir(format!("{}/.rosetta", rootfs)); } umount_container(cfg, &vmcfg).unwrap(); cfg.vmconfig_map.insert(name.clone(), vmcfg); confy::store(APP_NAME, cfg).unwrap(); println!("microVM created with name: {}", name); } 0707010000001A000081A4000000000000000000000001636923F10000027A000000000000000000000000000000000000002600000000krunvm-0.2.3+git12dac81/src/delete.rs// Copyright 2021 Red Hat, Inc. // SPDX-License-Identifier: Apache-2.0 use crate::{ArgMatches, KrunvmConfig, APP_NAME}; use super::utils::{remove_container, umount_container}; pub fn delete(cfg: &mut KrunvmConfig, matches: &ArgMatches) { let name = matches.value_of("NAME").unwrap(); let vmcfg = match cfg.vmconfig_map.remove(name) { None => { println!("No VM found with that name"); std::process::exit(-1); } Some(vmcfg) => vmcfg, }; umount_container(cfg, &vmcfg).unwrap(); remove_container(cfg, &vmcfg).unwrap(); confy::store(APP_NAME, &cfg).unwrap(); } 0707010000001B000081A4000000000000000000000001636923F10000031D000000000000000000000000000000000000002400000000krunvm-0.2.3+git12dac81/src/list.rs// Copyright 2021 Red Hat, Inc. // SPDX-License-Identifier: Apache-2.0 use crate::{ArgMatches, KrunvmConfig, VmConfig}; pub fn printvm(vm: &VmConfig) { println!("{}", vm.name); println!(" CPUs: {}", vm.cpus); println!(" RAM (MiB): {}", vm.mem); println!(" DNS server: {}", vm.dns); println!(" Buildah container: {}", vm.container); println!(" Workdir: {}", vm.workdir); println!(" Mapped volumes: {:?}", vm.mapped_volumes); println!(" Mapped ports: {:?}", vm.mapped_ports); } pub fn list(cfg: &KrunvmConfig, _matches: &ArgMatches) { if cfg.vmconfig_map.is_empty() { println!("No microVMs found"); } else { for (_name, vm) in cfg.vmconfig_map.iter() { println!(); printvm(vm); } println!(); } } 0707010000001C000081A4000000000000000000000001636923F10000300E000000000000000000000000000000000000002400000000krunvm-0.2.3+git12dac81/src/main.rs// Copyright 2021 Red Hat, Inc. // SPDX-License-Identifier: Apache-2.0 use std::collections::HashMap; #[cfg(target_os = "macos")] use std::fs::File; #[cfg(target_os = "macos")] use std::io::{self, Read, Write}; use clap::{crate_version, App, Arg, ArgMatches}; use serde_derive::{Deserialize, Serialize}; #[cfg(target_os = "macos")] use text_io::read; #[allow(unused)] mod bindings; mod changevm; mod config; mod create; mod delete; mod list; mod start; mod utils; const APP_NAME: &str = "krunvm"; #[derive(Default, Debug, Serialize, Deserialize)] pub struct VmConfig { name: String, cpus: u32, mem: u32, container: String, workdir: String, dns: String, mapped_volumes: HashMap<String, String>, mapped_ports: HashMap<String, String>, } #[derive(Debug, Serialize, Deserialize)] pub struct KrunvmConfig { version: u8, default_cpus: u32, default_mem: u32, default_dns: String, storage_volume: String, vmconfig_map: HashMap<String, VmConfig>, } impl Default for KrunvmConfig { fn default() -> KrunvmConfig { KrunvmConfig { version: 1, default_cpus: 2, default_mem: 1024, default_dns: "1.1.1.1".to_string(), storage_volume: String::new(), vmconfig_map: HashMap::new(), } } } #[cfg(target_os = "macos")] fn check_case_sensitivity(volume: &str) -> Result<bool, io::Error> { let first_path = format!("{}/krunvm_test", volume); let second_path = format!("{}/krunVM_test", volume); { let mut first = File::create(&first_path)?; first.write_all(b"first")?; } { let mut second = File::create(&second_path)?; second.write_all(b"second")?; } let mut data = String::new(); { let mut test = File::open(&first_path)?; test.read_to_string(&mut data)?; } if data == "first" { let _ = std::fs::remove_file(first_path); let _ = std::fs::remove_file(second_path); Ok(true) } else { let _ = std::fs::remove_file(first_path); Ok(false) } } #[cfg(target_os = "macos")] fn check_volume(cfg: &mut KrunvmConfig) { if !cfg.storage_volume.is_empty() { return; } println!( " On macOS, krunvm requires a dedicated, case-sensitive volume. You can easily create such volume by executing something like this on another terminal: diskutil apfs addVolume disk3 \"Case-sensitive APFS\" krunvm NOTE: APFS volume creation is a non-destructive action that doesn't require a dedicated disk nor \"sudo\" privileges. The new volume will share the disk space with the main container volume. " ); loop { print!("Please enter the mountpoint for this volume [/Volumes/krunvm]: "); io::stdout().flush().unwrap(); let answer: String = read!("{}\n"); let volume = if answer.is_empty() { "/Volumes/krunvm".to_string() } else { answer.to_string() }; print!("Checking volume... "); match check_case_sensitivity(&volume) { Ok(res) => { if res { println!("success."); println!("The volume has been configured. Please execute krunvm again"); cfg.storage_volume = volume; confy::store(APP_NAME, cfg).unwrap(); std::process::exit(-1); } else { println!("failed."); println!("This volume failed the case sensitivity test."); } } Err(err) => { println!("error."); println!("There was an error running the test: {}", err); } } } } #[cfg(target_os = "linux")] fn check_unshare() { let uid = unsafe { libc::getuid() }; if uid != 0 && !std::env::vars().any(|(key, _)| key == "BUILDAH_ISOLATION") { println!("Please re-run krunvm inside a \"buildah unshare\" session"); std::process::exit(-1); } } fn main() { let mut cfg: KrunvmConfig = confy::load(APP_NAME).unwrap(); let mut app = App::new("krunvm") .version(crate_version!()) .author("Sergio Lopez <slp@redhat.com>") .about("Manage microVMs created from OCI images") .arg( Arg::with_name("v") .short("v") .multiple(true) .help("Sets the level of verbosity"), ) .subcommand( App::new("changevm") .about("Change the configuration of a microVM") .arg( Arg::with_name("cpus") .long("cpus") .help("Number of vCPUs") .takes_value(true), ) .arg( Arg::with_name("mem") .long("mem") .help("Amount of RAM in MiB") .takes_value(true), ) .arg( Arg::with_name("workdir") .long("workdir") .short("w") .help("Working directory inside the microVM") .takes_value(true), ) .arg( Arg::with_name("remove-volumes") .long("remove-volumes") .help("Remove all volume mappings"), ) .arg( Arg::with_name("volume") .long("volume") .short("v") .help("Volume in form \"host_path:guest_path\" to be exposed to the guest") .takes_value(true) .multiple(true) .number_of_values(1), ) .arg( Arg::with_name("remove-ports") .long("remove-ports") .help("Remove all port mappings"), ) .arg( Arg::with_name("port") .long("port") .short("p") .help("Port in format \"host_port:guest_port\" to be exposed to the host") .takes_value(true) .multiple(true) .number_of_values(1), ) .arg( Arg::with_name("new-name") .long("name") .help("Assign a new name to the VM") .takes_value(true), ) .arg( Arg::with_name("NAME") .help("Name of the VM to be modified") .required(true), ), ) .subcommand( App::new("config") .about("Configure global values") .arg( Arg::with_name("cpus") .long("cpus") .help("Default number of vCPUs for newly created VMs") .takes_value(true), ) .arg( Arg::with_name("mem") .long("mem") .help("Default amount of RAM in MiB for newly created VMs") .takes_value(true), ) .arg( Arg::with_name("dns") .long("dns") .help("DNS server to use in the microVM") .takes_value(true), ), ) .subcommand( App::new("delete").about("Delete an existing microVM").arg( Arg::with_name("NAME") .help("Name of the microVM to be deleted") .required(true) .index(1), ), ) .subcommand( App::new("list").about("List microVMs").arg( Arg::with_name("debug") .short("d") .help("print debug information verbosely"), ), ) .subcommand( App::new("start") .about("Start an existing microVM") .arg(Arg::with_name("cpus").long("cpus").help("Number of vCPUs")) .arg( Arg::with_name("mem") .long("mem") .help("Amount of RAM in MiB"), ) .arg( Arg::with_name("NAME") .help("Name of the microVM") .required(true) .index(1), ) .arg( Arg::with_name("COMMAND") .help("Command to run inside the VM") .index(2), ) .arg( Arg::with_name("ARGS") .help("Arguments to be passed to the command executed in the VM") .multiple(true) .last(true), ), ); let mut create = App::new("create") .about("Create a new microVM") .arg( Arg::with_name("cpus") .long("cpus") .help("Number of vCPUs") .takes_value(true), ) .arg( Arg::with_name("mem") .long("mem") .help("Amount of RAM in MiB") .takes_value(true), ) .arg( Arg::with_name("dns") .long("dns") .help("DNS server to use in the microVM") .takes_value(true), ) .arg( Arg::with_name("workdir") .long("workdir") .short("w") .help("Working directory inside the microVM") .takes_value(true) .default_value(""), ) .arg( Arg::with_name("volume") .long("volume") .short("v") .help("Volume in form \"host_path:guest_path\" to be exposed to the guest") .takes_value(true) .multiple(true) .number_of_values(1), ) .arg( Arg::with_name("port") .long("port") .short("p") .help("Port in format \"host_port:guest_port\" to be exposed to the host") .takes_value(true) .multiple(true) .number_of_values(1), ) .arg( Arg::with_name("name") .long("name") .help("Assign a name to the VM") .takes_value(true), ) .arg( Arg::with_name("IMAGE") .help("OCI image to use as template") .required(true), ); if cfg!(target_os = "macos") { create = create.arg( Arg::with_name("x86") .long("x86") .short("x") .help("Create a x86_64 microVM even on an Aarch64 host"), ); } app = app.subcommand(create); let matches = app.clone().get_matches(); #[cfg(target_os = "macos")] check_volume(&mut cfg); #[cfg(target_os = "linux")] check_unshare(); if let Some(matches) = matches.subcommand_matches("changevm") { changevm::changevm(&mut cfg, matches); } else if let Some(matches) = matches.subcommand_matches("config") { config::config(&mut cfg, matches); } else if let Some(matches) = matches.subcommand_matches("create") { create::create(&mut cfg, matches); } else if let Some(matches) = matches.subcommand_matches("delete") { delete::delete(&mut cfg, matches); } else if let Some(matches) = matches.subcommand_matches("list") { list::list(&cfg, matches); } else if let Some(matches) = matches.subcommand_matches("start") { start::start(&cfg, matches); } else { app.print_long_help().unwrap(); println!(); } } 0707010000001D000081A4000000000000000000000001636923F100001AB0000000000000000000000000000000000000002500000000krunvm-0.2.3+git12dac81/src/start.rs// Copyright 2021 Red Hat, Inc. // SPDX-License-Identifier: Apache-2.0 use std::ffi::CString; use std::fs::File; #[cfg(target_os = "linux")] use std::io::{Error, ErrorKind}; use std::os::unix::io::AsRawFd; #[cfg(target_os = "macos")] use std::path::Path; use super::bindings; use super::utils::{mount_container, umount_container}; use crate::{ArgMatches, KrunvmConfig, VmConfig}; #[cfg(target_os = "linux")] fn map_volumes(_ctx: u32, vmcfg: &VmConfig, rootfs: &str) { for (host_path, guest_path) in vmcfg.mapped_volumes.iter() { let host_dir = CString::new(host_path.to_string()).unwrap(); let guest_dir = CString::new(format!("{}{}", rootfs, guest_path)).unwrap(); let ret = unsafe { libc::mkdir(guest_dir.as_ptr(), 0o755) }; if ret < 0 && Error::last_os_error().kind() != ErrorKind::AlreadyExists { println!("Error creating directory {:?}", guest_dir); std::process::exit(-1); } unsafe { libc::umount(guest_dir.as_ptr()) }; let ret = unsafe { libc::mount( host_dir.as_ptr(), guest_dir.as_ptr(), std::ptr::null(), libc::MS_BIND | libc::MS_REC, std::ptr::null(), ) }; if ret < 0 { println!("Error mounting volume {}", guest_path); std::process::exit(-1); } } } #[cfg(target_os = "macos")] fn map_volumes(ctx: u32, vmcfg: &VmConfig, rootfs: &str) { let mut volumes = Vec::new(); for (host_path, guest_path) in vmcfg.mapped_volumes.iter() { let full_guest = format!("{}{}", &rootfs, guest_path); let full_guest_path = Path::new(&full_guest); if !full_guest_path.exists() { std::fs::create_dir(full_guest_path) .expect("Couldn't create guest_path for mapped volume"); } let map = format!("{}:{}", host_path, guest_path); volumes.push(CString::new(map).unwrap()); } let mut vols: Vec<*const i8> = Vec::new(); for vol in volumes.iter() { vols.push(vol.as_ptr()); } vols.push(std::ptr::null()); let ret = unsafe { bindings::krun_set_mapped_volumes(ctx, vols.as_ptr()) }; if ret < 0 { println!("Error setting VM mapped volumes"); std::process::exit(-1); } } unsafe fn exec_vm(vmcfg: &VmConfig, rootfs: &str, cmd: Option<&str>, args: Vec<CString>) { //bindings::krun_set_log_level(9); let ctx = bindings::krun_create_ctx() as u32; let ret = bindings::krun_set_vm_config(ctx, vmcfg.cpus as u8, vmcfg.mem); if ret < 0 { println!("Error setting VM config"); std::process::exit(-1); } let c_rootfs = CString::new(rootfs).unwrap(); let ret = bindings::krun_set_root(ctx, c_rootfs.as_ptr() as *const i8); if ret < 0 { println!("Error setting VM rootfs"); std::process::exit(-1); } map_volumes(ctx, vmcfg, rootfs); let mut ports = Vec::new(); for (host_port, guest_port) in vmcfg.mapped_ports.iter() { let map = format!("{}:{}", host_port, guest_port); ports.push(CString::new(map).unwrap()); } let mut ps: Vec<*const i8> = Vec::new(); for port in ports.iter() { ps.push(port.as_ptr() as *const i8); } ps.push(std::ptr::null()); let ret = bindings::krun_set_port_map(ctx, ps.as_ptr()); if ret < 0 { println!("Error setting VM port map"); std::process::exit(-1); } if !vmcfg.workdir.is_empty() { let c_workdir = CString::new(vmcfg.workdir.clone()).unwrap(); let ret = bindings::krun_set_workdir(ctx, c_workdir.as_ptr() as *const i8); if ret < 0 { println!("Error setting VM workdir"); std::process::exit(-1); } } let hostname = CString::new(format!("HOSTNAME={}", vmcfg.name)).unwrap(); let home = CString::new("HOME=/root").unwrap(); let env: [*const i8; 3] = [ hostname.as_ptr() as *const i8, home.as_ptr() as *const i8, std::ptr::null(), ]; if let Some(cmd) = cmd { let mut argv: Vec<*const i8> = Vec::new(); for a in args.iter() { argv.push(a.as_ptr() as *const i8); } argv.push(std::ptr::null()); let c_cmd = CString::new(cmd).unwrap(); let ret = bindings::krun_set_exec( ctx, c_cmd.as_ptr() as *const i8, argv.as_ptr() as *const *const i8, env.as_ptr() as *const *const i8, ); if ret < 0 { println!("Error setting VM config"); std::process::exit(-1); } } else { let ret = bindings::krun_set_env(ctx, env.as_ptr() as *const *const i8); if ret < 0 { println!("Error setting VM environment variables"); std::process::exit(-1); } } let ret = bindings::krun_start_enter(ctx); if ret < 0 { println!("Error starting VM"); std::process::exit(-1); } } fn set_rlimits() { let mut limit = libc::rlimit { rlim_cur: 0, rlim_max: 0, }; let ret = unsafe { libc::getrlimit(libc::RLIMIT_NOFILE, &mut limit) }; if ret < 0 { panic!("Couldn't get RLIMIT_NOFILE value"); } limit.rlim_cur = limit.rlim_max; let ret = unsafe { libc::setrlimit(libc::RLIMIT_NOFILE, &limit) }; if ret < 0 { panic!("Couldn't set RLIMIT_NOFILE value"); } } fn set_lock(rootfs: &str) -> File { let lock_path = format!("{}/.krunvm.lock", rootfs); let file = File::create(lock_path).expect("Couldn't create lock file"); let ret = unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) }; if ret < 0 { println!("Couldn't acquire lock file. Is another instance of this VM already running?"); std::process::exit(-1); } file } pub fn start(cfg: &KrunvmConfig, matches: &ArgMatches) { let cmd = matches.value_of("COMMAND"); let name = matches.value_of("NAME").unwrap(); let vmcfg = match cfg.vmconfig_map.get(name) { None => { println!("No VM found with name {}", name); std::process::exit(-1); } Some(vmcfg) => vmcfg, }; umount_container(cfg, vmcfg).expect("Error unmounting container"); let rootfs = mount_container(cfg, vmcfg).expect("Error mounting container"); let args: Vec<CString> = if cmd.is_some() { match matches.values_of("ARGS") { Some(a) => a.map(|val| CString::new(val).unwrap()).collect(), None => Vec::new(), } } else { Vec::new() }; set_rlimits(); let _file = set_lock(&rootfs); unsafe { exec_vm(vmcfg, &rootfs, cmd, args) }; umount_container(cfg, vmcfg).expect("Error unmounting container"); } 0707010000001E000081A4000000000000000000000001636923F1000020EF000000000000000000000000000000000000002500000000krunvm-0.2.3+git12dac81/src/utils.rs// Copyright 2021 Red Hat, Inc. // SPDX-License-Identifier: Apache-2.0 use std::collections::HashMap; use std::path::Path; use std::process::Command; use crate::{KrunvmConfig, VmConfig, APP_NAME}; pub enum BuildahCommand { From, Inspect, Mount, Unmount, Remove, } #[cfg(target_os = "linux")] pub fn get_buildah_args(_cfg: &KrunvmConfig, cmd: BuildahCommand) -> Vec<String> { match cmd { BuildahCommand::From => vec!["from".to_string()], BuildahCommand::Inspect => vec!["inspect".to_string()], BuildahCommand::Mount => vec!["mount".to_string()], BuildahCommand::Unmount => vec!["umount".to_string()], BuildahCommand::Remove => vec!["rm".to_string()], } } #[cfg(target_os = "macos")] pub fn get_buildah_args(cfg: &KrunvmConfig, cmd: BuildahCommand) -> Vec<String> { let mut hbpath = std::env::current_exe().unwrap(); hbpath.pop(); hbpath.pop(); let hbpath = hbpath.as_path().display(); let policy_json = format!("{}/etc/containers/policy.json", hbpath); let registries_json = format!("{}/etc/containers/registries.conf", hbpath); let storage_root = format!("{}/root", cfg.storage_volume); let storage_runroot = format!("{}/runroot", cfg.storage_volume); let mut args = vec![ "--root".to_string(), storage_root, "--runroot".to_string(), storage_runroot, ]; match cmd { BuildahCommand::From => { args.push("--signature-policy".to_string()); args.push(policy_json); args.push("--registries-conf".to_string()); args.push(registries_json); args.push("from".to_string()); args.push("--os".to_string()); args.push("linux".to_string()); } BuildahCommand::Inspect => { args.push("inspect".to_string()); } BuildahCommand::Mount => { args.push("mount".to_string()); } BuildahCommand::Unmount => { args.push("umount".to_string()); } BuildahCommand::Remove => { args.push("rm".to_string()); } } args } pub fn parse_mapped_ports(port_matches: Vec<&str>) -> HashMap<String, String> { let mut mapped_ports = HashMap::new(); for port in port_matches.iter() { let vtuple: Vec<&str> = port.split(':').collect(); if vtuple.len() != 2 { println!("Invalid value for \"port\""); std::process::exit(-1); } let host_port: u16 = match vtuple[0].parse() { Ok(p) => p, Err(_) => { println!("Invalid host port"); std::process::exit(-1); } }; let guest_port: u16 = match vtuple[1].parse() { Ok(p) => p, Err(_) => { println!("Invalid guest port"); std::process::exit(-1); } }; mapped_ports.insert(host_port.to_string(), guest_port.to_string()); } mapped_ports } pub fn parse_mapped_volumes(volume_matches: Vec<&str>) -> HashMap<String, String> { let mut mapped_volumes = HashMap::new(); for volume in volume_matches.iter() { let vtuple: Vec<&str> = volume.split(':').collect(); if vtuple.len() != 2 { println!("Invalid value for \"volume\""); std::process::exit(-1); } let host_path = Path::new(vtuple[0]); if !host_path.is_absolute() { println!("Invalid volume, host_path is not an absolute path"); std::process::exit(-1); } if !host_path.exists() { println!("Invalid volume, host_path does not exists"); std::process::exit(-1); } let guest_path = Path::new(vtuple[1]); if !guest_path.is_absolute() { println!("Invalid volume, guest_path is not an absolute path"); std::process::exit(-1); } if guest_path.components().count() != 2 { println!( "Invalid volume, only single direct root children are supported as guest_path" ); std::process::exit(-1); } mapped_volumes.insert( host_path.to_str().unwrap().to_string(), guest_path.to_str().unwrap().to_string(), ); } mapped_volumes } #[cfg(target_os = "macos")] fn fix_root_mode(rootfs: &str) { let mut args = vec!["-w", "user.containers.override_stat", "0:0:0555"]; args.push(rootfs); let output = match Command::new("xattr") .args(&args) .stderr(std::process::Stdio::inherit()) .output() { Ok(output) => output, Err(err) => { if err.kind() == std::io::ErrorKind::NotFound { println!("{} requires xattr to manage the OCI images, and it wasn't found on this system.", APP_NAME); } else { println!("Error executing xattr: {}", err); } std::process::exit(-1); } }; let exit_code = output.status.code().unwrap_or(-1); if exit_code != 0 { println!("xattr returned an error: {}", exit_code); std::process::exit(-1); } } #[allow(unused_variables)] pub fn mount_container(cfg: &KrunvmConfig, vmcfg: &VmConfig) -> Result<String, std::io::Error> { let mut args = get_buildah_args(cfg, BuildahCommand::Mount); args.push(vmcfg.container.clone()); let output = match Command::new("buildah") .args(&args) .stderr(std::process::Stdio::inherit()) .output() { Ok(output) => output, Err(err) => { if err.kind() == std::io::ErrorKind::NotFound { println!("{} requires buildah to manage the OCI images, and it wasn't found on this system.", APP_NAME); } else { println!("Error executing buildah: {}", err); } std::process::exit(-1); } }; let exit_code = output.status.code().unwrap_or(-1); if exit_code != 0 { println!( "buildah returned an error: {}", std::str::from_utf8(&output.stdout).unwrap() ); std::process::exit(-1); } let rootfs = std::str::from_utf8(&output.stdout).unwrap().trim(); #[cfg(target_os = "macos")] fix_root_mode(&rootfs); Ok(rootfs.to_string()) } #[allow(unused_variables)] pub fn umount_container(cfg: &KrunvmConfig, vmcfg: &VmConfig) -> Result<(), std::io::Error> { let mut args = get_buildah_args(cfg, BuildahCommand::Unmount); args.push(vmcfg.container.clone()); let output = match Command::new("buildah") .args(&args) .stderr(std::process::Stdio::inherit()) .output() { Ok(output) => output, Err(err) => { if err.kind() == std::io::ErrorKind::NotFound { println!("{} requires buildah to manage the OCI images, and it wasn't found on this system.", APP_NAME); } else { println!("Error executing buildah: {}", err); } std::process::exit(-1); } }; let exit_code = output.status.code().unwrap_or(-1); if exit_code != 0 { println!( "buildah returned an error: {}", std::str::from_utf8(&output.stdout).unwrap() ); std::process::exit(-1); } Ok(()) } #[allow(unused_variables)] pub fn remove_container(cfg: &KrunvmConfig, vmcfg: &VmConfig) -> Result<(), std::io::Error> { let mut args = get_buildah_args(cfg, BuildahCommand::Remove); args.push(vmcfg.container.clone()); let output = match Command::new("buildah") .args(&args) .stderr(std::process::Stdio::inherit()) .output() { Ok(output) => output, Err(err) => { if err.kind() == std::io::ErrorKind::NotFound { println!("{} requires buildah to manage the OCI images, and it wasn't found on this system.", APP_NAME); } else { println!("Error executing buildah: {}", err); } std::process::exit(-1); } }; let exit_code = output.status.code().unwrap_or(-1); if exit_code != 0 { println!( "buildah returned an error: {}", std::str::from_utf8(&output.stdout).unwrap() ); std::process::exit(-1); } Ok(()) } 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!155 blocks
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor