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
[](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