mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-04-28 19:54:35 +00:00
runtime-rs: shim implements for runtime-rs
Responsible for processing shim related commands: start, delete. This patch is extracted from Alibaba Cloud's internal repository *runD* Thanks to all contributors! Fixes: #3785 Signed-off-by: acetang <aceapril@126.com> Signed-off-by: Bin Liu <bin@hyper.sh> Signed-off-by: Chao Wu <chaowu@linux.alibaba.com> Signed-off-by: Eryu Guan <eguan@linux.alibaba.com> Signed-off-by: Fupan Li <lifupan@gmail.com> Signed-off-by: gexuyang <gexuyang@linux.alibaba.com> Signed-off-by: Helin Guo <helinguo@linux.alibaba.com> Signed-off-by: He Rongguang <herongguang@linux.alibaba.com> Signed-off-by: Hui Zhu <teawater@gmail.com> Signed-off-by: Issac Hai <hjwissac@linux.alibaba.com> Signed-off-by: Jiahuan Chao <jhchao@linux.alibaba.com> Signed-off-by: lichenglong9 <lichenglong9@163.com> Signed-off-by: mengze <mengze@linux.alibaba.com> Signed-off-by: Qingyuan Hou <qingyuan.hou@linux.alibaba.com> Signed-off-by: Quanwei Zhou <quanweiZhou@linux.alibaba.com> Signed-off-by: shiqiangzhang <shiyu.zsq@linux.alibaba.com> Signed-off-by: Simon Guo <wei.guo.simon@linux.alibaba.com> Signed-off-by: Tim Zhang <tim@hyper.sh> Signed-off-by: wanglei01 <wllenyj@linux.alibaba.com> Signed-off-by: Wei Yang <wei.yang1@linux.alibaba.com> Signed-off-by: yanlei <yl.on.the.way@gmail.com> Signed-off-by: Yiqun Leng <yqleng@linux.alibaba.com> Signed-off-by: yuchang.xu <yuchang.xu@linux.alibaba.com> Signed-off-by: Yves Chan <lingfu@linux.alibaba.com> Signed-off-by: Zack <zmlcc@linux.alibaba.com> Signed-off-by: Zhiheng Tao <zhihengtao@linux.alibaba.com> Signed-off-by: Zhongtao Hu <zhongtaohu.tim@linux.alibaba.com> Signed-off-by: Zizheng Bian <zizheng.bian@linux.alibaba.com>
This commit is contained in:
parent
641b736106
commit
278f843f92
1
Makefile
1
Makefile
@ -9,6 +9,7 @@ COMPONENTS =
|
|||||||
COMPONENTS += libs
|
COMPONENTS += libs
|
||||||
COMPONENTS += agent
|
COMPONENTS += agent
|
||||||
COMPONENTS += runtime
|
COMPONENTS += runtime
|
||||||
|
COMPONENTS += runtime-rs
|
||||||
|
|
||||||
# List of available tools
|
# List of available tools
|
||||||
TOOLS =
|
TOOLS =
|
||||||
|
2
src/runtime-rs/.gitignore
vendored
Normal file
2
src/runtime-rs/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
target
|
||||||
|
crates/shim/src/config.rs
|
1423
src/runtime-rs/Cargo.lock
generated
Normal file
1423
src/runtime-rs/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
4
src/runtime-rs/Cargo.toml
Normal file
4
src/runtime-rs/Cargo.toml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[workspace]
|
||||||
|
members = [
|
||||||
|
"crates/shim",
|
||||||
|
]
|
171
src/runtime-rs/Makefile
Normal file
171
src/runtime-rs/Makefile
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
# Copyright (c) 2019-2022 Alibaba Cloud
|
||||||
|
# Copyright (c) 2019-2022 Ant Group
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
# To show variables or targets help on `make help`
|
||||||
|
# Use the following format:
|
||||||
|
# '##VAR VARIABLE_NAME: help about variable'
|
||||||
|
# '##TARGET TARGET_NAME: help about target'
|
||||||
|
|
||||||
|
PROJECT_NAME = Kata Containers
|
||||||
|
PROJECT_URL = https://github.com/kata-containers
|
||||||
|
PROJECT_COMPONENT = containerd-shim-kata-v2
|
||||||
|
CONTAINERD_RUNTIME_NAME = io.containerd.kata.v2
|
||||||
|
|
||||||
|
TARGET = $(PROJECT_COMPONENT)
|
||||||
|
|
||||||
|
SOURCES := \
|
||||||
|
$(shell find . 2>&1 | grep -E '.*\.rs$$') \
|
||||||
|
Cargo.toml
|
||||||
|
|
||||||
|
VERSION_FILE := ./VERSION
|
||||||
|
VERSION := $(shell grep -v ^\# $(VERSION_FILE))
|
||||||
|
COMMIT_NO := $(shell git rev-parse HEAD 2>/dev/null || true)
|
||||||
|
COMMIT := $(if $(shell git status --porcelain --untracked-files=no 2>/dev/null || true),${COMMIT_NO}-dirty,${COMMIT_NO})
|
||||||
|
COMMIT_MSG = $(if $(COMMIT),$(COMMIT),unknown)
|
||||||
|
|
||||||
|
# Exported to allow cargo to see it
|
||||||
|
export VERSION_COMMIT := $(if $(COMMIT),$(VERSION)-$(COMMIT),$(VERSION))
|
||||||
|
|
||||||
|
EXTRA_RUSTFEATURES :=
|
||||||
|
|
||||||
|
ifneq ($(EXTRA_RUSTFEATURES),)
|
||||||
|
override EXTRA_RUSTFEATURES := --features $(EXTRA_RUSTFEATURES)
|
||||||
|
endif
|
||||||
|
|
||||||
|
include ../../utils.mk
|
||||||
|
|
||||||
|
TARGET_PATH = target/$(TRIPLE)/$(BUILD_TYPE)/$(TARGET)
|
||||||
|
|
||||||
|
##VAR DESTDIR=<path> is a directory prepended to each installed target file
|
||||||
|
DESTDIR :=
|
||||||
|
##VAR BINDIR=<path> is a directory for installing executable programs
|
||||||
|
BINDIR := /usr/bin
|
||||||
|
|
||||||
|
GENERATED_CODE = crates/shim/src/config.rs
|
||||||
|
|
||||||
|
RUNTIME_NAME=$(TARGET)
|
||||||
|
RUNTIME_VERSION=$(VERSION)
|
||||||
|
|
||||||
|
GENERATED_REPLACEMENTS= \
|
||||||
|
PROJECT_NAME \
|
||||||
|
RUNTIME_NAME \
|
||||||
|
CONTAINERD_RUNTIME_NAME \
|
||||||
|
RUNTIME_VERSION \
|
||||||
|
BINDIR \
|
||||||
|
COMMIT \
|
||||||
|
VERSION_COMMIT
|
||||||
|
GENERATED_FILES :=
|
||||||
|
|
||||||
|
GENERATED_FILES += $(GENERATED_CODE)
|
||||||
|
|
||||||
|
# Display name of command and it's version (or a message if not available).
|
||||||
|
#
|
||||||
|
# Arguments:
|
||||||
|
#
|
||||||
|
# 1: Name of command
|
||||||
|
define get_command_version
|
||||||
|
$(shell printf "%s: %s\\n" $(1) "$(or $(shell $(1) --version 2>/dev/null), (not available))")
|
||||||
|
endef
|
||||||
|
|
||||||
|
define get_toolchain_version
|
||||||
|
$(shell printf "%s: %s\\n" "toolchain" "$(or $(shell rustup show active-toolchain 2>/dev/null), (unknown))")
|
||||||
|
endef
|
||||||
|
|
||||||
|
define INSTALL_FILE
|
||||||
|
install -D -m 644 $1 $(DESTDIR)$2/$1 || exit 1;
|
||||||
|
endef
|
||||||
|
|
||||||
|
.DEFAULT_GOAL := default
|
||||||
|
|
||||||
|
##TARGET default: build code
|
||||||
|
default: $(TARGET) show-header
|
||||||
|
|
||||||
|
$(TARGET): $(GENERATED_CODE) $(TARGET_PATH)
|
||||||
|
|
||||||
|
$(TARGET_PATH): $(SOURCES) | show-summary
|
||||||
|
@RUSTFLAGS="$(EXTRA_RUSTFLAGS) --deny warnings" cargo build --target $(TRIPLE) --$(BUILD_TYPE) $(EXTRA_RUSTFEATURES)
|
||||||
|
|
||||||
|
$(GENERATED_FILES): %: %.in
|
||||||
|
@sed $(foreach r,$(GENERATED_REPLACEMENTS),-e 's|@$r@|$($r)|g') "$<" > "$@"
|
||||||
|
|
||||||
|
##TARGET optimize: optimized build
|
||||||
|
optimize: $(SOURCES) | show-summary show-header
|
||||||
|
@RUSTFLAGS="-C link-arg=-s $(EXTRA_RUSTFLAGS) --deny warnings" cargo build --target $(TRIPLE) --$(BUILD_TYPE) $(EXTRA_RUSTFEATURES)
|
||||||
|
|
||||||
|
##TARGET clean: clean build
|
||||||
|
clean:
|
||||||
|
@cargo clean
|
||||||
|
@rm -f $(GENERATED_FILES)
|
||||||
|
@rm -f tarpaulin-report.html
|
||||||
|
|
||||||
|
vendor:
|
||||||
|
@cargo vendor
|
||||||
|
|
||||||
|
#TARGET test: run cargo tests
|
||||||
|
test:
|
||||||
|
@cargo test --all --target $(TRIPLE) $(EXTRA_RUSTFEATURES) -- --nocapture
|
||||||
|
|
||||||
|
##TARGET check: run test
|
||||||
|
check: $(GENERATED_FILES) standard_rust_check
|
||||||
|
|
||||||
|
##TARGET run: build and run agent
|
||||||
|
run:
|
||||||
|
@cargo run --target $(TRIPLE)
|
||||||
|
|
||||||
|
show-header:
|
||||||
|
@printf "%s - version %s (commit %s)\n\n" "$(TARGET)" "$(VERSION)" "$(COMMIT_MSG)"
|
||||||
|
|
||||||
|
show-summary: show-header
|
||||||
|
@printf "project:\n"
|
||||||
|
@printf " name: $(PROJECT_NAME)\n"
|
||||||
|
@printf " url: $(PROJECT_URL)\n"
|
||||||
|
@printf " component: $(PROJECT_COMPONENT)\n"
|
||||||
|
@printf "target: $(TARGET)\n"
|
||||||
|
@printf "architecture:\n"
|
||||||
|
@printf " host: $(ARCH)\n"
|
||||||
|
@printf "rust:\n"
|
||||||
|
@printf " %s\n" "$(call get_command_version,cargo)"
|
||||||
|
@printf " %s\n" "$(call get_command_version,rustc)"
|
||||||
|
@printf " %s\n" "$(call get_command_version,rustup)"
|
||||||
|
@printf " %s\n" "$(call get_toolchain_version)"
|
||||||
|
@printf "\n"
|
||||||
|
|
||||||
|
## help: Show help comments that start with `##VAR` and `##TARGET`
|
||||||
|
help: Makefile show-summary
|
||||||
|
@echo "========================== Help ============================="
|
||||||
|
@echo "Variables:"
|
||||||
|
@sed -n 's/^##VAR//p' $< | sort
|
||||||
|
@echo ""
|
||||||
|
@echo "Targets:"
|
||||||
|
@sed -n 's/^##TARGET//p' $< | sort
|
||||||
|
|
||||||
|
TARPAULIN_ARGS:=-v --workspace
|
||||||
|
install-tarpaulin:
|
||||||
|
cargo install cargo-tarpaulin
|
||||||
|
|
||||||
|
# Check if cargo tarpaulin is installed
|
||||||
|
HAS_TARPAULIN:= $(shell cargo --list | grep tarpaulin 2>/dev/null)
|
||||||
|
check_tarpaulin:
|
||||||
|
ifndef HAS_TARPAULIN
|
||||||
|
$(error "tarpaulin is not available please: run make install-tarpaulin ")
|
||||||
|
else
|
||||||
|
$(info OK: tarpaulin installed)
|
||||||
|
endif
|
||||||
|
|
||||||
|
##TARGET codecov: Generate code coverage report
|
||||||
|
codecov: check_tarpaulin
|
||||||
|
cargo tarpaulin $(TARPAULIN_ARGS)
|
||||||
|
|
||||||
|
##TARGET codecov-html: Generate code coverage html report
|
||||||
|
codecov-html: check_tarpaulin
|
||||||
|
cargo tarpaulin $(TARPAULIN_ARGS) -o Html
|
||||||
|
|
||||||
|
.PHONY: \
|
||||||
|
help \
|
||||||
|
optimize \
|
||||||
|
show-header \
|
||||||
|
show-summary \
|
||||||
|
vendor
|
1
src/runtime-rs/VERSION
Symbolic link
1
src/runtime-rs/VERSION
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../VERSION
|
46
src/runtime-rs/crates/shim/Cargo.toml
Normal file
46
src/runtime-rs/crates/shim/Cargo.toml
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
[package]
|
||||||
|
name = "shim"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["The Kata Containers community <kata-dev@lists.katacontainers.io>"]
|
||||||
|
description = "Containerd shim runtime for Kata Containers"
|
||||||
|
keywords = ["kata-containers", "shim"]
|
||||||
|
repository = "https://github.com/kata-containers/kata-containers.git"
|
||||||
|
license = "Apache-2.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "containerd-shim-kata-v2"
|
||||||
|
path = "src/bin/main.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "^1.0"
|
||||||
|
backtrace = {version = ">=0.3.35", features = ["libunwind", "libbacktrace", "std"], default-features = false}
|
||||||
|
# TODO: change to version after release
|
||||||
|
# issue: https://github.com/kata-containers/kata-containers/issues/3866
|
||||||
|
containerd-shim-protos = { git="https://github.com/containerd/rust-extensions.git", rev = "c0baac598fc3ad62f651e8aae8de15db2ce5695c", features = ["async"]}
|
||||||
|
go-flag = "0.1.0"
|
||||||
|
libc = "0.2.108"
|
||||||
|
log = "0.4.14"
|
||||||
|
nix = "0.16.0"
|
||||||
|
protobuf = "2.23.0"
|
||||||
|
sha2 = "=0.9.3"
|
||||||
|
slog = {version = "2.7.0", features = ["std", "release_max_level_trace", "max_level_trace"]}
|
||||||
|
slog-async = "2.7.0"
|
||||||
|
slog-scope = "4.4.0"
|
||||||
|
slog-stdlog = "4.1.0"
|
||||||
|
thiserror = "1.0.30"
|
||||||
|
tokio = { version = "1.8.0", features = [ "rt", "rt-multi-thread" ] }
|
||||||
|
unix_socket2 = "0.5.4"
|
||||||
|
|
||||||
|
kata-types = { path = "../../../libs/kata-types"}
|
||||||
|
kata-sys-util = { path = "../../../libs/kata-sys-util"}
|
||||||
|
logging = { path = "../../../libs/logging"}
|
||||||
|
oci = { path = "../../../libs/oci" }
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
vergen = { version = "6", default-features = false, features = ["build", "git", "rustc"] }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tempfile = "3.2.0"
|
||||||
|
serial_test = "0.5.1"
|
||||||
|
tests_utils = { path = "../../tests/utils"}
|
12
src/runtime-rs/crates/shim/build.rs
Normal file
12
src/runtime-rs/crates/shim/build.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// Copyright (c) 2019-2022 Alibaba Cloud
|
||||||
|
// Copyright (c) 2019-2022 Ant Group
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
use vergen::{vergen, Config};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Generate the default 'cargo:' instruction output
|
||||||
|
vergen(Config::default()).unwrap();
|
||||||
|
}
|
325
src/runtime-rs/crates/shim/src/args.rs
Normal file
325
src/runtime-rs/crates/shim/src/args.rs
Normal file
@ -0,0 +1,325 @@
|
|||||||
|
// Copyright (c) 2019-2022 Alibaba Cloud
|
||||||
|
// Copyright (c) 2019-2022 Ant Group
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
use std::{os::unix::fs::FileTypeExt, path::PathBuf};
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Context, Result};
|
||||||
|
use kata_sys_util::validate;
|
||||||
|
|
||||||
|
use crate::Error;
|
||||||
|
|
||||||
|
/// Received command-line arguments or environment arguments
|
||||||
|
/// from a shimv2 container manager such as containerd.
|
||||||
|
///
|
||||||
|
/// For detailed information, please refer to the
|
||||||
|
/// [shim spec](https://github.com/containerd/containerd/blob/main/runtime/v2/README.md).
|
||||||
|
#[derive(Debug, Default, Clone)]
|
||||||
|
pub struct Args {
|
||||||
|
/// the id of the container
|
||||||
|
pub id: String,
|
||||||
|
/// the namespace for the container
|
||||||
|
pub namespace: String,
|
||||||
|
/// the address of the containerd's main socket
|
||||||
|
pub address: String,
|
||||||
|
/// the binary path to publish events back to containerd
|
||||||
|
pub publish_binary: String,
|
||||||
|
/// Abstract socket path to serve.
|
||||||
|
pub socket: String,
|
||||||
|
/// the path to the bundle to delete
|
||||||
|
pub bundle: String,
|
||||||
|
/// Whether or not to enable debug
|
||||||
|
pub debug: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Args {
|
||||||
|
/// Check the shim argument object is vaild or not.
|
||||||
|
///
|
||||||
|
/// The id, namespace, address and publish_binary are mandatory for START, RUN and DELETE.
|
||||||
|
/// And bundle is mandatory for DELETE.
|
||||||
|
pub fn validate(&mut self, should_check_bundle: bool) -> Result<()> {
|
||||||
|
if self.id.is_empty()
|
||||||
|
|| self.namespace.is_empty()
|
||||||
|
|| self.address.is_empty()
|
||||||
|
|| self.publish_binary.is_empty()
|
||||||
|
{
|
||||||
|
return Err(anyhow!(Error::ArgumentIsEmpty(format!(
|
||||||
|
"id: {} namespace: {} address: {} publish_binary: {}",
|
||||||
|
&self.id, &self.namespace, &self.address, &self.publish_binary
|
||||||
|
))));
|
||||||
|
}
|
||||||
|
|
||||||
|
validate::verify_cid(&self.id).context("verify cid")?;
|
||||||
|
validate::verify_cid(&self.namespace).context("verify namespace")?;
|
||||||
|
|
||||||
|
// Ensure `address` is a valid path.
|
||||||
|
let path = PathBuf::from(self.address.clone())
|
||||||
|
.canonicalize()
|
||||||
|
.context(Error::InvalidPath(self.address.clone()))?;
|
||||||
|
let md = path
|
||||||
|
.metadata()
|
||||||
|
.context(Error::FileGetMetadata(format!("{:?}", path)))?;
|
||||||
|
if !md.file_type().is_socket() {
|
||||||
|
return Err(Error::InvalidArgument).context("address is not socket");
|
||||||
|
}
|
||||||
|
self.address = path
|
||||||
|
.to_str()
|
||||||
|
.map(|v| v.to_owned())
|
||||||
|
.ok_or(Error::InvalidArgument)?;
|
||||||
|
|
||||||
|
// Ensure `bundle` is a valid path.
|
||||||
|
if should_check_bundle {
|
||||||
|
if self.bundle.is_empty() {
|
||||||
|
return Err(anyhow!(Error::ArgumentIsEmpty("bundle".to_string())));
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = PathBuf::from(self.bundle.clone())
|
||||||
|
.canonicalize()
|
||||||
|
.map_err(|_| Error::InvalidArgument)?;
|
||||||
|
let md = path
|
||||||
|
.metadata()
|
||||||
|
.map_err(|_| Error::InvalidArgument)
|
||||||
|
.context("get address metadata")?;
|
||||||
|
if !md.is_dir() {
|
||||||
|
return Err(Error::InvalidArgument).context("medata is dir");
|
||||||
|
}
|
||||||
|
self.bundle = path
|
||||||
|
.to_str()
|
||||||
|
.map(|v| v.to_owned())
|
||||||
|
.ok_or(Error::InvalidArgument)
|
||||||
|
.context("path to string")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::os::unix::net::UnixListener;
|
||||||
|
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use kata_sys_util::validate;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_args_is_valid() {
|
||||||
|
let dir = tempfile::tempdir().unwrap();
|
||||||
|
let path = dir.path().to_path_buf();
|
||||||
|
let path = path.to_str().unwrap();
|
||||||
|
let bind_address = &format!("{}/socket1", path);
|
||||||
|
UnixListener::bind(bind_address).unwrap();
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct TestData {
|
||||||
|
arg: Args,
|
||||||
|
should_check_bundle: bool,
|
||||||
|
result: Result<()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let default_id = "1dfc0567".to_string();
|
||||||
|
let default_namespace = "ns1".to_string();
|
||||||
|
let default_address = bind_address.to_string();
|
||||||
|
let default_publish_binary = "containerd".to_string();
|
||||||
|
let default_socket = "socket".to_string();
|
||||||
|
let default_bundle = path.to_string();
|
||||||
|
let default_debug = false;
|
||||||
|
|
||||||
|
let mut arg = Args {
|
||||||
|
id: default_id.clone(),
|
||||||
|
namespace: default_namespace.clone(),
|
||||||
|
address: default_address.clone(),
|
||||||
|
publish_binary: default_publish_binary.clone(),
|
||||||
|
socket: default_socket,
|
||||||
|
bundle: default_bundle.clone(),
|
||||||
|
debug: default_debug,
|
||||||
|
};
|
||||||
|
|
||||||
|
let tests = &[
|
||||||
|
TestData {
|
||||||
|
arg: arg.clone(),
|
||||||
|
should_check_bundle: false,
|
||||||
|
result: Ok(()),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
arg: {
|
||||||
|
arg.namespace = "".to_string();
|
||||||
|
arg.clone()
|
||||||
|
},
|
||||||
|
should_check_bundle: false,
|
||||||
|
result: Err(anyhow!(Error::ArgumentIsEmpty(format!(
|
||||||
|
"id: {} namespace: {} address: {} publish_binary: {}",
|
||||||
|
&arg.id, &arg.namespace, &arg.address, &arg.publish_binary
|
||||||
|
)))),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
arg: {
|
||||||
|
arg.namespace = default_namespace.clone();
|
||||||
|
arg.clone()
|
||||||
|
},
|
||||||
|
should_check_bundle: false,
|
||||||
|
result: Ok(()),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
arg: {
|
||||||
|
arg.id = "".to_string();
|
||||||
|
arg.clone()
|
||||||
|
},
|
||||||
|
should_check_bundle: false,
|
||||||
|
result: Err(anyhow!(Error::ArgumentIsEmpty(format!(
|
||||||
|
"id: {} namespace: {} address: {} publish_binary: {}",
|
||||||
|
&arg.id, &arg.namespace, &arg.address, &arg.publish_binary
|
||||||
|
)))),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
arg: {
|
||||||
|
arg.id = default_id;
|
||||||
|
arg.clone()
|
||||||
|
},
|
||||||
|
should_check_bundle: false,
|
||||||
|
result: Ok(()),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
arg: {
|
||||||
|
arg.address = "".to_string();
|
||||||
|
arg.clone()
|
||||||
|
},
|
||||||
|
should_check_bundle: false,
|
||||||
|
result: Err(anyhow!(Error::ArgumentIsEmpty(format!(
|
||||||
|
"id: {} namespace: {} address: {} publish_binary: {}",
|
||||||
|
&arg.id, &arg.namespace, &arg.address, &arg.publish_binary
|
||||||
|
)))),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
arg: {
|
||||||
|
arg.address = default_address.clone();
|
||||||
|
arg.clone()
|
||||||
|
},
|
||||||
|
should_check_bundle: false,
|
||||||
|
result: Ok(()),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
arg: {
|
||||||
|
arg.publish_binary = "".to_string();
|
||||||
|
arg.clone()
|
||||||
|
},
|
||||||
|
should_check_bundle: false,
|
||||||
|
result: Err(anyhow!(Error::ArgumentIsEmpty(format!(
|
||||||
|
"id: {} namespace: {} address: {} publish_binary: {}",
|
||||||
|
&arg.id, &arg.namespace, &arg.address, &arg.publish_binary
|
||||||
|
)))),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
arg: {
|
||||||
|
arg.publish_binary = default_publish_binary;
|
||||||
|
arg.clone()
|
||||||
|
},
|
||||||
|
should_check_bundle: false,
|
||||||
|
result: Ok(()),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
arg: {
|
||||||
|
arg.bundle = "".to_string();
|
||||||
|
arg.clone()
|
||||||
|
},
|
||||||
|
should_check_bundle: false,
|
||||||
|
result: Ok(()),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
arg: arg.clone(),
|
||||||
|
should_check_bundle: true,
|
||||||
|
result: Err(anyhow!(Error::ArgumentIsEmpty("bundle".to_string()))),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
arg: {
|
||||||
|
arg.bundle = default_bundle;
|
||||||
|
arg.clone()
|
||||||
|
},
|
||||||
|
should_check_bundle: true,
|
||||||
|
result: Ok(()),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
arg: {
|
||||||
|
arg.namespace = "id1/id2".to_string();
|
||||||
|
arg.clone()
|
||||||
|
},
|
||||||
|
should_check_bundle: true,
|
||||||
|
result: Err(
|
||||||
|
anyhow!(validate::Error::InvalidContainerID("id/id2".to_string()))
|
||||||
|
.context("verify namespace"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
arg: {
|
||||||
|
arg.namespace = default_namespace.clone() + "id1 id2";
|
||||||
|
arg.clone()
|
||||||
|
},
|
||||||
|
should_check_bundle: true,
|
||||||
|
result: Err(anyhow!(validate::Error::InvalidContainerID(
|
||||||
|
default_namespace.clone() + "id1 id2",
|
||||||
|
))
|
||||||
|
.context("verify namespace")),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
arg: {
|
||||||
|
arg.namespace = default_namespace.clone() + "id2\tid2";
|
||||||
|
arg.clone()
|
||||||
|
},
|
||||||
|
should_check_bundle: true,
|
||||||
|
result: Err(anyhow!(validate::Error::InvalidContainerID(
|
||||||
|
default_namespace.clone() + "id1\tid2",
|
||||||
|
))
|
||||||
|
.context("verify namespace")),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
arg: {
|
||||||
|
arg.namespace = default_namespace;
|
||||||
|
arg.clone()
|
||||||
|
},
|
||||||
|
should_check_bundle: true,
|
||||||
|
result: Ok(()),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
arg: {
|
||||||
|
arg.address = default_address.clone() + "/..";
|
||||||
|
arg.clone()
|
||||||
|
},
|
||||||
|
should_check_bundle: true,
|
||||||
|
result: Err(anyhow!(Error::InvalidPath(arg.address.clone()))),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
arg: {
|
||||||
|
arg.address = default_address.clone() + "/..";
|
||||||
|
arg.clone()
|
||||||
|
},
|
||||||
|
should_check_bundle: true,
|
||||||
|
result: Err(anyhow!(Error::InvalidPath(arg.address.clone()))),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
arg: {
|
||||||
|
arg.address = default_address;
|
||||||
|
arg
|
||||||
|
},
|
||||||
|
should_check_bundle: true,
|
||||||
|
result: Ok(()),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for (i, t) in tests.iter().enumerate() {
|
||||||
|
let msg = format!("test[{}]: {:?}", i, t);
|
||||||
|
let should_check_bundle = t.should_check_bundle;
|
||||||
|
let result = t.arg.clone().validate(should_check_bundle);
|
||||||
|
let msg = format!("{}, result: {:?}", msg, result);
|
||||||
|
|
||||||
|
if t.result.is_ok() {
|
||||||
|
assert!(result.is_ok(), "{}", msg);
|
||||||
|
} else {
|
||||||
|
let expected_error = format!("{}", t.result.as_ref().unwrap_err());
|
||||||
|
let actual_error = format!("{}", result.unwrap_err());
|
||||||
|
assert!(actual_error == expected_error, "{}", msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
192
src/runtime-rs/crates/shim/src/bin/main.rs
Normal file
192
src/runtime-rs/crates/shim/src/bin/main.rs
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
// Copyright (c) 2019-2022 Alibaba Cloud
|
||||||
|
// Copyright (c) 2019-2022 Ant Group
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
ffi::{OsStr, OsString},
|
||||||
|
path::PathBuf,
|
||||||
|
};
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Context, Result};
|
||||||
|
use nix::{
|
||||||
|
mount::{mount, MsFlags},
|
||||||
|
sched::{self, CloneFlags},
|
||||||
|
};
|
||||||
|
use shim::{config, Args, Error, ShimExecutor};
|
||||||
|
|
||||||
|
const DEFAULT_RUNTIME_WORKER_THREADS: usize = 2;
|
||||||
|
const ENV_RUNTIME_WORKER_THREADS: &str = "RUNTIME_WORKER_THREADS";
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Action {
|
||||||
|
Run(Args),
|
||||||
|
Start(Args),
|
||||||
|
Delete(Args),
|
||||||
|
Help,
|
||||||
|
Version,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_args(args: &[OsString]) -> Result<Action> {
|
||||||
|
let mut help = false;
|
||||||
|
let mut version = false;
|
||||||
|
let mut shim_args = Args::default();
|
||||||
|
|
||||||
|
// Crate `go_flag` is used to keep compatible with go/flag package.
|
||||||
|
let rest_args = go_flag::parse_args_with_warnings::<String, _, _>(&args[1..], None, |flags| {
|
||||||
|
flags.add_flag("address", &mut shim_args.address);
|
||||||
|
flags.add_flag("bundle", &mut shim_args.bundle);
|
||||||
|
flags.add_flag("debug", &mut shim_args.debug);
|
||||||
|
flags.add_flag("id", &mut shim_args.id);
|
||||||
|
flags.add_flag("namespace", &mut shim_args.namespace);
|
||||||
|
flags.add_flag("publish-binary", &mut shim_args.publish_binary);
|
||||||
|
flags.add_flag("socket", &mut shim_args.socket);
|
||||||
|
flags.add_flag("help", &mut help);
|
||||||
|
flags.add_flag("version", &mut version);
|
||||||
|
})
|
||||||
|
.context(Error::ParseArgument(format!("{:?}", args)))?;
|
||||||
|
|
||||||
|
if help {
|
||||||
|
Ok(Action::Help)
|
||||||
|
} else if version {
|
||||||
|
Ok(Action::Version)
|
||||||
|
} else if rest_args.is_empty() {
|
||||||
|
Ok(Action::Run(shim_args))
|
||||||
|
} else if rest_args[0] == "start" {
|
||||||
|
Ok(Action::Start(shim_args))
|
||||||
|
} else if rest_args[0] == "delete" {
|
||||||
|
Ok(Action::Delete(shim_args))
|
||||||
|
} else {
|
||||||
|
Err(anyhow!(Error::InvalidArgument))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_help(cmd: &OsStr) {
|
||||||
|
let path = PathBuf::from(cmd);
|
||||||
|
let name = match path.file_name() {
|
||||||
|
Some(v) => v.to_str(),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let name = name.unwrap_or(config::RUNTIME_NAME);
|
||||||
|
|
||||||
|
println!(
|
||||||
|
r#"Usage of {}:
|
||||||
|
-address string
|
||||||
|
grpc address back to main containerd
|
||||||
|
-bundle string
|
||||||
|
path to the bundle if not workdir
|
||||||
|
-debug
|
||||||
|
enable debug output in logs
|
||||||
|
-id string
|
||||||
|
id of the task
|
||||||
|
-namespace string
|
||||||
|
namespace that owns the shim
|
||||||
|
-publish-binary string
|
||||||
|
path to publish binary (used for publishing events) (default "containerd")
|
||||||
|
-socket string
|
||||||
|
socket path to serve
|
||||||
|
--version
|
||||||
|
show the runtime version detail and exit
|
||||||
|
"#,
|
||||||
|
name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_version(err: Option<anyhow::Error>) {
|
||||||
|
let data = format!(
|
||||||
|
r#"{} containerd shim: id: {}, version: {}, commit: {}"#,
|
||||||
|
config::PROJECT_NAME,
|
||||||
|
config::CONTAINERD_RUNTIME_NAME,
|
||||||
|
config::RUNTIME_VERSION,
|
||||||
|
config::RUNTIME_VERSION_COMMIT,
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(err) = err {
|
||||||
|
eprintln!(
|
||||||
|
"{}\r\nERROR: {} failed: {:?}",
|
||||||
|
data,
|
||||||
|
config::RUNTIME_NAME,
|
||||||
|
err
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!("{}", data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_tokio_runtime() -> Result<tokio::runtime::Runtime> {
|
||||||
|
let worker_threads = std::env::var(ENV_RUNTIME_WORKER_THREADS)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.parse()
|
||||||
|
.unwrap_or(DEFAULT_RUNTIME_WORKER_THREADS);
|
||||||
|
|
||||||
|
let rt = tokio::runtime::Builder::new_multi_thread()
|
||||||
|
.worker_threads(worker_threads)
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.context("prepare tokio runtime")?;
|
||||||
|
Ok(rt)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn real_main() -> Result<()> {
|
||||||
|
let args = std::env::args_os().collect::<Vec<_>>();
|
||||||
|
if args.is_empty() {
|
||||||
|
return Err(anyhow!(Error::ArgumentIsEmpty(
|
||||||
|
"command-line arguments".to_string()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let action = parse_args(&args).context("parse args")?;
|
||||||
|
match action {
|
||||||
|
Action::Start(args) => ShimExecutor::new(args).start().context("shim start")?,
|
||||||
|
Action::Delete(args) => ShimExecutor::new(args).delete().context("shim delete")?,
|
||||||
|
Action::Run(args) => {
|
||||||
|
// set mnt namespace
|
||||||
|
// need setup before other async call
|
||||||
|
setup_mnt().context("setup mnt")?;
|
||||||
|
|
||||||
|
let mut shim = ShimExecutor::new(args);
|
||||||
|
let rt = get_tokio_runtime().context("get tokio runtime")?;
|
||||||
|
rt.block_on(shim.run())?
|
||||||
|
}
|
||||||
|
Action::Help => show_help(&args[0]),
|
||||||
|
Action::Version => show_version(None),
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
if let Err(err) = real_main() {
|
||||||
|
show_version(Some(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_mnt() -> Result<()> {
|
||||||
|
// Unshare the mount namespace, so that the calling process has a private copy of its namespace
|
||||||
|
// which is not shared with any other process.
|
||||||
|
sched::unshare(CloneFlags::CLONE_NEWNS).context("unshare clone newns")?;
|
||||||
|
|
||||||
|
// Mount and unmount events propagate into this mount from the (master) shared peer group of
|
||||||
|
// which it was formerly a member. Mount and unmount events under this mount do not propagate
|
||||||
|
// to any peer.
|
||||||
|
mount(
|
||||||
|
Some("none"),
|
||||||
|
"/",
|
||||||
|
Some(""),
|
||||||
|
MsFlags::MS_REC | MsFlags::MS_SLAVE,
|
||||||
|
Some(""),
|
||||||
|
)
|
||||||
|
.context("mount with slave")?;
|
||||||
|
|
||||||
|
// Mount and unmount events immediately under this mount will propagate to the other mounts
|
||||||
|
// that are members of this mount's peer group.
|
||||||
|
mount(
|
||||||
|
Some("none"),
|
||||||
|
"/",
|
||||||
|
Some(""),
|
||||||
|
MsFlags::MS_REC | MsFlags::MS_SHARED,
|
||||||
|
Some(""),
|
||||||
|
)
|
||||||
|
.context("mount with shared")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
19
src/runtime-rs/crates/shim/src/config.rs.in
Normal file
19
src/runtime-rs/crates/shim/src/config.rs.in
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// Copyright (c) 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// WARNING: This file is auto-generated - DO NOT EDIT!
|
||||||
|
//
|
||||||
|
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
pub const PROJECT_NAME: &str = "@PROJECT_NAME@";
|
||||||
|
pub const RUNTIME_VERSION: &str = "@RUNTIME_VERSION@";
|
||||||
|
pub const RUNTIME_VERSION_COMMIT: &str = "@VERSION_COMMIT@";
|
||||||
|
pub const RUNTIME_GIT_COMMIT: &str = "@COMMIT@";
|
||||||
|
pub const RUNTIME_NAME: &str = "@RUNTIME_NAME@";
|
||||||
|
pub const CONTAINERD_RUNTIME_NAME: &str = "@CONTAINERD_RUNTIME_NAME@";
|
||||||
|
pub const RUNTIME_DIR: &str = "@BINDIR@";
|
||||||
|
pub const RUNTIME_PATH: &str = "@BINDIR@/@RUNTIME_NAME@";
|
52
src/runtime-rs/crates/shim/src/error.rs
Normal file
52
src/runtime-rs/crates/shim/src/error.rs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// Copyright (c) 2019-2022 Alibaba Cloud
|
||||||
|
// Copyright (c) 2019-2022 Ant Group
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("failed to parse argument {0}")]
|
||||||
|
ParseArgument(String),
|
||||||
|
#[error("failed to get bundle path")]
|
||||||
|
GetBundlePath,
|
||||||
|
#[error("invalid argument")]
|
||||||
|
InvalidArgument,
|
||||||
|
#[error("argument is empty {0}")]
|
||||||
|
ArgumentIsEmpty(String),
|
||||||
|
#[error("invalid path {0}")]
|
||||||
|
InvalidPath(String),
|
||||||
|
|
||||||
|
// File
|
||||||
|
#[error("failed to open file {0}")]
|
||||||
|
FileOpen(String),
|
||||||
|
#[error("failed to get file metadata {0}")]
|
||||||
|
FileGetMetadata(String),
|
||||||
|
#[error("failed to read file {0}")]
|
||||||
|
FileRead(String),
|
||||||
|
#[error("failed to write file {0}")]
|
||||||
|
FileWrite(String),
|
||||||
|
|
||||||
|
#[error("empty sandbox id")]
|
||||||
|
EmptySandboxId,
|
||||||
|
#[error("failed to get self exec: {0}")]
|
||||||
|
SelfExec(#[source] std::io::Error),
|
||||||
|
#[error("failed to bind socket at {1} with error: {0}")]
|
||||||
|
BindSocket(#[source] std::io::Error, PathBuf),
|
||||||
|
#[error("failed to spawn child: {0}")]
|
||||||
|
SpawnChild(#[source] std::io::Error),
|
||||||
|
#[error("failed to clean container {0}")]
|
||||||
|
CleanUpContainer(String),
|
||||||
|
#[error("failed to get env variable: {0}")]
|
||||||
|
EnvVar(#[source] std::env::VarError),
|
||||||
|
#[error("failed to parse server fd environment variable {0}")]
|
||||||
|
ServerFd(String),
|
||||||
|
#[error("failed to wait ttrpc server when {0}")]
|
||||||
|
WaitServer(String),
|
||||||
|
#[error("failed to get system time: {0}")]
|
||||||
|
SystemTime(#[source] std::time::SystemTimeError),
|
||||||
|
#[error("failed to parse pid")]
|
||||||
|
ParsePid,
|
||||||
|
}
|
28
src/runtime-rs/crates/shim/src/lib.rs
Normal file
28
src/runtime-rs/crates/shim/src/lib.rs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Copyright (c) 2019-2022 Alibaba Cloud
|
||||||
|
// Copyright (c) 2019-2022 Ant Group
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate slog;
|
||||||
|
|
||||||
|
macro_rules! sl {
|
||||||
|
() => {
|
||||||
|
slog_scope::logger().new(slog::o!("subsystem" => "shim"))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
mod args;
|
||||||
|
pub use args::Args;
|
||||||
|
mod error;
|
||||||
|
pub use error::Error;
|
||||||
|
mod logger;
|
||||||
|
mod panic_hook;
|
||||||
|
mod shim;
|
||||||
|
pub use shim::ShimExecutor;
|
||||||
|
#[rustfmt::skip]
|
||||||
|
pub mod config;
|
||||||
|
mod shim_delete;
|
||||||
|
mod shim_run;
|
||||||
|
mod shim_start;
|
41
src/runtime-rs/crates/shim/src/logger.rs
Normal file
41
src/runtime-rs/crates/shim/src/logger.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// Copyright (c) 2019-2022 Alibaba Cloud
|
||||||
|
// Copyright (c) 2019-2022 Ant Group
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
use std::os::unix::fs::OpenOptionsExt;
|
||||||
|
|
||||||
|
use anyhow::{Context, Result};
|
||||||
|
|
||||||
|
use crate::Error;
|
||||||
|
|
||||||
|
pub(crate) fn set_logger(path: &str, sid: &str, is_debug: bool) -> Result<slog_async::AsyncGuard> {
|
||||||
|
let fifo = std::fs::OpenOptions::new()
|
||||||
|
.custom_flags(libc::O_NONBLOCK)
|
||||||
|
.create(true)
|
||||||
|
.write(true)
|
||||||
|
.append(true)
|
||||||
|
.open(path)
|
||||||
|
.context(Error::FileOpen(path.to_string()))?;
|
||||||
|
|
||||||
|
let level = if is_debug {
|
||||||
|
slog::Level::Debug
|
||||||
|
} else {
|
||||||
|
slog::Level::Info
|
||||||
|
};
|
||||||
|
|
||||||
|
let (logger, async_guard) = logging::create_logger("kata-runtime", sid, level, fifo);
|
||||||
|
|
||||||
|
// not reset global logger when drop
|
||||||
|
slog_scope::set_global_logger(logger).cancel_reset();
|
||||||
|
|
||||||
|
let level = if is_debug {
|
||||||
|
log::Level::Debug
|
||||||
|
} else {
|
||||||
|
log::Level::Info
|
||||||
|
};
|
||||||
|
let _ = slog_stdlog::init_with_level(level).context(format!("init with level {}", level))?;
|
||||||
|
|
||||||
|
Ok(async_guard)
|
||||||
|
}
|
41
src/runtime-rs/crates/shim/src/panic_hook.rs
Normal file
41
src/runtime-rs/crates/shim/src/panic_hook.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// Copyright (c) 2019-2022 Alibaba Cloud
|
||||||
|
// Copyright (c) 2019-2022 Ant Group
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
use std::{boxed::Box, ops::Deref};
|
||||||
|
|
||||||
|
use backtrace::Backtrace;
|
||||||
|
|
||||||
|
// TODO: the Kata 1.x runtime had a SIGUSR1 handler that would log a formatted backtrace on
|
||||||
|
// receiving that signal. It could be useful to re-add that feature.
|
||||||
|
pub(crate) fn set_panic_hook() {
|
||||||
|
std::panic::set_hook(Box::new(move |panic_info| {
|
||||||
|
let (filename, line) = panic_info
|
||||||
|
.location()
|
||||||
|
.map(|loc| (loc.file(), loc.line()))
|
||||||
|
.unwrap_or(("<unknown>", 0));
|
||||||
|
|
||||||
|
let cause = panic_info
|
||||||
|
.payload()
|
||||||
|
.downcast_ref::<String>()
|
||||||
|
.map(std::string::String::deref);
|
||||||
|
|
||||||
|
let cause = cause.unwrap_or_else(|| {
|
||||||
|
panic_info
|
||||||
|
.payload()
|
||||||
|
.downcast_ref::<&str>()
|
||||||
|
.copied()
|
||||||
|
.unwrap_or("<cause unknown>")
|
||||||
|
});
|
||||||
|
let bt = Backtrace::new();
|
||||||
|
let bt_data = format!("{:?}", bt);
|
||||||
|
error!(
|
||||||
|
sl!(),
|
||||||
|
"A panic occurred at {}:{}: {}\r\n{:?}", filename, line, cause, bt_data
|
||||||
|
);
|
||||||
|
|
||||||
|
std::process::abort();
|
||||||
|
}));
|
||||||
|
}
|
116
src/runtime-rs/crates/shim/src/shim.rs
Normal file
116
src/runtime-rs/crates/shim/src/shim.rs
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
// Copyright (c) 2019-2022 Alibaba Cloud
|
||||||
|
// Copyright (c) 2019-2022 Ant Group
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
os::unix::ffi::OsStrExt,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Context, Result};
|
||||||
|
use sha2::Digest;
|
||||||
|
|
||||||
|
use crate::{Args, Error};
|
||||||
|
|
||||||
|
const SOCKET_ROOT: &str = "/run/containerd";
|
||||||
|
const SHIM_PID_FILE: &str = "shim.pid";
|
||||||
|
|
||||||
|
pub(crate) const ENV_KATA_RUNTIME_BIND_FD: &str = "KATA_RUNTIME_BIND_FD";
|
||||||
|
|
||||||
|
/// Command executor for shim.
|
||||||
|
pub struct ShimExecutor {
|
||||||
|
pub(crate) args: Args,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShimExecutor {
|
||||||
|
/// Create a new instance of [`Shim`].
|
||||||
|
pub fn new(args: Args) -> Self {
|
||||||
|
ShimExecutor { args }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn load_oci_spec(&self) -> Result<oci::Spec> {
|
||||||
|
let bundle_path = self.get_bundle_path()?;
|
||||||
|
let spec_file = bundle_path.join("config.json");
|
||||||
|
|
||||||
|
oci::Spec::load(spec_file.to_str().unwrap_or_default()).context("load spec")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn write_address(&self, address: &Path) -> Result<()> {
|
||||||
|
let dir = self.get_bundle_path()?;
|
||||||
|
let file_path = &dir.join("address");
|
||||||
|
std::fs::write(file_path, address.as_os_str().as_bytes())
|
||||||
|
.context(Error::FileWrite(format!("{:?}", &file_path)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn write_pid_file(&self, pid: u32) -> Result<()> {
|
||||||
|
let dir = self.get_bundle_path()?;
|
||||||
|
let file_path = &dir.join(SHIM_PID_FILE);
|
||||||
|
std::fs::write(file_path, format!("{}", pid))
|
||||||
|
.context(Error::FileWrite(format!("{:?}", &file_path)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn read_pid_file(&self, bundle_path: &Path) -> Result<u32> {
|
||||||
|
let file_path = bundle_path.join(SHIM_PID_FILE);
|
||||||
|
let data = std::fs::read_to_string(&file_path)
|
||||||
|
.context(Error::FileOpen(format!("{:?}", file_path)))?;
|
||||||
|
|
||||||
|
data.parse::<u32>().context(Error::ParsePid)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_bundle_path(&self) -> Result<PathBuf> {
|
||||||
|
std::env::current_dir().context(Error::GetBundlePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn socket_address(&self, id: &str) -> Result<PathBuf> {
|
||||||
|
if id.is_empty() {
|
||||||
|
return Err(anyhow!(Error::EmptySandboxId));
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = [&self.args.address, &self.args.namespace, id].join("/");
|
||||||
|
let mut hasher = sha2::Sha256::new();
|
||||||
|
hasher.update(data);
|
||||||
|
Ok(PathBuf::from(format!(
|
||||||
|
"unix://{}/s/{:X}",
|
||||||
|
SOCKET_ROOT,
|
||||||
|
hasher.finalize()
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use serial_test::serial;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn test_shim_executor() {
|
||||||
|
let dir = tempfile::tempdir().unwrap();
|
||||||
|
let bundle_path = dir.path();
|
||||||
|
std::env::set_current_dir(bundle_path).unwrap();
|
||||||
|
|
||||||
|
let args = Args {
|
||||||
|
id: "1dfc0567".to_string(),
|
||||||
|
namespace: "test_namespace".into(),
|
||||||
|
address: "containerd_socket".into(),
|
||||||
|
publish_binary: "containerd".into(),
|
||||||
|
socket: "socket".into(),
|
||||||
|
bundle: bundle_path.to_str().unwrap().into(),
|
||||||
|
debug: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let executor = ShimExecutor::new(args);
|
||||||
|
|
||||||
|
executor.write_address(Path::new("12345")).unwrap();
|
||||||
|
let dir = executor.get_bundle_path().unwrap();
|
||||||
|
let file_path = &dir.join("address");
|
||||||
|
let buf = std::fs::read_to_string(file_path).unwrap();
|
||||||
|
assert_eq!(&buf, "12345");
|
||||||
|
|
||||||
|
executor.write_pid_file(1267).unwrap();
|
||||||
|
let read_pid = executor.read_pid_file(&dir).unwrap();
|
||||||
|
assert_eq!(read_pid, 1267);
|
||||||
|
}
|
||||||
|
}
|
71
src/runtime-rs/crates/shim/src/shim_delete.rs
Normal file
71
src/runtime-rs/crates/shim/src/shim_delete.rs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// Copyright (c) 2019-2022 Alibaba Cloud
|
||||||
|
// Copyright (c) 2019-2022 Ant Group
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
use anyhow::{Context, Result};
|
||||||
|
use containerd_shim_protos::shim::shim::DeleteResponse;
|
||||||
|
use protobuf::Message;
|
||||||
|
|
||||||
|
use crate::{shim::ShimExecutor, Error};
|
||||||
|
|
||||||
|
impl ShimExecutor {
|
||||||
|
pub fn delete(&mut self) -> Result<()> {
|
||||||
|
self.args.validate(true).context("validate")?;
|
||||||
|
let rsp = self.do_cleanup().context("do cleanup")?;
|
||||||
|
rsp.write_to_writer(&mut std::io::stdout())
|
||||||
|
.context(Error::FileWrite(format!("write {:?} to stdout", rsp)))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_cleanup(&self) -> Result<DeleteResponse> {
|
||||||
|
let mut rsp = DeleteResponse::new();
|
||||||
|
rsp.set_exit_status(128 + libc::SIGKILL as u32);
|
||||||
|
let mut exited_time = protobuf::well_known_types::Timestamp::new();
|
||||||
|
let seconds = std::time::SystemTime::now()
|
||||||
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
|
.map_err(Error::SystemTime)?
|
||||||
|
.as_secs() as i64;
|
||||||
|
exited_time.set_seconds(seconds);
|
||||||
|
rsp.set_exited_at(exited_time);
|
||||||
|
|
||||||
|
// TODO: implement cleanup
|
||||||
|
Ok(rsp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use serial_test::serial;
|
||||||
|
use tests_utils::gen_id;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::Args;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn test_shim_delete() {
|
||||||
|
let dir = tempfile::tempdir().unwrap();
|
||||||
|
let bundle_path = dir.path();
|
||||||
|
std::env::set_current_dir(bundle_path).unwrap();
|
||||||
|
|
||||||
|
let id = gen_id(16);
|
||||||
|
let namespace = gen_id(16);
|
||||||
|
let args = Args {
|
||||||
|
id,
|
||||||
|
namespace,
|
||||||
|
address: "containerd_socket".into(),
|
||||||
|
publish_binary: "containerd".into(),
|
||||||
|
socket: "socket".into(),
|
||||||
|
bundle: bundle_path.to_str().unwrap().into(),
|
||||||
|
debug: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let executor = ShimExecutor::new(args);
|
||||||
|
|
||||||
|
let resp = executor.do_cleanup().unwrap();
|
||||||
|
assert_eq!(resp.exit_status, 128 + libc::SIGKILL as u32);
|
||||||
|
assert!(resp.exited_at.as_ref().unwrap().seconds > 0);
|
||||||
|
}
|
||||||
|
}
|
54
src/runtime-rs/crates/shim/src/shim_run.rs
Normal file
54
src/runtime-rs/crates/shim/src/shim_run.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Copyright (c) 2019-2022 Alibaba Cloud
|
||||||
|
// Copyright (c) 2019-2022 Ant Group
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
use std::os::unix::io::RawFd;
|
||||||
|
|
||||||
|
use anyhow::{Context, Result};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
logger,
|
||||||
|
shim::{ShimExecutor, ENV_KATA_RUNTIME_BIND_FD},
|
||||||
|
Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl ShimExecutor {
|
||||||
|
pub async fn run(&mut self) -> Result<()> {
|
||||||
|
crate::panic_hook::set_panic_hook();
|
||||||
|
let sid = self.args.id.clone();
|
||||||
|
let bundle_path = self.get_bundle_path().context("get bundle")?;
|
||||||
|
let path = bundle_path.join("log");
|
||||||
|
let _logger_guard =
|
||||||
|
logger::set_logger(path.to_str().unwrap(), &sid, self.args.debug).context("set logger");
|
||||||
|
|
||||||
|
self.do_run()
|
||||||
|
.await
|
||||||
|
.map_err(|err| {
|
||||||
|
error!(sl!(), "failed run shim {:?}", err);
|
||||||
|
err
|
||||||
|
})
|
||||||
|
.context("run shim")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn do_run(&mut self) -> Result<()> {
|
||||||
|
info!(sl!(), "start to run");
|
||||||
|
self.args.validate(false).context("validata")?;
|
||||||
|
|
||||||
|
let _server_fd = get_server_fd().context("get server fd")?;
|
||||||
|
// TODO: implement run
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_server_fd() -> Result<RawFd> {
|
||||||
|
let env_fd = std::env::var(ENV_KATA_RUNTIME_BIND_FD).map_err(Error::EnvVar)?;
|
||||||
|
let fd = env_fd
|
||||||
|
.parse::<RawFd>()
|
||||||
|
.map_err(|_| Error::ServerFd(env_fd))?;
|
||||||
|
Ok(fd)
|
||||||
|
}
|
238
src/runtime-rs/crates/shim/src/shim_start.rs
Normal file
238
src/runtime-rs/crates/shim/src/shim_start.rs
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
// Copyright (c) 2019-2022 Alibaba Cloud
|
||||||
|
// Copyright (c) 2019-2022 Ant Group
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
fs,
|
||||||
|
io::Write,
|
||||||
|
os::unix::{io::IntoRawFd, prelude::OsStrExt},
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Context, Result};
|
||||||
|
use kata_types::{container::ContainerType, k8s};
|
||||||
|
use unix_socket::UnixListener;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
shim::{ShimExecutor, ENV_KATA_RUNTIME_BIND_FD},
|
||||||
|
Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl ShimExecutor {
|
||||||
|
pub fn start(&mut self) -> Result<()> {
|
||||||
|
self.args.validate(false).context("validate")?;
|
||||||
|
|
||||||
|
let address = self.do_start().context("do start")?;
|
||||||
|
std::io::stdout()
|
||||||
|
.write_all(address.as_os_str().as_bytes())
|
||||||
|
.context("failed to write stdout")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_start(&mut self) -> Result<PathBuf> {
|
||||||
|
let spec = self.load_oci_spec()?;
|
||||||
|
let (container_type, id) = k8s::container_type_with_id(&spec);
|
||||||
|
|
||||||
|
match container_type {
|
||||||
|
ContainerType::PodSandbox => {
|
||||||
|
let address = self.socket_address(&self.args.id)?;
|
||||||
|
let socket = new_listener(&address)?;
|
||||||
|
let child_pid = self.create_shim_process(socket)?;
|
||||||
|
self.write_pid_file(child_pid)?;
|
||||||
|
self.write_address(&address)?;
|
||||||
|
Ok(address)
|
||||||
|
}
|
||||||
|
ContainerType::PodContainer => {
|
||||||
|
let sid = id
|
||||||
|
.ok_or(Error::InvalidArgument)
|
||||||
|
.context("get sid for container")?;
|
||||||
|
let (address, pid) = self.get_shim_info_from_sandbox(&sid)?;
|
||||||
|
self.write_pid_file(pid)?;
|
||||||
|
self.write_address(&address)?;
|
||||||
|
Ok(address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_command(&self) -> Result<std::process::Command> {
|
||||||
|
if self.args.id.is_empty()
|
||||||
|
|| self.args.namespace.is_empty()
|
||||||
|
|| self.args.address.is_empty()
|
||||||
|
|| self.args.publish_binary.is_empty()
|
||||||
|
{
|
||||||
|
return Err(anyhow!("invalid param"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let bundle_path = self.get_bundle_path().context("get bundle path")?;
|
||||||
|
let self_exec = std::env::current_exe().map_err(Error::SelfExec)?;
|
||||||
|
let mut command = std::process::Command::new(self_exec);
|
||||||
|
|
||||||
|
command
|
||||||
|
.current_dir(bundle_path)
|
||||||
|
.stdin(std::process::Stdio::null())
|
||||||
|
.stdout(std::process::Stdio::null())
|
||||||
|
.stderr(std::process::Stdio::null())
|
||||||
|
.arg("-id")
|
||||||
|
.arg(&self.args.id)
|
||||||
|
.arg("-namespace")
|
||||||
|
.arg(&self.args.namespace)
|
||||||
|
.arg("-address")
|
||||||
|
.arg(&self.args.address)
|
||||||
|
.arg("-publish-binary")
|
||||||
|
.arg(&self.args.publish_binary)
|
||||||
|
.env("RUST_BACKTRACE", "1");
|
||||||
|
|
||||||
|
if self.args.debug {
|
||||||
|
command.arg("-debug");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(command)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_shim_process<T: IntoRawFd>(&self, socket: T) -> Result<u32> {
|
||||||
|
let mut cmd = self.new_command().context("new command")?;
|
||||||
|
cmd.env(
|
||||||
|
ENV_KATA_RUNTIME_BIND_FD,
|
||||||
|
format!("{}", socket.into_raw_fd()),
|
||||||
|
);
|
||||||
|
let child = cmd
|
||||||
|
.spawn()
|
||||||
|
.map_err(Error::SpawnChild)
|
||||||
|
.context("spawn child")?;
|
||||||
|
|
||||||
|
Ok(child.id())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_shim_info_from_sandbox(&self, sandbox_id: &str) -> Result<(PathBuf, u32)> {
|
||||||
|
// All containers of a pod share the same pod socket address.
|
||||||
|
let address = self.socket_address(sandbox_id).context("socket address")?;
|
||||||
|
let bundle_path = self.get_bundle_path().context("get bundle path")?;
|
||||||
|
let parent_bundle_path = Path::new(&bundle_path)
|
||||||
|
.parent()
|
||||||
|
.unwrap_or_else(|| Path::new(""));
|
||||||
|
let sandbox_bundle_path = parent_bundle_path
|
||||||
|
.join(sandbox_id)
|
||||||
|
.canonicalize()
|
||||||
|
.context(Error::GetBundlePath)?;
|
||||||
|
let pid = self.read_pid_file(&sandbox_bundle_path)?;
|
||||||
|
|
||||||
|
Ok((address, pid))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_listener(address: &Path) -> Result<UnixListener> {
|
||||||
|
let trim_path = address.strip_prefix("unix:").context("trim path")?;
|
||||||
|
let file_path = Path::new("/").join(trim_path);
|
||||||
|
let file_path = file_path.as_path();
|
||||||
|
if let Some(parent_dir) = file_path.parent() {
|
||||||
|
fs::create_dir_all(parent_dir).context("create parent dir")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnixListener::bind(file_path).context("bind address")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use serial_test::serial;
|
||||||
|
use tests_utils::gen_id;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::Args;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn test_new_command() {
|
||||||
|
let dir = tempfile::tempdir().unwrap();
|
||||||
|
let bundle_path = dir.path();
|
||||||
|
std::env::set_current_dir(bundle_path).unwrap();
|
||||||
|
|
||||||
|
let args = Args {
|
||||||
|
id: "sandbox1".into(),
|
||||||
|
namespace: "ns".into(),
|
||||||
|
address: "address".into(),
|
||||||
|
publish_binary: "containerd".into(),
|
||||||
|
socket: "socket".into(),
|
||||||
|
bundle: bundle_path.to_str().unwrap().into(),
|
||||||
|
debug: false,
|
||||||
|
};
|
||||||
|
let mut executor = ShimExecutor::new(args);
|
||||||
|
|
||||||
|
let cmd = executor.new_command().unwrap();
|
||||||
|
assert_eq!(cmd.get_args().len(), 8);
|
||||||
|
assert_eq!(cmd.get_envs().len(), 1);
|
||||||
|
assert_eq!(
|
||||||
|
cmd.get_current_dir().unwrap(),
|
||||||
|
executor.get_bundle_path().unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
executor.args.debug = true;
|
||||||
|
let cmd = executor.new_command().unwrap();
|
||||||
|
assert_eq!(cmd.get_args().len(), 9);
|
||||||
|
assert_eq!(cmd.get_envs().len(), 1);
|
||||||
|
assert_eq!(
|
||||||
|
cmd.get_current_dir().unwrap(),
|
||||||
|
executor.get_bundle_path().unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn test_get_info_from_sandbox() {
|
||||||
|
let dir = tempfile::tempdir().unwrap();
|
||||||
|
let sandbox_id = gen_id(16);
|
||||||
|
let bundle_path = &dir.path().join(&sandbox_id);
|
||||||
|
std::fs::create_dir(bundle_path).unwrap();
|
||||||
|
std::env::set_current_dir(bundle_path).unwrap();
|
||||||
|
|
||||||
|
let args = Args {
|
||||||
|
id: sandbox_id.to_owned(),
|
||||||
|
namespace: "ns1".into(),
|
||||||
|
address: "containerd_socket".into(),
|
||||||
|
publish_binary: "containerd".into(),
|
||||||
|
socket: "socket".into(),
|
||||||
|
bundle: bundle_path.to_str().unwrap().into(),
|
||||||
|
debug: false,
|
||||||
|
};
|
||||||
|
let executor = ShimExecutor::new(args);
|
||||||
|
|
||||||
|
let addr = executor.socket_address(&executor.args.id).unwrap();
|
||||||
|
executor.write_address(&addr).unwrap();
|
||||||
|
executor.write_pid_file(1267).unwrap();
|
||||||
|
|
||||||
|
let container_id = gen_id(16);
|
||||||
|
let bundle_path2 = &dir.path().join(&container_id);
|
||||||
|
std::fs::create_dir(bundle_path2).unwrap();
|
||||||
|
std::env::set_current_dir(bundle_path2).unwrap();
|
||||||
|
|
||||||
|
let args = Args {
|
||||||
|
id: container_id,
|
||||||
|
namespace: "ns1".into(),
|
||||||
|
address: "containerd_socket".into(),
|
||||||
|
publish_binary: "containerd".into(),
|
||||||
|
socket: "socket".into(),
|
||||||
|
bundle: bundle_path2.to_str().unwrap().into(),
|
||||||
|
debug: false,
|
||||||
|
};
|
||||||
|
let executor2 = ShimExecutor::new(args);
|
||||||
|
|
||||||
|
let (address, pid) = executor2.get_shim_info_from_sandbox(&sandbox_id).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(pid, 1267);
|
||||||
|
assert_eq!(&address, &addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn test_new_listener() {
|
||||||
|
let path = "/tmp/aaabbbccc";
|
||||||
|
let uds_path = format!("unix://{}", path);
|
||||||
|
std::fs::remove_file(path).ok();
|
||||||
|
|
||||||
|
let _ = new_listener(Path::new(&uds_path)).unwrap();
|
||||||
|
std::fs::remove_file(path).ok();
|
||||||
|
}
|
||||||
|
}
|
395
src/runtime-rs/tests/texture/image-bundle/config.json
Normal file
395
src/runtime-rs/tests/texture/image-bundle/config.json
Normal file
@ -0,0 +1,395 @@
|
|||||||
|
{
|
||||||
|
"ociVersion": "0.5.0-dev",
|
||||||
|
"process": {
|
||||||
|
"terminal": true,
|
||||||
|
"user": {
|
||||||
|
"uid": 1,
|
||||||
|
"gid": 1,
|
||||||
|
"additionalGids": [
|
||||||
|
5,
|
||||||
|
6
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"args": [
|
||||||
|
"sh"
|
||||||
|
],
|
||||||
|
"env": [
|
||||||
|
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||||
|
"TERM=xterm"
|
||||||
|
],
|
||||||
|
"cwd": "/",
|
||||||
|
"capabilities": {
|
||||||
|
"bounding": [
|
||||||
|
"CAP_AUDIT_WRITE",
|
||||||
|
"CAP_KILL",
|
||||||
|
"CAP_NET_BIND_SERVICE"
|
||||||
|
],
|
||||||
|
"permitted": [
|
||||||
|
"CAP_AUDIT_WRITE",
|
||||||
|
"CAP_KILL",
|
||||||
|
"CAP_NET_BIND_SERVICE"
|
||||||
|
],
|
||||||
|
"inheritable": [
|
||||||
|
"CAP_AUDIT_WRITE",
|
||||||
|
"CAP_KILL",
|
||||||
|
"CAP_NET_BIND_SERVICE"
|
||||||
|
],
|
||||||
|
"effective": [
|
||||||
|
"CAP_AUDIT_WRITE",
|
||||||
|
"CAP_KILL"
|
||||||
|
],
|
||||||
|
"ambient": [
|
||||||
|
"CAP_NET_BIND_SERVICE"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"rlimits": [
|
||||||
|
{
|
||||||
|
"type": "RLIMIT_CORE",
|
||||||
|
"hard": 1024,
|
||||||
|
"soft": 1024
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "RLIMIT_NOFILE",
|
||||||
|
"hard": 1024,
|
||||||
|
"soft": 1024
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"apparmorProfile": "acme_secure_profile",
|
||||||
|
"selinuxLabel": "system_u:system_r:svirt_lxc_net_t:s0:c124,c675",
|
||||||
|
"noNewPrivileges": true
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"path": "rootfs",
|
||||||
|
"readonly": true
|
||||||
|
},
|
||||||
|
"hostname": "slartibartfast",
|
||||||
|
"mounts": [
|
||||||
|
{
|
||||||
|
"destination": "/proc",
|
||||||
|
"type": "proc",
|
||||||
|
"source": "proc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "/dev",
|
||||||
|
"type": "tmpfs",
|
||||||
|
"source": "tmpfs",
|
||||||
|
"options": [
|
||||||
|
"nosuid",
|
||||||
|
"strictatime",
|
||||||
|
"mode=755",
|
||||||
|
"size=65536k"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "/dev/pts",
|
||||||
|
"type": "devpts",
|
||||||
|
"source": "devpts",
|
||||||
|
"options": [
|
||||||
|
"nosuid",
|
||||||
|
"noexec",
|
||||||
|
"newinstance",
|
||||||
|
"ptmxmode=0666",
|
||||||
|
"mode=0620",
|
||||||
|
"gid=5"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "/dev/shm",
|
||||||
|
"type": "tmpfs",
|
||||||
|
"source": "shm",
|
||||||
|
"options": [
|
||||||
|
"nosuid",
|
||||||
|
"noexec",
|
||||||
|
"nodev",
|
||||||
|
"mode=1777",
|
||||||
|
"size=65536k"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "/dev/mqueue",
|
||||||
|
"type": "mqueue",
|
||||||
|
"source": "mqueue",
|
||||||
|
"options": [
|
||||||
|
"nosuid",
|
||||||
|
"noexec",
|
||||||
|
"nodev"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "/sys",
|
||||||
|
"type": "sysfs",
|
||||||
|
"source": "sysfs",
|
||||||
|
"options": [
|
||||||
|
"nosuid",
|
||||||
|
"noexec",
|
||||||
|
"nodev"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "/sys/fs/cgroup",
|
||||||
|
"type": "cgroup",
|
||||||
|
"source": "cgroup",
|
||||||
|
"options": [
|
||||||
|
"nosuid",
|
||||||
|
"noexec",
|
||||||
|
"nodev",
|
||||||
|
"relatime",
|
||||||
|
"ro"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"hooks": {
|
||||||
|
"prestart": [
|
||||||
|
{
|
||||||
|
"path": "/usr/bin/fix-mounts",
|
||||||
|
"args": [
|
||||||
|
"fix-mounts",
|
||||||
|
"arg1",
|
||||||
|
"arg2"
|
||||||
|
],
|
||||||
|
"env": [
|
||||||
|
"key1=value1"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/usr/bin/setup-network"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"createRuntime": [
|
||||||
|
{
|
||||||
|
"path": "/usr/bin/fix-mounts",
|
||||||
|
"args": ["fix-mounts", "arg1", "arg2"],
|
||||||
|
"env": [ "key1=value1"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/usr/bin/setup-network"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"createContainer": [
|
||||||
|
{
|
||||||
|
"path": "/usr/bin/mount-hook",
|
||||||
|
"args": ["-mount", "arg1", "arg2"],
|
||||||
|
"env": [ "key1=value1"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"startContainer": [
|
||||||
|
{
|
||||||
|
"path": "/usr/bin/refresh-ldcache"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"poststart": [
|
||||||
|
{
|
||||||
|
"path": "/usr/bin/notify-start",
|
||||||
|
"timeout": 5
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"poststop": [
|
||||||
|
{
|
||||||
|
"path": "/usr/sbin/cleanup.sh",
|
||||||
|
"args": [
|
||||||
|
"cleanup.sh",
|
||||||
|
"-f"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"linux": {
|
||||||
|
"devices": [
|
||||||
|
{
|
||||||
|
"path": "/dev/fuse",
|
||||||
|
"type": "c",
|
||||||
|
"major": 10,
|
||||||
|
"minor": 229,
|
||||||
|
"fileMode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/dev/sda",
|
||||||
|
"type": "b",
|
||||||
|
"major": 8,
|
||||||
|
"minor": 0,
|
||||||
|
"fileMode": 432,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"uidMappings": [
|
||||||
|
{
|
||||||
|
"containerID": 0,
|
||||||
|
"hostID": 1000,
|
||||||
|
"size": 32000
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"gidMappings": [
|
||||||
|
{
|
||||||
|
"containerID": 0,
|
||||||
|
"hostID": 1000,
|
||||||
|
"size": 32000
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sysctl": {
|
||||||
|
"net.ipv4.ip_forward": "1",
|
||||||
|
"net.core.somaxconn": "256"
|
||||||
|
},
|
||||||
|
"cgroupsPath": "/myRuntime/myContainer",
|
||||||
|
"resources": {
|
||||||
|
"network": {
|
||||||
|
"classID": 1048577,
|
||||||
|
"priorities": [
|
||||||
|
{
|
||||||
|
"name": "eth0",
|
||||||
|
"priority": 500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "eth1",
|
||||||
|
"priority": 1000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"pids": {
|
||||||
|
"limit": 32771
|
||||||
|
},
|
||||||
|
"hugepageLimits": [
|
||||||
|
{
|
||||||
|
"pageSize": "2MB",
|
||||||
|
"limit": 9223372036854772000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pageSize": "64KB",
|
||||||
|
"limit": 1000000
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"oomScoreAdj": 100,
|
||||||
|
"memory": {
|
||||||
|
"limit": 536870912,
|
||||||
|
"reservation": 536870912,
|
||||||
|
"swap": 536870912,
|
||||||
|
"kernel": -1,
|
||||||
|
"kernelTCP": -1,
|
||||||
|
"swappiness": 0,
|
||||||
|
"disableOOMKiller": false,
|
||||||
|
"useHierarchy": false
|
||||||
|
},
|
||||||
|
"cpu": {
|
||||||
|
"shares": 1024,
|
||||||
|
"quota": 1000000,
|
||||||
|
"period": 500000,
|
||||||
|
"realtimeRuntime": 950000,
|
||||||
|
"realtimePeriod": 1000000,
|
||||||
|
"cpus": "2-3",
|
||||||
|
"mems": "0-7"
|
||||||
|
},
|
||||||
|
"devices": [
|
||||||
|
{
|
||||||
|
"allow": false,
|
||||||
|
"access": "rwm"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow": true,
|
||||||
|
"type": "c",
|
||||||
|
"major": 10,
|
||||||
|
"minor": 229,
|
||||||
|
"access": "rw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow": true,
|
||||||
|
"type": "b",
|
||||||
|
"major": 8,
|
||||||
|
"minor": 0,
|
||||||
|
"access": "r"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"blockIO": {
|
||||||
|
"weight": 10,
|
||||||
|
"leafWeight": 10,
|
||||||
|
"weightDevice": [
|
||||||
|
{
|
||||||
|
"major": 8,
|
||||||
|
"minor": 0,
|
||||||
|
"weight": 500,
|
||||||
|
"leafWeight": 300
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"major": 8,
|
||||||
|
"minor": 16,
|
||||||
|
"weight": 500
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"throttleReadBpsDevice": [
|
||||||
|
{
|
||||||
|
"major": 8,
|
||||||
|
"minor": 0,
|
||||||
|
"rate": 600
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"throttleWriteIOPSDevice": [
|
||||||
|
{
|
||||||
|
"major": 8,
|
||||||
|
"minor": 16,
|
||||||
|
"rate": 300
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rootfsPropagation": "slave",
|
||||||
|
"seccomp": {
|
||||||
|
"defaultAction": "SCMP_ACT_ALLOW",
|
||||||
|
"architectures": [
|
||||||
|
"SCMP_ARCH_X86",
|
||||||
|
"SCMP_ARCH_X32"
|
||||||
|
],
|
||||||
|
"syscalls": [
|
||||||
|
{
|
||||||
|
"names": [
|
||||||
|
"getcwd",
|
||||||
|
"chmod"
|
||||||
|
],
|
||||||
|
"action": "SCMP_ACT_ERRNO"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"namespaces": [
|
||||||
|
{
|
||||||
|
"type": "pid"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "network"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ipc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "uts"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "mount"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "user"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "cgroup"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"maskedPaths": [
|
||||||
|
"/proc/kcore",
|
||||||
|
"/proc/latency_stats",
|
||||||
|
"/proc/timer_stats",
|
||||||
|
"/proc/sched_debug"
|
||||||
|
],
|
||||||
|
"readonlyPaths": [
|
||||||
|
"/proc/asound",
|
||||||
|
"/proc/bus",
|
||||||
|
"/proc/fs",
|
||||||
|
"/proc/irq",
|
||||||
|
"/proc/sys",
|
||||||
|
"/proc/sysrq-trigger"
|
||||||
|
],
|
||||||
|
"mountLabel": "system_u:object_r:svirt_sandbox_file_t:s0:c715,c811"
|
||||||
|
},
|
||||||
|
"annotations": {
|
||||||
|
"com.example.key1": "value1",
|
||||||
|
"com.example.key2": "value2"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
[runtime]
|
||||||
|
enable_debug = true
|
||||||
|
|
||||||
|
[hypervisor]
|
||||||
|
|
||||||
|
[hypervisor.dragonball]
|
||||||
|
default_vcpus = 2
|
||||||
|
|
||||||
|
[hypervisor.qemu]
|
||||||
|
default_vcpus = 4
|
||||||
|
|
10
src/runtime-rs/tests/utils/Cargo.toml
Normal file
10
src/runtime-rs/tests/utils/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "tests_utils"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2018"
|
||||||
|
description = "This crate is used to share code among tests"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rand = "0.8.4"
|
35
src/runtime-rs/tests/utils/src/lib.rs
Normal file
35
src/runtime-rs/tests/utils/src/lib.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright (c) 2019-2022 Alibaba Cloud
|
||||||
|
// Copyright (c) 2019-2022 Ant Group
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
// This crate is used to share code among tests
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use rand::{
|
||||||
|
distributions::Alphanumeric,
|
||||||
|
{thread_rng, Rng},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn get_kata_config_file() -> PathBuf {
|
||||||
|
let target = format!(
|
||||||
|
"{}/../texture/kata-containers-configuration.toml",
|
||||||
|
env!("CARGO_MANIFEST_DIR")
|
||||||
|
);
|
||||||
|
std::fs::canonicalize(target).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_image_bundle_path() -> PathBuf {
|
||||||
|
let target = format!("{}/../texture/image-bundle", env!("CARGO_MANIFEST_DIR"));
|
||||||
|
std::fs::canonicalize(target).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gen_id(len: usize) -> String {
|
||||||
|
thread_rng()
|
||||||
|
.sample_iter(&Alphanumeric)
|
||||||
|
.take(len)
|
||||||
|
.map(char::from)
|
||||||
|
.collect()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user